From: Vladimir Serbinenko <phcoder@gmail.com>
To: grub-devel@gnu.org
Cc: Vladimir Serbinenko <phcoder@gmail.com>
Subject: [PATCH 3/3] Use ET_DYN images and PHDRs for creating relocatable images
Date: Tue, 8 Apr 2025 15:16:25 +0000 [thread overview]
Message-ID: <20250408151657.3303174-4-phcoder@gmail.com> (raw)
In-Reply-To: <20250408151657.3303174-1-phcoder@gmail.com>
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 <phcoder@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
prev parent reply other threads:[~2025-04-08 15:18 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-08 15:16 [PATCH 0/3] Use -shared compilation instead of -Wl,-r Vladimir Serbinenko
2025-04-08 15:16 ` [PATCH 1/3] Use ET_DYN instead of ET_REL modules Vladimir Serbinenko
2025-04-23 22:36 ` Glenn Washburn
2025-04-08 15:16 ` [PATCH 2/3] loongarch64: Use la.pcrel instead of la Vladimir Serbinenko
2025-04-08 15:16 ` Vladimir Serbinenko [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250408151657.3303174-4-phcoder@gmail.com \
--to=phcoder@gmail.com \
--cc=grub-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.