1 /* dl.c - arch-dependent part of loadable module support */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2013 Free Software Foundation, Inc.
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.
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.
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/>.
22 #include <grub/misc.h>
25 #include <grub/i18n.h>
26 #include <grub/cpu/reloc.h>
30 #define LDR 0x58000050
32 grub_uint32_t ldr
; /* ldr x16, 8 */
33 grub_uint32_t br
; /* br x16 */
38 * Check if EHDR is a valid ELF header.
41 grub_arch_dl_check_header (void *ehdr
)
45 /* Check the magic numbers. */
46 if (e
->e_ident
[EI_CLASS
] != ELFCLASS64
47 || e
->e_ident
[EI_DATA
] != ELFDATA2LSB
|| e
->e_machine
!= EM_AARCH64
)
48 return grub_error (GRUB_ERR_BAD_OS
,
49 N_("invalid arch-dependent ELF magic"));
54 #pragma GCC diagnostic ignored "-Wcast-align"
57 grub_arch_dl_get_tramp_got_size (const void *ehdr
, grub_size_t
*tramp
,
60 const Elf_Ehdr
*e
= ehdr
;
67 for (i
= 0, s
= (const Elf_Shdr
*) ((grub_addr_t
) e
+ e
->e_shoff
);
69 i
++, s
= (const Elf_Shdr
*) ((grub_addr_t
) s
+ e
->e_shentsize
))
70 if (s
->sh_type
== SHT_REL
|| s
->sh_type
== SHT_RELA
)
72 const Elf_Rel
*rel
, *max
;
74 for (rel
= (const Elf_Rel
*) ((grub_addr_t
) e
+ s
->sh_offset
),
75 max
= rel
+ s
->sh_size
/ s
->sh_entsize
;
77 rel
= (const Elf_Rel
*) ((grub_addr_t
) rel
+ s
->sh_entsize
))
78 switch (ELF_R_TYPE (rel
->r_info
))
80 case R_AARCH64_CALL26
:
81 case R_AARCH64_JUMP26
:
83 *tramp
+= sizeof (struct trampoline
);
93 * Unified function for both REL and RELA
96 grub_arch_dl_relocate_symbols (grub_dl_t mod
, void *ehdr
,
97 Elf_Shdr
*s
, grub_dl_segment_t seg
)
101 for (rel
= (Elf_Rel
*) ((char *) ehdr
+ s
->sh_offset
),
102 max
= (Elf_Rel
*) ((char *) rel
+ s
->sh_size
);
104 rel
= (Elf_Rel
*) ((char *) rel
+ s
->sh_entsize
))
108 grub_uint64_t sym_addr
;
110 if (rel
->r_offset
>= seg
->size
)
111 return grub_error (GRUB_ERR_BAD_MODULE
,
112 "reloc offset is out of the segment");
114 sym
= (Elf_Sym
*) ((char *) mod
->symtab
115 + mod
->symsize
* ELF_R_SYM (rel
->r_info
));
117 sym_addr
= sym
->st_value
;
118 if (s
->sh_type
== SHT_RELA
)
119 sym_addr
+= ((Elf_Rela
*) rel
)->r_addend
;
121 place
= (void *) ((grub_addr_t
) seg
->addr
+ rel
->r_offset
);
123 switch (ELF_R_TYPE (rel
->r_info
))
125 case R_AARCH64_ABS64
:
127 grub_uint64_t
*abs_place
= place
;
129 grub_dprintf ("dl", " reloc_abs64 %p => 0x%016llx\n",
130 place
, (unsigned long long) sym_addr
);
132 *abs_place
= (grub_uint64_t
) sym_addr
;
135 case R_AARCH64_CALL26
:
136 case R_AARCH64_JUMP26
:
138 grub_int64_t offset
= sym_addr
- (grub_uint64_t
) place
;
140 if (!grub_arm_64_check_xxxx26_offset (offset
))
142 struct trampoline
*tp
= mod
->trampptr
;
143 mod
->trampptr
= tp
+ 1;
147 offset
= (grub_uint8_t
*) tp
- (grub_uint8_t
*) place
;
150 if (!grub_arm_64_check_xxxx26_offset (offset
))
151 return grub_error (GRUB_ERR_BAD_MODULE
,
152 "trampoline out of range");
154 grub_arm64_set_xxxx26_offset (place
, offset
);
158 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
159 N_("relocation 0x%x is not implemented yet"),
160 ELF_R_TYPE (rel
->r_info
));
164 return GRUB_ERR_NONE
;