]> git.proxmox.com Git - grub2.git/blame - grub-core/kern/x86_64/dl.c
* grub-core/kern/x86_64/dl.c (grub_arch_dl_relocate_symbols): Issue
[grub2.git] / grub-core / kern / x86_64 / dl.c
CommitLineData
20011694 1/* dl-x86_64.c - arch-dependent part of loadable module support */
2/*
3 * GRUB -- GRand Unified Bootloader
58bc8bd5 4 * Copyright (C) 2002,2005,2007,2009 Free Software Foundation, Inc.
20011694 5 *
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <grub/dl.h>
21#include <grub/elf.h>
22#include <grub/misc.h>
23#include <grub/err.h>
24
25/* Check if EHDR is a valid ELF header. */
26grub_err_t
27grub_arch_dl_check_header (void *ehdr)
28{
29 Elf64_Ehdr *e = ehdr;
30
31 /* Check the magic numbers. */
32 if (e->e_ident[EI_CLASS] != ELFCLASS64
33 || e->e_ident[EI_DATA] != ELFDATA2LSB
34 || e->e_machine != EM_X86_64)
35 return grub_error (GRUB_ERR_BAD_OS, "invalid arch specific ELF magic");
36
37 return GRUB_ERR_NONE;
38}
39
40/* Relocate symbols. */
41grub_err_t
42grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
43{
44 Elf64_Ehdr *e = ehdr;
45 Elf64_Shdr *s;
20011694 46 Elf64_Word entsize;
47 unsigned i;
48
49 /* Find a symbol table. */
50 for (i = 0, s = (Elf64_Shdr *) ((char *) e + e->e_shoff);
51 i < e->e_shnum;
52 i++, s = (Elf64_Shdr *) ((char *) s + e->e_shentsize))
53 if (s->sh_type == SHT_SYMTAB)
54 break;
55
56 if (i == e->e_shnum)
57 return grub_error (GRUB_ERR_BAD_MODULE, "no symtab found");
58
20011694 59 entsize = s->sh_entsize;
60
61 for (i = 0, s = (Elf64_Shdr *) ((char *) e + e->e_shoff);
62 i < e->e_shnum;
63 i++, s = (Elf64_Shdr *) ((char *) s + e->e_shentsize))
64 if (s->sh_type == SHT_RELA)
65 {
66 grub_dl_segment_t seg;
67
68 /* Find the target segment. */
69 for (seg = mod->segment; seg; seg = seg->next)
70 if (seg->section == s->sh_info)
71 break;
72
73 if (seg)
74 {
75 Elf64_Rela *rel, *max;
76
77 for (rel = (Elf64_Rela *) ((char *) e + s->sh_offset),
78 max = rel + s->sh_size / s->sh_entsize;
79 rel < max;
80 rel++)
81 {
82 Elf64_Word *addr32;
83 Elf64_Xword *addr64;
84 Elf64_Sym *sym;
85
86 if (seg->size < rel->r_offset)
87 return grub_error (GRUB_ERR_BAD_MODULE,
88 "reloc offset is out of the segment");
89
90 addr32 = (Elf64_Word *) ((char *) seg->addr + rel->r_offset);
91 addr64 = (Elf64_Xword *) addr32;
8231fb77 92 sym = (Elf64_Sym *) ((char *) mod->symtab
32622956 93 + entsize * ELF_R_SYM (rel->r_info));
20011694 94
32622956 95 switch (ELF_R_TYPE (rel->r_info))
20011694 96 {
97 case R_X86_64_64:
6e09b8b7 98 *addr64 += rel->r_addend + sym->st_value;
20011694 99 break;
100
101 case R_X86_64_PC32:
6e09b8b7 102 *addr32 += rel->r_addend + sym->st_value -
20011694 103 (Elf64_Xword) seg->addr - rel->r_offset;
104 break;
105
106 case R_X86_64_32:
107 case R_X86_64_32S:
6e09b8b7 108 *addr32 += rel->r_addend + sym->st_value;
20011694 109 break;
110
111 default:
9bb182f3
VS
112 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
113 "this relocation (%d) is not implemented yet",
114 ELF_R_TYPE (rel->r_info));
20011694 115 }
116 }
117 }
118 }
119
120 return GRUB_ERR_NONE;
121}