ET_REL images contain lots of complicated relocations. One new relocation we need to support is R_LARCH_GOT_PC_HI20/LO12. Rather than the eternal chasing of complicated we can use linker to handle them and then only relatively simple dynamic relocs remain to handle.
This required small adjustments to the asm code to be compatible with -shared. Signed-off-by: Vladimir Serbinenko <phco...@gmail.com> --- conf/Makefile.common | 8 +- configure.ac | 7 +- grub-core/Makefile.core.def | 20 +- grub-core/kern/ia64/efi/startup.S | 7 +- grub-core/kern/mips/startup.S | 4 +- grub-core/kern/x86_64/efi/startup.S | 6 +- include/grub/util/mkimage.h | 3 + util/grub-mkimagexx.c | 451 +++++++++++++++------------- 8 files changed, 270 insertions(+), 236 deletions(-) diff --git a/conf/Makefile.common b/conf/Makefile.common index 3e2dff090..900a15c7b 100644 --- a/conf/Makefile.common +++ b/conf/Makefile.common @@ -41,7 +41,7 @@ CFLAGS_KERNEL = $(CFLAGS_PLATFORM) -ffreestanding LDFLAGS_KERNEL = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1 CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) -STRIPFLAGS_KERNEL = -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx +STRIPFLAGS_KERNEL = -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx if !COND_emu if COND_HAVE_ASM_USCORE LDFLAGS_KERNEL += -Wl,--defsym=_malloc=_grub_malloc -Wl,--defsym=_free=_grub_free @@ -54,10 +54,10 @@ CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding if COND_emu LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib -Wl,-r else -if COND_mips -LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -shared +if COND_i386 +LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -shared -Wl,-Ttext-segment=0 -Wl,-Bstatic -Wl,-T${srcdir}/../conf/i386-modules.sc else -LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -shared -Wl,-Ttext-segment=0 -Wl,-Bstatic -Wl,-T${srcdir}/../conf/modules.sc +LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -shared endif endif CPPFLAGS_MODULE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) diff --git a/configure.ac b/configure.ac index cdb6a5c41..25f3ff932 100644 --- a/configure.ac +++ b/configure.ac @@ -876,9 +876,6 @@ if ( test "x$target_cpu" = xi386 || test "x$target_cpu" = xx86_64 ); then fi if test "x$target_cpu" = xloongarch64; then - TARGET_CFLAGS="$TARGET_CFLAGS -fno-plt" - TARGET_CCASFLAGS="$TARGET_CCASFLAGS -fno-plt" - AC_CACHE_CHECK([for no-relax options], grub_cv_target_cc_mno_relax, [ grub_cv_target_cc_mno_relax=no for cand in "-mno-relax" "-Wa,-mno-relax"; do @@ -1405,7 +1402,8 @@ case $target_cpu-$platform in TARGET_CFLAGS="$TARGET_CFLAGS -fPIC" fi ;; - riscv32-* | ia64-*) + # THose platforms require -fPIC in order to generate ET_DYN + riscv32-* | ia64-* | loongarch64-*) TARGET_CFLAGS="$TARGET_CFLAGS -fPIC" ;; *) @@ -2198,6 +2196,7 @@ AM_CONDITIONAL([COND_sparc64_ieee1275], [test x$target_cpu = xsparc64 -a x$platf AM_CONDITIONAL([COND_sparc64_emu], [test x$target_cpu = xsparc64 -a x$platform = xemu]) AM_CONDITIONAL([COND_x86_64_efi], [test x$target_cpu = xx86_64 -a x$platform = xefi]) AM_CONDITIONAL([COND_x86_64_xen], [test x$target_cpu = xx86_64 -a x$platform = xxen]) +AM_CONDITIONAL([COND_i386], [test x$target_cpu = xi386]) AM_CONDITIONAL([COND_HOST_HURD], [test x$host_kernel = xhurd]) AM_CONDITIONAL([COND_HOST_LINUX], [test x$host_kernel = xlinux]) diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index f70e02e69..4c6269c2b 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -51,34 +51,34 @@ kernel = { emu_ldflags = '-Wl,-r'; i386_efi_cflags = '-fshort-wchar'; - i386_efi_ldflags = '-Wl,-r'; + i386_efi_ldflags = '-shared'; i386_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; x86_64_efi_cflags = '-fshort-wchar'; - x86_64_efi_ldflags = '-Wl,-r'; + x86_64_efi_ldflags = '-shared'; x86_64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; ia64_efi_cflags = '-fshort-wchar -fno-builtin -fpic -minline-int-divide-max-throughput'; - ia64_efi_ldflags = '-Wl,-r'; + ia64_efi_ldflags = '-shared'; ia64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; arm_efi_cflags = '-fshort-wchar'; - arm_efi_ldflags = '-Wl,-r'; + arm_efi_ldflags = '-shared'; arm_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; arm64_efi_cflags = '-fshort-wchar'; - arm64_efi_ldflags = '-Wl,-r'; + arm64_efi_ldflags = '-shared'; arm64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version -R .eh_frame'; loongarch64_efi_cflags = '-fshort-wchar'; - loongarch64_efi_ldflags = '-Wl,-r'; + loongarch64_efi_ldflags = '-shared'; loongarch64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version -R .eh_frame'; riscv32_efi_cflags = '-fshort-wchar'; - riscv32_efi_ldflags = '-Wl,-r'; + riscv32_efi_ldflags = '-shared'; riscv32_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version -R .eh_frame'; riscv64_efi_cflags = '-fshort-wchar'; - riscv64_efi_ldflags = '-Wl,-r'; + riscv64_efi_ldflags = '-shared'; riscv64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version -R .eh_frame'; i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)'; @@ -108,9 +108,9 @@ kernel = { i386_qemu_cppflags = '-DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR)'; emu_cflags = '$(CFLAGS_GNULIB)'; emu_cppflags = '$(CPPFLAGS_GNULIB)'; - arm_uboot_ldflags = '-Wl,-r'; + arm_uboot_ldflags = '-shared'; arm_uboot_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; - arm_coreboot_ldflags = '-Wl,-r'; + arm_coreboot_ldflags = '-shared'; arm_coreboot_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; i386_pc_startup = kern/i386/pc/startup.S; diff --git a/grub-core/kern/ia64/efi/startup.S b/grub-core/kern/ia64/efi/startup.S index d75c6d7cc..e220cbf2d 100644 --- a/grub-core/kern/ia64/efi/startup.S +++ b/grub-core/kern/ia64/efi/startup.S @@ -29,8 +29,11 @@ _start: alloc loc0=ar.pfs,2,4,0,0 mov loc1=rp - addl loc2=@gprel(grub_efi_image_handle),gp - addl loc3=@gprel(grub_efi_system_table),gp + addl loc2=@ltoffx(grub_efi_image_handle),r1 + addl loc3=@ltoffx(grub_efi_system_table),r1 + ;; + ld8.mov loc2 = [loc2], grub_efi_image_handle + ld8.mov loc3 = [loc3], grub_efi_system_table ;; st8 [loc2]=in0 st8 [loc3]=in1 diff --git a/grub-core/kern/mips/startup.S b/grub-core/kern/mips/startup.S index 1fdb58aca..fde64358c 100644 --- a/grub-core/kern/mips/startup.S +++ b/grub-core/kern/mips/startup.S @@ -74,8 +74,8 @@ cont: #endif /* Move the modules out of BSS. */ - lui $t2, %hi(__bss_start) - addiu $t2, %lo(__bss_start) + lui $t2, %hi(_edata) + addiu $t2, %lo(_edata) lui $t1, %hi(_end) addiu $t1, %lo(_end) diff --git a/grub-core/kern/x86_64/efi/startup.S b/grub-core/kern/x86_64/efi/startup.S index 9357e5c5d..d27bbbf12 100644 --- a/grub-core/kern/x86_64/efi/startup.S +++ b/grub-core/kern/x86_64/efi/startup.S @@ -27,8 +27,10 @@ start: _start: - movq %rcx, EXT_C(grub_efi_image_handle)(%rip) - movq %rdx, EXT_C(grub_efi_system_table)(%rip) + movq EXT_C(grub_efi_image_handle)@GOTPCREL(%rip), %rax + movq %rcx, (%rax) + movq EXT_C(grub_efi_system_table)@GOTPCREL(%rip), %rax + movq %rdx, (%rax) andq $~0xf, %rsp call EXT_C(grub_main) diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h index 9d74f82c5..e9ed38874 100644 --- a/include/grub/util/mkimage.h +++ b/include/grub/util/mkimage.h @@ -36,6 +36,9 @@ struct grub_mkimage_layout unsigned ia64jmpnum; grub_uint32_t bss_start; grub_uint32_t end; + grub_int64_t vaddr_diff; + grub_int64_t off_diff; + grub_size_t dyn_pltoff; }; /* Private header. Use only in mkimage-related sources. */ diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index 97e83671a..8fa3d5266 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -100,11 +100,13 @@ struct section_metadata { Elf_Half num_sections; Elf_Shdr *sections; - Elf_Addr *addrs; - Elf_Addr *vaddrs; Elf_Half section_entsize; Elf_Shdr *symtab; const char *strtab; + + Elf_Half num_phdrs; + Elf_Phdr *phdrs; + Elf_Half phdr_entsize; }; #define GRUB_SBAT_NOTE_NAME ".sbat" @@ -604,7 +606,7 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc static Elf_Addr SUFFIX (relocate_symbols) (Elf_Ehdr *e, struct section_metadata *smd, void *jumpers, Elf_Addr jumpers_addr, - Elf_Addr bss_start, Elf_Addr end, + struct grub_mkimage_layout *layout, const struct grub_install_image_target_desc *image_target) { Elf_Word symtab_size, sym_size, num_syms; @@ -642,11 +644,7 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, struct section_metadata *smd, } else if (cur_index == STN_UNDEF) { - if (sym->st_name && grub_strcmp (name, "__bss_start") == 0) - sym->st_value = bss_start; - else if (sym->st_name && grub_strcmp (name, "_end") == 0) - sym->st_value = end; - else if (sym->st_name) + if (sym->st_name) grub_util_error ("undefined symbol %s", name); else continue; @@ -656,7 +654,7 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, struct section_metadata *smd, else { sym->st_value = (grub_target_to_host (sym->st_value) - + smd->vaddrs[cur_index]); + + layout->vaddr_diff); } if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info) @@ -665,13 +663,11 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, struct section_metadata *smd, *jptr = grub_host_to_target64 (sym->st_value); sym->st_value = (char *) jptr - (char *) jumpers + jumpers_addr; jptr++; - *jptr = 0; + *jptr = layout->vaddr_diff + layout->dyn_pltoff; jptr++; } - grub_util_info ("locating %s at 0x%" GRUB_HOST_PRIxLONG_LONG - " (0x%" GRUB_HOST_PRIxLONG_LONG ")", name, - (unsigned long long) sym->st_value, - (unsigned long long) smd->vaddrs[cur_index]); + grub_util_info ("locating %s at 0x%" GRUB_HOST_PRIxLONG_LONG, name, + (unsigned long long) sym->st_value); if (start_address == (Elf_Addr)-1) if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0) @@ -696,10 +692,10 @@ SUFFIX (get_symbol_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i, /* Return the address of a modified value. */ static Elf_Addr * -SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset, +SUFFIX (get_target_address) (char *e, struct grub_mkimage_layout *layout, Elf_Addr offset, const struct grub_install_image_target_desc *image_target) { - return (Elf_Addr *) ((char *) e + grub_target_to_host (s->sh_offset) + offset); + return (Elf_Addr *) ((char *) e + offset + layout->off_diff); } #ifdef MKIMAGE_ELF64 @@ -783,6 +779,8 @@ arm_get_trampoline_size (Elf_Ehdr *e, { case R_ARM_ABS32: case R_ARM_V4BX: + case R_ARM_JUMP_SLOT: + case R_ARM_RELATIVE: break; case R_ARM_THM_CALL: case R_ARM_THM_JUMP24: @@ -820,20 +818,20 @@ SUFFIX (is_kept_reloc_section) (Elf_Shdr *s, const struct grub_install_image_tar again by a PE32 relocator when loaded. */ static void SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, - char *pe_target, Elf_Addr tramp_off, Elf_Addr got_off, + char *pe_target, struct grub_mkimage_layout *layout, const struct grub_install_image_target_desc *image_target) { Elf_Half i; Elf_Shdr *s; #ifdef MKIMAGE_ELF64 - struct grub_ia64_trampoline *tr = (void *) (pe_target + tramp_off); - grub_uint64_t *gpptr = (void *) (pe_target + got_off); + struct grub_ia64_trampoline *tr = (void *) (pe_target + layout->tramp_off); + grub_uint64_t *gpptr = (void *) (pe_target + layout->got_off); unsigned unmatched_adr_got_page = 0; struct grub_loongarch64_stack stack; grub_loongarch64_stack_init (&stack); #define MASK19 ((1 << 19) - 1) #else - grub_uint32_t *tr = (void *) (pe_target + tramp_off); + grub_uint32_t *tr = (void *) (pe_target + layout->tramp_off); #endif for (i = 0, s = smd->sections; @@ -846,7 +844,7 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, Elf_Word rtab_size, r_size, num_rs; Elf_Off rtab_offset; Elf_Word target_section_index; - Elf_Addr target_section_addr; + Elf_Addr target_section_addr = layout->vaddr_diff; Elf_Shdr *target_section; Elf_Word j; @@ -859,7 +857,6 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, } target_section_index = grub_target_to_host32 (s->sh_info); - target_section_addr = smd->addrs[target_section_index]; target_section = (Elf_Shdr *) ((char *) smd->sections + (target_section_index * smd->section_entsize)); @@ -884,7 +881,7 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, Elf_Addr addend; offset = grub_target_to_host (r->r_offset); - target = SUFFIX (get_target_address) (e, target_section, + target = SUFFIX (get_target_address) (pe_target, layout, offset, image_target); info = grub_target_to_host (r->r_info); sym_addr = SUFFIX (get_symbol_address) (e, smd->symtab, @@ -938,10 +935,24 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, case R_X86_64_NONE: break; + case R_X86_64_RELATIVE: + *target = grub_host_to_target64 (addend + layout->vaddr_diff); + break; + + case R_X86_64_GLOB_DAT: case R_X86_64_64: *target = grub_host_to_target64 (grub_target_to_host64 (*target) + addend + sym_addr); grub_util_info ("relocating an R_X86_64_64 entry to 0x%" + GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG " by 0x%lx", + (unsigned long long) *target, + (unsigned long long) offset, addend + sym_addr); + break; + + case R_X86_64_JUMP_SLOT: + *target = grub_host_to_target64 (addend + sym_addr); + grub_util_info ("relocating an R_X86_64_JUMP_SLOT entry to 0x%" GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" GRUB_HOST_PRIxLONG_LONG, (unsigned long long) *target, @@ -1012,6 +1023,10 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, } break; + case R_IA64_REL64LSB: + *target = grub_host_to_target64 (addend + layout->vaddr_diff); + break; + case R_IA64_LTOFF22X: case R_IA64_LTOFF22: { @@ -1053,10 +1068,18 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, *target = grub_host_to_target64 (grub_target_to_host64 (*target) + addend + sym_addr - target_section_addr); break; + case R_IA64_IPLTLSB: + memcpy(target, ((char *)pe_target + addend + sym_addr - image_target->vaddr_offset), 16); + grub_util_info ("relocating an IPLT entry to 0x%" + GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) + grub_target_to_host64 (*target), + (unsigned long long) offset); + break; case R_IA64_DIR64LSB: case R_IA64_FPTR64LSB: - *target = grub_host_to_target64 (grub_target_to_host64 (*target) - + addend + sym_addr); + *target = grub_host_to_target64 (addend + sym_addr); grub_util_info ("relocating a direct entry to 0x%" GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" GRUB_HOST_PRIxLONG_LONG, @@ -1080,11 +1103,17 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, sym_addr += addend; switch (ELF_R_TYPE (info)) { + case R_AARCH64_JUMP_SLOT: + *target = grub_host_to_target64 (sym_addr); + break; case R_AARCH64_ABS64: { *target = grub_host_to_target64 (grub_target_to_host64 (*target) + sym_addr); } break; + case R_AARCH64_RELATIVE: + *target = grub_host_to_target64 (addend + layout->vaddr_diff); + break; case R_AARCH64_PREL32: { grub_uint32_t *t32 = (grub_uint32_t *) target; @@ -1137,7 +1166,7 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, && 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_arm64_set_abs_lo12_ldst64 ((grub_uint32_t *) SUFFIX (get_target_address) (pe_target, layout, grub_target_to_host (rel2->r_offset), image_target), ((char *) gpptr - (char *) pe_target + image_target->vaddr_offset)); break; @@ -1184,9 +1213,15 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, case R_LARCH_64: { grub_uint64_t *t64 = (grub_uint64_t *) target; - *t64 = grub_host_to_target64 (grub_target_to_host64 (*t64) + sym_addr); + *t64 = grub_host_to_target64 (sym_addr); } break; + case R_LARCH_JUMP_SLOT: + *target = grub_host_to_target64 (sym_addr); + break; + case R_LARCH_RELATIVE: + *target = grub_host_to_target64 (addend + layout->vaddr_diff); + break; case R_LARCH_MARK_LA: break; case R_LARCH_SOP_PUSH_PCREL: @@ -1243,6 +1278,15 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, sym_addr -= image_target->vaddr_offset; switch (ELF_R_TYPE (info)) { + case R_ARM_JUMP_SLOT: + { + grub_util_info (" JUMP:\toffset=%d\t(0x%08x)", + (int) sym_addr, (int) sym_addr); + if (image_target->id == IMAGE_EFI) + sym_addr += GRUB_PE32_SECTION_ALIGNMENT; + *target = grub_host_to_target32 (sym_addr); + break; + } case R_ARM_ABS32: { grub_util_info (" ABS32:\toffset=%d\t(0x%08x)", @@ -1253,6 +1297,9 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, *target = grub_host_to_target32 (grub_target_to_host32 (*target) + sym_addr); } break; + case R_ARM_RELATIVE: + *target = grub_host_to_target32 (grub_target_to_host32 (*target) + addend + layout->vaddr_diff); + break; /* Happens when compiled with -march=armv4. Since currently we need at least armv5, keep bx as-is. */ @@ -1358,6 +1405,12 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, switch (ELF_R_TYPE (info)) { + case R_RISCV_JUMP_SLOT: + *target = grub_host_to_target_addr (sym_addr); + break; + case R_RISCV_RELATIVE: + *target = grub_host_to_target_addr (addend + layout->vaddr_diff); + break; case R_RISCV_ADD8: *t8 = *t8 + sym_addr; break; @@ -1696,7 +1749,10 @@ translate_relocation_pe (struct translate_context *ctx, { grub_util_error ("can\'t add fixup entry for R_X86_64_32(S)"); } - else if (ELF_R_TYPE (info) == R_X86_64_64) + else if (ELF_R_TYPE (info) == R_X86_64_64 + || ELF_R_TYPE (info) == R_X86_64_RELATIVE + || ELF_R_TYPE (info) == R_X86_64_JUMP_SLOT + || ELF_R_TYPE (info) == R_X86_64_GLOB_DAT) { grub_util_info ("adding a relocation entry for 0x%" GRUB_HOST_PRIxLONG_LONG, @@ -1723,8 +1779,31 @@ translate_relocation_pe (struct translate_context *ctx, case R_IA64_SEGREL64LSB: break; + case R_IA64_IPLTLSB: +#if 1 + { + grub_util_info ("adding a relocation entry for 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) addr); + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + addr, + 0, ctx->current_address, + image_target); + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + addr + 8, + 0, ctx->current_address, + image_target); + } +#endif + break; + case R_IA64_FPTR64LSB: case R_IA64_DIR64LSB: + case R_IA64_REL64LSB: #if 1 { grub_util_info ("adding a relocation entry for 0x%" @@ -1749,7 +1828,9 @@ translate_relocation_pe (struct translate_context *ctx, #if defined(MKIMAGE_ELF64) switch (ELF_R_TYPE (info)) { + case R_AARCH64_RELATIVE: case R_AARCH64_ABS64: + case R_AARCH64_JUMP_SLOT: { ctx->current_address = add_fixup_entry (&ctx->lst, @@ -1789,6 +1870,8 @@ translate_relocation_pe (struct translate_context *ctx, switch (ELF_R_TYPE (info)) { case R_LARCH_64: + case R_LARCH_RELATIVE: + case R_LARCH_JUMP_SLOT: { ctx->current_address = add_fixup_entry (&ctx->lst, GRUB_PE32_REL_BASED_DIR64, @@ -1859,6 +1942,8 @@ translate_relocation_pe (struct translate_context *ctx, break; /* Create fixup entry for PE/COFF loader */ case R_ARM_ABS32: + case R_ARM_JUMP_SLOT: + case R_ARM_RELATIVE: { ctx->current_address = add_fixup_entry (&ctx->lst, @@ -1877,6 +1962,10 @@ translate_relocation_pe (struct translate_context *ctx, case EM_RISCV: switch (ELF_R_TYPE (info)) { +#if defined(MKIMAGE_ELF32) + case R_RISCV_RELATIVE: + case R_RISCV_JUMP_SLOT: +#endif case R_RISCV_32: { ctx->current_address @@ -1886,6 +1975,10 @@ translate_relocation_pe (struct translate_context *ctx, image_target); } break; +#if defined(MKIMAGE_ELF64) + case R_RISCV_RELATIVE: + case R_RISCV_JUMP_SLOT: +#endif case R_RISCV_64: { ctx->current_address @@ -2147,7 +2240,6 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, Elf_Rel *r; Elf_Word rtab_size, r_size, num_rs; Elf_Off rtab_offset; - Elf_Addr section_address; Elf_Word j; if (!SUFFIX (is_kept_reloc_section) (s, image_target, smd)) @@ -2165,8 +2257,6 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, rtab_offset = grub_target_to_host (s->sh_offset); num_rs = rtab_size / r_size; - section_address = smd->vaddrs[grub_le_to_cpu32 (s->sh_info)]; - for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset); j < num_rs; j++, r = (Elf_Rel *) ((char *) r + r_size)) @@ -2178,7 +2268,7 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, offset = grub_target_to_host (r->r_offset); info = grub_target_to_host (r->r_info); - addr = section_address + offset; + addr = layout->vaddr_diff + offset; translate_relocation (&ctx, addr, info, image_target); } @@ -2262,6 +2352,9 @@ SUFFIX (is_kept_reloc_section) (Elf_Shdr *s, const struct grub_install_image_tar int r = 0; const char *name = smd->strtab + grub_host_to_target32 (s->sh_name); + if (strncmp (name, ".rela.dyn", 9) == 0 || strncmp (name, ".rel.dyn", 8) == 0) + return 1; + if (!strncmp (name, ".rela.", 6)) name += 5; else if (!strncmp (name, ".rel.", 5)) @@ -2299,31 +2392,6 @@ SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, const struct grub_install_i return 1; } -static Elf_Addr -SUFFIX (put_section) (Elf_Shdr *s, int i, - Elf_Addr current_address, - struct section_metadata *smd, - const struct grub_install_image_target_desc *image_target) -{ - Elf_Word align = grub_host_to_target_addr (s->sh_addralign); - const char *name = smd->strtab + grub_host_to_target32 (s->sh_name); - - if (align) - current_address = ALIGN_UP (current_address + image_target->vaddr_offset, - align) - - image_target->vaddr_offset; - - grub_util_info ("locating the section %s at 0x%" - GRUB_HOST_PRIxLONG_LONG, - name, (unsigned long long) current_address); - if (!is_relocatable (image_target)) - current_address = grub_host_to_target_addr (s->sh_addr) - - image_target->link_addr; - smd->addrs[i] = current_address; - current_address += grub_host_to_target_addr (s->sh_size); - return current_address; -} - /* * Locate section addresses by merging code sections and data sections * into .text and .data, respectively. @@ -2335,97 +2403,105 @@ SUFFIX (locate_sections) (Elf_Ehdr *e, const char *kernel_path, const struct grub_install_image_target_desc *image_target) { int i; - Elf_Shdr *s; + Elf_Phdr *p; layout->align = 1; + layout->kernel_size = 0; + + Elf_Addr min_vaddr = ~(Elf_Addr)0; + Elf_Addr max_vaddr = 0; + Elf_Addr max_filled_vaddr = 0; + Elf_Addr max_align = 1; + Elf_Addr max_execvaddr = 0; + Elf_Addr min_wvaddr = ~(Elf_Addr)0; + /* Page-aligning simplifies relocation handling. */ if (image_target->elf_target == EM_AARCH64) - layout->align = 4096; + max_align = 4096; - layout->kernel_size = 0; + for (i = 0, p = smd->phdrs; + i < smd->num_phdrs; + i++, p = (Elf_Phdr *) ((char *) p + smd->phdr_entsize)) + { + if (grub_target_to_host32 (p->p_type) == PT_LOAD) + { + if (grub_target_to_host (p->p_vaddr) < min_vaddr) + min_vaddr = grub_target_to_host (p->p_vaddr); + if (grub_target_to_host (p->p_vaddr) + grub_target_to_host (p->p_memsz) > max_vaddr) + max_vaddr = grub_target_to_host (p->p_vaddr) + grub_target_to_host (p->p_memsz); + if (grub_target_to_host (p->p_vaddr) + grub_target_to_host (p->p_filesz) > max_filled_vaddr) + max_filled_vaddr = grub_target_to_host (p->p_vaddr) + grub_target_to_host (p->p_filesz); + if ((grub_target_to_host32 (p->p_flags) & PF_X) && grub_target_to_host (p->p_vaddr) + grub_target_to_host (p->p_memsz) > max_execvaddr) + max_execvaddr = grub_target_to_host (p->p_vaddr) + grub_target_to_host (p->p_memsz); + if ((grub_target_to_host32 (p->p_flags) & PF_W) && grub_target_to_host (p->p_vaddr) < min_wvaddr) + min_wvaddr = grub_target_to_host (p->p_vaddr); + if (grub_target_to_host (p->p_align) > max_align) + max_align = grub_target_to_host (p->p_align); + } + if (grub_target_to_host32 (p->p_type) == PT_DYNAMIC) + { + Elf64_Dyn *dyn = (Elf64_Dyn *) ((char *) e + grub_target_to_host (p->p_offset)); + grub_size_t sz = grub_target_to_host (p->p_filesz); + unsigned j; + for (j = 0; j < sz / sizeof(dyn[0]); j++) + switch (dyn[j].d_tag) + { + case DT_PLTGOT: + layout->dyn_pltoff = dyn[j].d_un.d_ptr; + break; + case DT_NULL: + goto end_dynamic; + } + end_dynamic:; + } + } - for (i = 0, s = smd->sections; - i < smd->num_sections; - i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) - if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC) - && grub_host_to_target32 (s->sh_addralign) > layout->align) - layout->align = grub_host_to_target32 (s->sh_addralign); + if (image_target->id == IMAGE_EFI) + { + if (ALIGN_DOWN(min_wvaddr, 4096) < ALIGN_UP(max_execvaddr, 4096)) + grub_util_error("writable and executable overlap"); + max_execvaddr = ALIGN_UP(max_execvaddr, 4096); + } - /* .text */ - for (i = 0, s = smd->sections; - i < smd->num_sections; - i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) - if (SUFFIX (is_text_section) (s, image_target)) - { - layout->kernel_size = SUFFIX (put_section) (s, i, layout->kernel_size, - smd, image_target); - if (!is_relocatable (image_target) && - grub_host_to_target_addr (s->sh_addr) != image_target->link_addr) - { - char *msg - = grub_xasprintf (_("`%s' is miscompiled: its start address is 0x%llx" - " instead of 0x%llx: ld.gold bug?"), - kernel_path, - (unsigned long long) grub_host_to_target_addr (s->sh_addr), - (unsigned long long) image_target->link_addr); - grub_util_error ("%s", msg); - } - } + if (!is_relocatable (image_target) && + min_vaddr != image_target->link_addr) + { + char *msg + = grub_xasprintf (_("`%s' is miscompiled: its start address is 0x%llx" + " instead of 0x%llx: ld.gold bug?"), + kernel_path, + (unsigned long long) min_vaddr, + (unsigned long long) image_target->link_addr); + grub_util_error ("%s", msg); + } + + layout->vaddr_diff = image_target->vaddr_offset; + layout->off_diff = -(grub_int64_t)min_vaddr; + layout->kernel_size = max_filled_vaddr - min_vaddr; + layout->bss_size = max_vaddr - max_filled_vaddr; + layout->exec_size = max_execvaddr - min_vaddr; + layout->align = max_align; + + if (image_target->id == IMAGE_EFI) + { + layout->kernel_size += layout->bss_size; + layout->bss_size = 0; + } #ifdef MKIMAGE_ELF32 if (image_target->elf_target == EM_ARM) { grub_size_t tramp; - layout->kernel_size = ALIGN_UP (layout->kernel_size, 16); - tramp = arm_get_trampoline_size (e, smd->sections, smd->section_entsize, smd->num_sections, image_target); - - layout->tramp_off = layout->kernel_size; - layout->kernel_size += ALIGN_UP (tramp, 16); + if (tramp != 0) + grub_util_error("inserting trampolines is no longer supported"); } #endif - layout->kernel_size = ALIGN_UP (layout->kernel_size + image_target->vaddr_offset, - image_target->section_align) - - image_target->vaddr_offset; - layout->exec_size = layout->kernel_size; - - /* .data */ - for (i = 0, s = smd->sections; - i < smd->num_sections; - i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) - if (SUFFIX (is_data_section) (s, image_target)) - layout->kernel_size = SUFFIX (put_section) (s, i, layout->kernel_size, smd, - image_target); - - layout->bss_start = layout->kernel_size; - layout->end = layout->kernel_size; - - /* .bss */ - for (i = 0, s = smd->sections; - i < smd->num_sections; - i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) - { - if (SUFFIX (is_bss_section) (s, image_target)) - layout->end = SUFFIX (put_section) (s, i, layout->end, smd, image_target); - - /* - * This must to be in the last time this function passes through the loop. - */ - smd->vaddrs[i] = smd->addrs[i] + image_target->vaddr_offset; - } - - layout->end = ALIGN_UP (layout->end + image_target->vaddr_offset, + layout->end = ALIGN_UP (layout->kernel_size + image_target->vaddr_offset, image_target->section_align) - image_target->vaddr_offset; - /* Explicitly initialize BSS - when producing PE32 to avoid a bug in EFI implementations. - Platforms other than EFI and U-boot shouldn't have .bss in - their binaries as we build with -Wl,-Ttext. - */ - if (image_target->id == IMAGE_EFI || !is_relocatable (image_target)) - layout->kernel_size = layout->end; } char * @@ -2435,11 +2511,12 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, const struct grub_install_image_target_desc *image_target) { char *kernel_img, *out_img; - struct section_metadata smd = { 0, 0, 0, 0, 0, 0, 0 }; + struct section_metadata smd = { 0, 0, 0, 0, 0, 0, 0, 0 }; Elf_Ehdr *e; int i; Elf_Shdr *s; - Elf_Off section_offset; + Elf_Phdr *p; + Elf_Off section_offset, phdr_offset; grub_size_t kernel_size; grub_memset (layout, 0, sizeof (*layout)); @@ -2464,71 +2541,23 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, smd.sections = (Elf_Shdr *) (kernel_img + section_offset); + phdr_offset = grub_target_to_host (e->e_phoff); + smd.phdr_entsize = grub_target_to_host16 (e->e_phentsize); + smd.num_phdrs = grub_target_to_host16 (e->e_phnum); + + if (kernel_size < phdr_offset + + (grub_uint32_t) smd.phdr_entsize * smd.num_phdrs) + grub_util_error (_("premature end of file %s"), kernel_path); + + smd.phdrs = (Elf_Phdr *) (kernel_img + phdr_offset); + /* Relocate sections then symbols in the virtual address space. */ s = (Elf_Shdr *) ((char *) smd.sections + grub_host_to_target16 (e->e_shstrndx) * smd.section_entsize); smd.strtab = (char *) e + grub_host_to_target_addr (s->sh_offset); - smd.addrs = xcalloc (smd.num_sections, sizeof (*smd.addrs)); - smd.vaddrs = xcalloc (smd.num_sections, sizeof (*smd.vaddrs)); - SUFFIX (locate_sections) (e, kernel_path, &smd, layout, image_target); - if (!is_relocatable (image_target)) - { - Elf_Addr current_address = layout->kernel_size; - Elf_Addr bss_start = layout->kernel_size; - bool is_first = true; - - for (i = 0, s = smd.sections; - i < smd.num_sections; - i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize)) - if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) - { - Elf_Word sec_align = grub_host_to_target_addr (s->sh_addralign); - const char *name = smd.strtab + grub_host_to_target32 (s->sh_name); - - if (sec_align) - current_address = ALIGN_UP (current_address - + image_target->vaddr_offset, - sec_align) - - image_target->vaddr_offset; - - grub_util_info ("locating the section %s at 0x%" - GRUB_HOST_PRIxLONG_LONG, - name, (unsigned long long) current_address); - if (!is_relocatable (image_target)) - current_address = grub_host_to_target_addr (s->sh_addr) - - image_target->link_addr; - - if (is_first == true) - { - bss_start = current_address; - is_first = false; - } - - smd.vaddrs[i] = current_address - + image_target->vaddr_offset; - current_address += grub_host_to_target_addr (s->sh_size); - } - current_address = ALIGN_UP (current_address + image_target->vaddr_offset, - image_target->section_align) - - image_target->vaddr_offset; - - if (image_target->id == IMAGE_YEELOONG_FLASH - || image_target->id == IMAGE_FULOONG2F_FLASH - || image_target->id == IMAGE_LOONGSON_ELF - || image_target->id == IMAGE_QEMU_MIPS_FLASH - || image_target->id == IMAGE_MIPS_ARC) - { - layout->kernel_size = bss_start; - } - - layout->bss_size = current_address - layout->kernel_size; - } - else - layout->bss_size = 0; - if (image_target->id == IMAGE_SPARC64_AOUT || image_target->id == IMAGE_SPARC64_RAW || image_target->id == IMAGE_UBOOT @@ -2542,7 +2571,7 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, for (i = 0, s = smd.sections; i < smd.num_sections; i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize)) - if (s->sh_type == grub_host_to_target32 (SHT_SYMTAB)) + if (s->sh_type == grub_host_to_target32 (SHT_DYNSYM)) { smd.symtab = s; break; @@ -2600,16 +2629,32 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, layout->start_address = SUFFIX (relocate_symbols) (e, &smd, (char *) out_img + layout->ia64jmp_off, layout->ia64jmp_off + image_target->vaddr_offset, - layout->bss_start, layout->end, image_target); + layout, image_target); if (layout->start_address == (Elf_Addr) -1) grub_util_error ("start symbol is not defined"); + make_reloc_section (e, layout, &smd, image_target); + } + + for (i = 0, p = smd.phdrs; + i < smd.num_phdrs; + i++, p = (Elf_Phdr *) ((char *) p + smd.phdr_entsize)) + { + if (grub_target_to_host32 (p->p_type) != PT_LOAD) + continue; + memcpy (out_img + grub_target_to_host (p->p_vaddr) + layout->off_diff, + kernel_img + grub_target_to_host (p->p_offset), grub_target_to_host (p->p_filesz)); + if (image_target->id == IMAGE_EFI) + memset (out_img + grub_target_to_host (p->p_vaddr) + layout->off_diff + grub_target_to_host (p->p_filesz), + 0, grub_target_to_host (p->p_memsz) - grub_target_to_host (p->p_filesz)); + } + + if (is_relocatable (image_target)) + { /* Resolve addrs in the virtual address space. */ - SUFFIX (relocate_addrs) (e, &smd, out_img, layout->tramp_off, - layout->got_off, image_target); + SUFFIX (relocate_addrs) (e, &smd, out_img, layout, image_target); - make_reloc_section (e, layout, &smd, image_target); if (image_target->id != IMAGE_EFI) { out_img = xrealloc (out_img, layout->kernel_size + total_module_size @@ -2621,25 +2666,7 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path, } } - for (i = 0, s = smd.sections; - i < smd.num_sections; - i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize)) - if (SUFFIX (is_kept_section) (s, image_target)) - { - if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) - memset (out_img + smd.addrs[i], 0, - grub_host_to_target_addr (s->sh_size)); - else - memcpy (out_img + smd.addrs[i], - kernel_img + grub_host_to_target_addr (s->sh_offset), - grub_host_to_target_addr (s->sh_size)); - } free (kernel_img); - free (smd.vaddrs); - smd.vaddrs = NULL; - free (smd.addrs); - smd.addrs = NULL; - return out_img; } -- 2.49.0 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel