arm64: Add support for GOT and PCREL32 relocations.
This commit is contained in:
parent
377c121170
commit
34fe0b5901
9 changed files with 226 additions and 54 deletions
|
@ -25,14 +25,9 @@
|
||||||
#include <grub/i18n.h>
|
#include <grub/i18n.h>
|
||||||
#include <grub/cpu/reloc.h>
|
#include <grub/cpu/reloc.h>
|
||||||
|
|
||||||
struct trampoline
|
|
||||||
{
|
|
||||||
#define LDR 0x58000050
|
#define LDR 0x58000050
|
||||||
#define BR 0xd61f0200
|
#define BR 0xd61f0200
|
||||||
grub_uint32_t ldr; /* ldr x16, 8 */
|
|
||||||
grub_uint32_t br; /* br x16 */
|
|
||||||
grub_uint64_t addr;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if EHDR is a valid ELF header.
|
* Check if EHDR is a valid ELF header.
|
||||||
|
@ -53,42 +48,6 @@ grub_arch_dl_check_header (void *ehdr)
|
||||||
|
|
||||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||||
|
|
||||||
grub_err_t
|
|
||||||
grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
|
||||||
grub_size_t *got)
|
|
||||||
{
|
|
||||||
const Elf_Ehdr *e = ehdr;
|
|
||||||
const Elf_Shdr *s;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
*tramp = 0;
|
|
||||||
*got = 0;
|
|
||||||
|
|
||||||
for (i = 0, s = (const Elf_Shdr *) ((grub_addr_t) e + e->e_shoff);
|
|
||||||
i < e->e_shnum;
|
|
||||||
i++, s = (const Elf_Shdr *) ((grub_addr_t) s + e->e_shentsize))
|
|
||||||
if (s->sh_type == SHT_REL || s->sh_type == SHT_RELA)
|
|
||||||
{
|
|
||||||
const Elf_Rel *rel, *max;
|
|
||||||
|
|
||||||
for (rel = (const Elf_Rel *) ((grub_addr_t) e + s->sh_offset),
|
|
||||||
max = rel + s->sh_size / s->sh_entsize;
|
|
||||||
rel < max;
|
|
||||||
rel = (const Elf_Rel *) ((grub_addr_t) rel + s->sh_entsize))
|
|
||||||
switch (ELF_R_TYPE (rel->r_info))
|
|
||||||
{
|
|
||||||
case R_AARCH64_CALL26:
|
|
||||||
case R_AARCH64_JUMP26:
|
|
||||||
{
|
|
||||||
*tramp += sizeof (struct trampoline);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return GRUB_ERR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unified function for both REL and RELA
|
* Unified function for both REL and RELA
|
||||||
*/
|
*/
|
||||||
|
@ -97,6 +56,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
|
||||||
Elf_Shdr *s, grub_dl_segment_t seg)
|
Elf_Shdr *s, grub_dl_segment_t seg)
|
||||||
{
|
{
|
||||||
Elf_Rel *rel, *max;
|
Elf_Rel *rel, *max;
|
||||||
|
unsigned unmatched_adr_got_page = 0;
|
||||||
|
|
||||||
for (rel = (Elf_Rel *) ((char *) ehdr + s->sh_offset),
|
for (rel = (Elf_Rel *) ((char *) ehdr + s->sh_offset),
|
||||||
max = (Elf_Rel *) ((char *) rel + s->sh_size);
|
max = (Elf_Rel *) ((char *) rel + s->sh_size);
|
||||||
|
@ -145,7 +105,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
|
||||||
|
|
||||||
if (!grub_arm_64_check_xxxx26_offset (offset))
|
if (!grub_arm_64_check_xxxx26_offset (offset))
|
||||||
{
|
{
|
||||||
struct trampoline *tp = mod->trampptr;
|
struct grub_arm64_trampoline *tp = mod->trampptr;
|
||||||
mod->trampptr = tp + 1;
|
mod->trampptr = tp + 1;
|
||||||
tp->ldr = LDR;
|
tp->ldr = LDR;
|
||||||
tp->br = BR;
|
tp->br = BR;
|
||||||
|
@ -160,6 +120,56 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
|
||||||
grub_arm64_set_xxxx26_offset (place, offset);
|
grub_arm64_set_xxxx26_offset (place, offset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case R_AARCH64_PREL32:
|
||||||
|
{
|
||||||
|
grub_int64_t value;
|
||||||
|
Elf64_Word *addr32 = place;
|
||||||
|
value = ((grub_int32_t) *addr32) + sym_addr -
|
||||||
|
(Elf64_Xword) (grub_addr_t) seg->addr - rel->r_offset;
|
||||||
|
if (value != (grub_int32_t) value)
|
||||||
|
return grub_error (GRUB_ERR_BAD_MODULE, "relocation out of range");
|
||||||
|
grub_dprintf("dl", " reloc_prel32 %p => 0x%016llx\n",
|
||||||
|
place, (unsigned long long) sym_addr);
|
||||||
|
*addr32 = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case R_AARCH64_ADR_GOT_PAGE:
|
||||||
|
{
|
||||||
|
grub_uint64_t *gp = mod->gotptr;
|
||||||
|
Elf_Rela *rel2;
|
||||||
|
grub_int64_t gpoffset = ((grub_uint64_t) gp & ~0xfffULL) - (((grub_uint64_t) place) & ~0xfffULL);
|
||||||
|
*gp = (grub_uint64_t) sym_addr;
|
||||||
|
mod->gotptr = gp + 1;
|
||||||
|
unmatched_adr_got_page++;
|
||||||
|
grub_dprintf("dl", " reloc_got %p => 0x%016llx (0x%016llx)\n",
|
||||||
|
place, (unsigned long long) sym_addr, (unsigned long long) gp);
|
||||||
|
if (!grub_arm64_check_hi21_signed (gpoffset))
|
||||||
|
return grub_error (GRUB_ERR_BAD_MODULE,
|
||||||
|
"HI21 out of range");
|
||||||
|
grub_arm64_set_hi21(place, gpoffset);
|
||||||
|
for (rel2 = (Elf_Rela *) ((char *) rel + s->sh_entsize);
|
||||||
|
rel2 < (Elf_Rela *) max;
|
||||||
|
rel2 = (Elf_Rela *) ((char *) rel2 + s->sh_entsize))
|
||||||
|
if (ELF_R_SYM (rel2->r_info)
|
||||||
|
== ELF_R_SYM (rel->r_info)
|
||||||
|
&& ((Elf_Rela *) rel)->r_addend == rel2->r_addend
|
||||||
|
&& ELF_R_TYPE (rel2->r_info) == R_AARCH64_LD64_GOT_LO12_NC)
|
||||||
|
{
|
||||||
|
grub_arm64_set_abs_lo12_ldst64 ((void *) ((grub_addr_t) seg->addr + rel2->r_offset),
|
||||||
|
(grub_uint64_t)gp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rel2 >= (Elf_Rela *) max)
|
||||||
|
return grub_error (GRUB_ERR_BAD_MODULE,
|
||||||
|
"ADR_GOT_PAGE without matching LD64_GOT_LO12_NC");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case R_AARCH64_LD64_GOT_LO12_NC:
|
||||||
|
if (unmatched_adr_got_page == 0)
|
||||||
|
return grub_error (GRUB_ERR_BAD_MODULE,
|
||||||
|
"LD64_GOT_LO12_NC without matching ADR_GOT_PAGE");
|
||||||
|
unmatched_adr_got_page--;
|
||||||
|
break;
|
||||||
case R_AARCH64_ADR_PREL_PG_HI21:
|
case R_AARCH64_ADR_PREL_PG_HI21:
|
||||||
{
|
{
|
||||||
grub_int64_t offset = (sym_addr & ~0xfffULL) - (((grub_uint64_t) place) & ~0xfffULL);
|
grub_int64_t offset = (sym_addr & ~0xfffULL) - (((grub_uint64_t) place) & ~0xfffULL);
|
||||||
|
|
|
@ -93,3 +93,42 @@ grub_arm64_set_abs_lo12_ldst64 (grub_uint32_t *place, grub_int64_t target)
|
||||||
*place &= insmask;
|
*place &= insmask;
|
||||||
*place |= grub_cpu_to_le32 (target << 7) & ~insmask;
|
*place |= grub_cpu_to_le32 (target << 7) & ~insmask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||||
|
|
||||||
|
grub_err_t
|
||||||
|
grub_arm64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
||||||
|
grub_size_t *got)
|
||||||
|
{
|
||||||
|
const Elf64_Ehdr *e = ehdr;
|
||||||
|
const Elf64_Shdr *s;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
*tramp = 0;
|
||||||
|
*got = 0;
|
||||||
|
|
||||||
|
for (i = 0, s = (Elf64_Shdr *) ((char *) e + grub_le_to_cpu64 (e->e_shoff));
|
||||||
|
i < grub_le_to_cpu16 (e->e_shnum);
|
||||||
|
i++, s = (Elf64_Shdr *) ((char *) s + grub_le_to_cpu16 (e->e_shentsize)))
|
||||||
|
if (s->sh_type == grub_cpu_to_le32_compile_time (SHT_REL)
|
||||||
|
|| s->sh_type == grub_cpu_to_le32_compile_time (SHT_RELA))
|
||||||
|
{
|
||||||
|
const Elf64_Rela *rel, *max;
|
||||||
|
|
||||||
|
for (rel = (Elf64_Rela *) ((char *) e + grub_le_to_cpu64 (s->sh_offset)),
|
||||||
|
max = (const Elf64_Rela *) ((grub_addr_t) rel + grub_le_to_cpu64 (s->sh_size));
|
||||||
|
rel < max; rel = (const Elf64_Rela *) ((grub_addr_t) rel + grub_le_to_cpu64 (s->sh_entsize)))
|
||||||
|
switch (ELF64_R_TYPE (rel->r_info))
|
||||||
|
{
|
||||||
|
case R_AARCH64_CALL26:
|
||||||
|
case R_AARCH64_JUMP26:
|
||||||
|
*tramp += sizeof (struct grub_arm64_trampoline);
|
||||||
|
break;
|
||||||
|
case R_AARCH64_ADR_GOT_PAGE:
|
||||||
|
*got += 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,13 @@
|
||||||
#ifndef GRUB_ARM64_RELOC_H
|
#ifndef GRUB_ARM64_RELOC_H
|
||||||
#define GRUB_ARM64_RELOC_H 1
|
#define GRUB_ARM64_RELOC_H 1
|
||||||
|
|
||||||
|
struct grub_arm64_trampoline
|
||||||
|
{
|
||||||
|
grub_uint32_t ldr; /* ldr x16, 8 */
|
||||||
|
grub_uint32_t br; /* br x16 */
|
||||||
|
grub_uint64_t addr;
|
||||||
|
};
|
||||||
|
|
||||||
int grub_arm_64_check_xxxx26_offset (grub_int64_t offset);
|
int grub_arm_64_check_xxxx26_offset (grub_int64_t offset);
|
||||||
void
|
void
|
||||||
grub_arm64_set_xxxx26_offset (grub_uint32_t *place, grub_int64_t offset);
|
grub_arm64_set_xxxx26_offset (grub_uint32_t *place, grub_int64_t offset);
|
||||||
|
|
|
@ -263,11 +263,16 @@ void grub_arch_dl_init_linker (void);
|
||||||
grub_err_t
|
grub_err_t
|
||||||
grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
||||||
grub_size_t *got);
|
grub_size_t *got);
|
||||||
|
grub_err_t
|
||||||
|
grub_arm64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
||||||
|
grub_size_t *got);
|
||||||
|
|
||||||
#if defined (__ia64__)
|
#if defined (__ia64__)
|
||||||
#define GRUB_ARCH_DL_TRAMP_ALIGN GRUB_IA64_DL_TRAMP_ALIGN
|
#define GRUB_ARCH_DL_TRAMP_ALIGN GRUB_IA64_DL_TRAMP_ALIGN
|
||||||
#define GRUB_ARCH_DL_GOT_ALIGN GRUB_IA64_DL_GOT_ALIGN
|
#define GRUB_ARCH_DL_GOT_ALIGN GRUB_IA64_DL_GOT_ALIGN
|
||||||
#define grub_arch_dl_get_tramp_got_size grub_ia64_dl_get_tramp_got_size
|
#define grub_arch_dl_get_tramp_got_size grub_ia64_dl_get_tramp_got_size
|
||||||
|
#elif defined (__aarch64__)
|
||||||
|
#define grub_arch_dl_get_tramp_got_size grub_arm64_dl_get_tramp_got_size
|
||||||
#else
|
#else
|
||||||
grub_err_t
|
grub_err_t
|
||||||
grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
||||||
|
|
|
@ -2068,11 +2068,14 @@ typedef Elf32_Addr Elf32_Conflict;
|
||||||
#define R_AARCH64_NONE 0 /* No relocation. */
|
#define R_AARCH64_NONE 0 /* No relocation. */
|
||||||
#define R_AARCH64_ABS64 257 /* Direct 64 bit. */
|
#define R_AARCH64_ABS64 257 /* Direct 64 bit. */
|
||||||
#define R_AARCH64_ABS32 258 /* Direct 32 bit. */
|
#define R_AARCH64_ABS32 258 /* Direct 32 bit. */
|
||||||
|
#define R_AARCH64_PREL32 261
|
||||||
#define R_AARCH64_ADR_PREL_PG_HI21 275
|
#define R_AARCH64_ADR_PREL_PG_HI21 275
|
||||||
#define R_AARCH64_ADD_ABS_LO12_NC 277
|
#define R_AARCH64_ADD_ABS_LO12_NC 277
|
||||||
#define R_AARCH64_LDST64_ABS_LO12_NC 286
|
#define R_AARCH64_LDST64_ABS_LO12_NC 286
|
||||||
#define R_AARCH64_JUMP26 282 /* 26-bit relative. */
|
#define R_AARCH64_JUMP26 282 /* 26-bit relative. */
|
||||||
#define R_AARCH64_CALL26 283 /* 26-bit relative. */
|
#define R_AARCH64_CALL26 283 /* 26-bit relative. */
|
||||||
|
#define R_AARCH64_ADR_GOT_PAGE 311
|
||||||
|
#define R_AARCH64_LD64_GOT_LO12_NC 312
|
||||||
#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */
|
#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */
|
||||||
#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */
|
#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */
|
||||||
#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */
|
#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */
|
||||||
|
|
|
@ -30,7 +30,7 @@ struct grub_mkimage_layout
|
||||||
size_t align;
|
size_t align;
|
||||||
grub_size_t ia64jmp_off;
|
grub_size_t ia64jmp_off;
|
||||||
grub_size_t tramp_off;
|
grub_size_t tramp_off;
|
||||||
grub_size_t ia64_got_off;
|
grub_size_t got_off;
|
||||||
grub_size_t got_size;
|
grub_size_t got_size;
|
||||||
unsigned ia64jmpnum;
|
unsigned ia64jmpnum;
|
||||||
grub_uint32_t bss_start;
|
grub_uint32_t bss_start;
|
||||||
|
|
|
@ -717,6 +717,7 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
|
||||||
#ifdef MKIMAGE_ELF64
|
#ifdef MKIMAGE_ELF64
|
||||||
struct grub_ia64_trampoline *tr = (void *) (pe_target + tramp_off);
|
struct grub_ia64_trampoline *tr = (void *) (pe_target + tramp_off);
|
||||||
grub_uint64_t *gpptr = (void *) (pe_target + got_off);
|
grub_uint64_t *gpptr = (void *) (pe_target + got_off);
|
||||||
|
unsigned unmatched_adr_got_page = 0;
|
||||||
#define MASK19 ((1 << 19) - 1)
|
#define MASK19 ((1 << 19) - 1)
|
||||||
#else
|
#else
|
||||||
grub_uint32_t *tr = (void *) (pe_target + tramp_off);
|
grub_uint32_t *tr = (void *) (pe_target + tramp_off);
|
||||||
|
@ -965,6 +966,18 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
|
||||||
*target = grub_host_to_target64 (grub_target_to_host64 (*target) + sym_addr);
|
*target = grub_host_to_target64 (grub_target_to_host64 (*target) + sym_addr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case R_AARCH64_PREL32:
|
||||||
|
{
|
||||||
|
grub_uint32_t *t32 = (grub_uint32_t *) target;
|
||||||
|
*t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
|
||||||
|
+ sym_addr
|
||||||
|
- target_section_addr - offset
|
||||||
|
- image_target->vaddr_offset);
|
||||||
|
grub_util_info ("relocating an R_AARCH64_PREL32 entry to 0x%x at the offset 0x%"
|
||||||
|
GRUB_HOST_PRIxLONG_LONG,
|
||||||
|
*t32, (unsigned long long) offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case R_AARCH64_ADD_ABS_LO12_NC:
|
case R_AARCH64_ADD_ABS_LO12_NC:
|
||||||
grub_arm64_set_abs_lo12 ((grub_uint32_t *) target,
|
grub_arm64_set_abs_lo12 ((grub_uint32_t *) target,
|
||||||
sym_addr);
|
sym_addr);
|
||||||
|
@ -985,6 +998,41 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
|
||||||
sym_addr);
|
sym_addr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case R_AARCH64_ADR_GOT_PAGE:
|
||||||
|
{
|
||||||
|
Elf64_Rela *rel2;
|
||||||
|
grub_int64_t gpoffset = (((char *) gpptr - (char *) pe_target + image_target->vaddr_offset) & ~0xfffULL)
|
||||||
|
- ((offset + target_section_addr + image_target->vaddr_offset) & ~0xfffULL);
|
||||||
|
unsigned k;
|
||||||
|
*gpptr = grub_host_to_target64 (sym_addr);
|
||||||
|
unmatched_adr_got_page++;
|
||||||
|
if (!grub_arm64_check_hi21_signed (gpoffset))
|
||||||
|
grub_util_error ("HI21 out of range");
|
||||||
|
grub_arm64_set_hi21((grub_uint32_t *)target,
|
||||||
|
gpoffset);
|
||||||
|
for (k = 0, rel2 = (Elf_Rela *) ((char *) r + r_size);
|
||||||
|
k < num_rs;
|
||||||
|
k++, rel2 = (Elf_Rela *) ((char *) rel2 + r_size))
|
||||||
|
if (ELF_R_SYM (rel2->r_info)
|
||||||
|
== ELF_R_SYM (r->r_info)
|
||||||
|
&& r->r_addend == rel2->r_addend
|
||||||
|
&& ELF_R_TYPE (rel2->r_info) == R_AARCH64_LD64_GOT_LO12_NC)
|
||||||
|
{
|
||||||
|
grub_arm64_set_abs_lo12_ldst64 ((grub_uint32_t *) SUFFIX (get_target_address) (e, target_section,
|
||||||
|
grub_target_to_host (rel2->r_offset), image_target),
|
||||||
|
((char *) gpptr - (char *) pe_target + image_target->vaddr_offset));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (k >= num_rs)
|
||||||
|
grub_util_error ("ADR_GOT_PAGE without matching LD64_GOT_LO12_NC");
|
||||||
|
gpptr++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case R_AARCH64_LD64_GOT_LO12_NC:
|
||||||
|
if (unmatched_adr_got_page == 0)
|
||||||
|
grub_util_error ("LD64_GOT_LO12_NC without matching ADR_GOT_PAGE");
|
||||||
|
unmatched_adr_got_page--;
|
||||||
|
break;
|
||||||
case R_AARCH64_ADR_PREL_PG_HI21:
|
case R_AARCH64_ADR_PREL_PG_HI21:
|
||||||
{
|
{
|
||||||
sym_addr &= ~0xfffULL;
|
sym_addr &= ~0xfffULL;
|
||||||
|
@ -1329,6 +1377,7 @@ translate_relocation_pe (struct translate_context *ctx,
|
||||||
/* Relative relocations do not require fixup entries. */
|
/* Relative relocations do not require fixup entries. */
|
||||||
case R_AARCH64_CALL26:
|
case R_AARCH64_CALL26:
|
||||||
case R_AARCH64_JUMP26:
|
case R_AARCH64_JUMP26:
|
||||||
|
case R_AARCH64_PREL32:
|
||||||
break;
|
break;
|
||||||
/* Page-relative relocations do not require fixup entries. */
|
/* Page-relative relocations do not require fixup entries. */
|
||||||
case R_AARCH64_ADR_PREL_PG_HI21:
|
case R_AARCH64_ADR_PREL_PG_HI21:
|
||||||
|
@ -1339,6 +1388,11 @@ translate_relocation_pe (struct translate_context *ctx,
|
||||||
case R_AARCH64_LDST64_ABS_LO12_NC:
|
case R_AARCH64_LDST64_ABS_LO12_NC:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* GOT is relocated separately. */
|
||||||
|
case R_AARCH64_ADR_GOT_PAGE:
|
||||||
|
case R_AARCH64_LD64_GOT_LO12_NC:
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
grub_util_error (_("relocation 0x%x is not implemented yet"),
|
grub_util_error (_("relocation 0x%x is not implemented yet"),
|
||||||
(unsigned int) ELF_R_TYPE (info));
|
(unsigned int) ELF_R_TYPE (info));
|
||||||
|
@ -1547,9 +1601,9 @@ finish_reloc_translation (struct translate_context *ctx, struct grub_mkimage_lay
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
translate_reloc_jumpers (struct translate_context *ctx,
|
create_u64_fixups (struct translate_context *ctx,
|
||||||
Elf_Addr jumpers, grub_size_t njumpers,
|
Elf_Addr jumpers, grub_size_t njumpers,
|
||||||
const struct grub_install_image_target_desc *image_target)
|
const struct grub_install_image_target_desc *image_target)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
assert (image_target->id == IMAGE_EFI);
|
assert (image_target->id == IMAGE_EFI);
|
||||||
|
@ -1614,11 +1668,17 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image_target->elf_target == EM_IA_64)
|
if (image_target->elf_target == EM_IA_64)
|
||||||
translate_reloc_jumpers (&ctx,
|
create_u64_fixups (&ctx,
|
||||||
layout->ia64jmp_off
|
layout->ia64jmp_off
|
||||||
+ image_target->vaddr_offset,
|
+ image_target->vaddr_offset,
|
||||||
2 * layout->ia64jmpnum + (layout->got_size / 8),
|
2 * layout->ia64jmpnum,
|
||||||
image_target);
|
image_target);
|
||||||
|
if (image_target->elf_target == EM_IA_64 || image_target->elf_target == EM_AARCH64)
|
||||||
|
create_u64_fixups (&ctx,
|
||||||
|
layout->got_off
|
||||||
|
+ image_target->vaddr_offset,
|
||||||
|
(layout->got_size / 8),
|
||||||
|
image_target);
|
||||||
|
|
||||||
finish_reloc_translation (&ctx, layout, image_target);
|
finish_reloc_translation (&ctx, layout, image_target);
|
||||||
}
|
}
|
||||||
|
@ -1944,7 +2004,18 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path,
|
||||||
image_target);
|
image_target);
|
||||||
layout->kernel_size += 16 * layout->ia64jmpnum;
|
layout->kernel_size += 16 * layout->ia64jmpnum;
|
||||||
|
|
||||||
layout->ia64_got_off = layout->kernel_size;
|
layout->got_off = layout->kernel_size;
|
||||||
|
layout->kernel_size += ALIGN_UP (layout->got_size, 16);
|
||||||
|
}
|
||||||
|
if (image_target->elf_target == EM_AARCH64)
|
||||||
|
{
|
||||||
|
grub_size_t tramp;
|
||||||
|
|
||||||
|
layout->kernel_size = ALIGN_UP (layout->kernel_size, 16);
|
||||||
|
|
||||||
|
grub_arm64_dl_get_tramp_got_size (e, &tramp, &layout->got_size);
|
||||||
|
|
||||||
|
layout->got_off = layout->kernel_size;
|
||||||
layout->kernel_size += ALIGN_UP (layout->got_size, 16);
|
layout->kernel_size += ALIGN_UP (layout->got_size, 16);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1977,7 +2048,7 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path,
|
||||||
section_entsize,
|
section_entsize,
|
||||||
num_sections, strtab,
|
num_sections, strtab,
|
||||||
out_img, layout->tramp_off,
|
out_img, layout->tramp_off,
|
||||||
layout->ia64_got_off,
|
layout->got_off,
|
||||||
image_target);
|
image_target);
|
||||||
|
|
||||||
make_reloc_section (e, layout,
|
make_reloc_section (e, layout,
|
||||||
|
|
|
@ -107,11 +107,14 @@ struct grub_module_verifier_arch archs[] = {
|
||||||
R_AARCH64_ABS64,
|
R_AARCH64_ABS64,
|
||||||
R_AARCH64_CALL26,
|
R_AARCH64_CALL26,
|
||||||
R_AARCH64_JUMP26,
|
R_AARCH64_JUMP26,
|
||||||
|
R_AARCH64_ADR_GOT_PAGE,
|
||||||
|
R_AARCH64_LD64_GOT_LO12_NC,
|
||||||
-1
|
-1
|
||||||
}, (int[]){
|
}, (int[]){
|
||||||
R_AARCH64_ADR_PREL_PG_HI21,
|
R_AARCH64_ADR_PREL_PG_HI21,
|
||||||
R_AARCH64_ADD_ABS_LO12_NC,
|
R_AARCH64_ADD_ABS_LO12_NC,
|
||||||
R_AARCH64_LDST64_ABS_LO12_NC,
|
R_AARCH64_LDST64_ABS_LO12_NC,
|
||||||
|
R_AARCH64_PREL32,
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -319,6 +319,40 @@ section_check_relocations (const struct grub_module_verifier_arch *arch, void *e
|
||||||
continue;
|
continue;
|
||||||
grub_util_error ("relocation 0x%x is not module-local", type);
|
grub_util_error ("relocation 0x%x is not module-local", type);
|
||||||
}
|
}
|
||||||
|
#if defined(MODULEVERIFIER_ELF64)
|
||||||
|
if (arch->machine == EM_AARCH64)
|
||||||
|
{
|
||||||
|
unsigned unmatched_adr_got_page = 0;
|
||||||
|
Elf_Rela *rel2;
|
||||||
|
for (rel = (Elf_Rel *) ((char *) ehdr + grub_target_to_host (s->sh_offset)),
|
||||||
|
max = (Elf_Rel *) ((char *) rel + grub_target_to_host (s->sh_size));
|
||||||
|
rel < max;
|
||||||
|
rel = (Elf_Rel *) ((char *) rel + grub_target_to_host (s->sh_entsize)))
|
||||||
|
{
|
||||||
|
switch (ELF_R_TYPE (grub_target_to_host (rel->r_info)))
|
||||||
|
{
|
||||||
|
case R_AARCH64_ADR_GOT_PAGE:
|
||||||
|
unmatched_adr_got_page++;
|
||||||
|
for (rel2 = (Elf_Rela *) ((char *) rel + grub_target_to_host (s->sh_entsize));
|
||||||
|
rel2 < (Elf_Rela *) max;
|
||||||
|
rel2 = (Elf_Rela *) ((char *) rel2 + grub_target_to_host (s->sh_entsize)))
|
||||||
|
if (ELF_R_SYM (rel2->r_info)
|
||||||
|
== ELF_R_SYM (rel->r_info)
|
||||||
|
&& ((Elf_Rela *) rel)->r_addend == rel2->r_addend
|
||||||
|
&& ELF_R_TYPE (rel2->r_info) == R_AARCH64_LD64_GOT_LO12_NC)
|
||||||
|
break;
|
||||||
|
if (rel2 >= (Elf_Rela *) max)
|
||||||
|
grub_util_error ("ADR_GOT_PAGE without matching LD64_GOT_LO12_NC");
|
||||||
|
break;
|
||||||
|
case R_AARCH64_LD64_GOT_LO12_NC:
|
||||||
|
if (unmatched_adr_got_page == 0)
|
||||||
|
grub_util_error ("LD64_GOT_LO12_NC without matching ADR_GOT_PAGE");
|
||||||
|
unmatched_adr_got_page--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in a new issue