From d7cad9ca0817f1a070d1f99e66c759e2d0e6338f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=80=84=E5=87=AF=E8=90=8C00355110?= Date: Wed, 11 Feb 2026 15:45:48 +0800 Subject: [PATCH 1/3] Fix grub2 relocation overflow error when booting on numa configurations --- ...check-for-mcmodel-large-until-PIC-PI.patch | 83 + ...Use-ET_DYN-instead-of-ET_REL-modules.patch | 1759 +++++++++++++++++ ...ongarch64-Use-la.pcrel-instead-of-la.patch | 31 + ...s-and-PHDRs-for-creating-relocatable.patch | 985 +++++++++ grub.macros | 14 +- grub.patches | 5 + grub2.spec | 5 +- 7 files changed, 2880 insertions(+), 2 deletions(-) create mode 100644 1095-configure-Defer-check-for-mcmodel-large-until-PIC-PI.patch create mode 100644 1096-Use-ET_DYN-instead-of-ET_REL-modules.patch create mode 100644 1097-loongarch64-Use-la.pcrel-instead-of-la.patch create mode 100644 1098-Use-ET_DYN-images-and-PHDRs-for-creating-relocatable.patch diff --git a/1095-configure-Defer-check-for-mcmodel-large-until-PIC-PI.patch b/1095-configure-Defer-check-for-mcmodel-large-until-PIC-PI.patch new file mode 100644 index 0000000..60fae7f --- /dev/null +++ b/1095-configure-Defer-check-for-mcmodel-large-until-PIC-PI.patch @@ -0,0 +1,83 @@ +From 218cc48cfca631a76e155a2b18c2356c1ec28e4d Mon Sep 17 00:00:00 2001 +From: Fedora Ninjas +Date: Tue, 3 Feb 2026 20:55:50 +0800 +Subject: [PATCH 4/4] configure: Defer check for -mcmodel=large until PIC/PIE + checks are done + +On RISC-V, large code model is only compatible with position-depedent +code. However, the configure script checks availability of -mcmodel=large +before determining whether PIC/PIE is enabled, and disable them. + +This is problematic with toolchains that enable PIE by default, where +check for -mcmodel=large will always fail with, + +cc1: sorry, unimplemented: code model 'large' with '-fPIC' + +and -mcmodel=medany will be silently used instead, causing relocation +failures at runtime with some memory layouts since -mcmodel=medany +requires all data and code to stay within a contiguous 4 GiB range. + +Let's defer the check for -mcmodel=large until PIC/PIE is ensured disabled. + +Fixes: f1957dc8a334 (RISC-V: Add to build system) + +Reported-by: Han Gao +Signed-off-by: Yao Zi +Reviewed-by: Daniel Kiper +--- + configure.ac | 32 +++++++++++++++----------------- + 1 file changed, 15 insertions(+), 17 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 09f3a42..9e562fe 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1334,23 +1334,6 @@ AC_SUBST(TARGET_LDFLAGS_OLDMAGIC) + + LDFLAGS="$TARGET_LDFLAGS" + +-if test "$target_cpu" = x86_64 || test "$target_cpu" = sparc64 ; then +- # Use large model to support 4G memory +- AC_CACHE_CHECK([whether option -mcmodel=large works], grub_cv_cc_mcmodel, [ +- CFLAGS="$TARGET_CFLAGS -mcmodel=large" +- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], +- [grub_cv_cc_mcmodel=yes], +- [grub_cv_cc_mcmodel=no]) +- ]) +- if test "x$grub_cv_cc_mcmodel" = xyes; then +- TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=large" +- elif test "$target_cpu" = sparc64; then +- TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=medany" +- fi +-elif test "$target_cpu" = riscv64 ; then +- TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=medany" +-fi +- + if test "$target_cpu"-"$platform" = x86_64-efi; then + # EFI writes to stack below %rsp, we must not use the red zone + AC_CACHE_CHECK([whether option -mno-red-zone works], grub_cv_cc_no_red_zone, [ +@@ -1489,6 +1472,21 @@ esac] + + CFLAGS="$TARGET_CFLAGS" + ++if test "$target_cpu" = x86_64 || test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64 ; then ++ # Use large model to support 4G memory ++ AC_CACHE_CHECK([whether option -mcmodel=large works], grub_cv_cc_mcmodel, [ ++ CFLAGS="$TARGET_CFLAGS -mcmodel=large" ++ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], ++ [grub_cv_cc_mcmodel=yes], ++ [grub_cv_cc_mcmodel=no]) ++ ]) ++ if test "x$grub_cv_cc_mcmodel" = xyes; then ++ TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=large" ++ elif test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64; then ++ TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=medany" ++ fi ++fi ++ + # Stack smashing protector. + grub_CHECK_STACK_PROTECTOR + AC_ARG_ENABLE([stack-protector], +-- +2.47.3 + diff --git a/1096-Use-ET_DYN-instead-of-ET_REL-modules.patch b/1096-Use-ET_DYN-instead-of-ET_REL-modules.patch new file mode 100644 index 0000000..788d9f1 --- /dev/null +++ b/1096-Use-ET_DYN-instead-of-ET_REL-modules.patch @@ -0,0 +1,1759 @@ +From 5d0c20880692327802341fce8281f38bad038ca1 Mon Sep 17 00:00:00 2001 +From: Fedora Ninjas +Date: Fri, 30 Jan 2026 18:00:27 +0800 +Subject: [PATCH 1/4] Use ET_DYN instead of ET_REL modules + +ET_DYN also known as .so files are actually meant to be loaded dynamically. +Most of the work of linking is done by normal linker and we need to do +only simple relocation by offset. This significantly simplifies our +dynamic loading. Moreover the tools are meant to produce .so files and so +it's easier to get them to produce correct output. Also it reduce the +core size on i386-pc by 44 bytes on config biosdisk+part_msdos+ext2 + +This required to use -fPIC on mips as otherwise linker chokes on relocations +incompatible with -shared + +This was originally meant for Rust as rustc produces .so output +as a possibility but it simplifies the code, so it's useful independently of +Rust + +Signed-off-by: Vladimir Serbinenko +--- + conf/Makefile.common | 11 +- + conf/i386-modules.sc | 35 ++++ + configure.ac | 39 +++-- + grub-core/genmod.sh.in | 20 ++- + grub-core/genmoddep.awk | 2 +- + grub-core/kern/arm/dl.c | 19 ++- + grub-core/kern/arm64/dl.c | 22 ++- + grub-core/kern/backtrace.c | 2 + + grub-core/kern/dl.c | 290 +++++++++++++++----------------- + grub-core/kern/emu/full.c | 4 +- + grub-core/kern/i386/dl.c | 19 ++- + grub-core/kern/ia64/dl.c | 48 ++++-- + grub-core/kern/loongarch64/dl.c | 20 ++- + grub-core/kern/mips/dl.c | 76 ++++++++- + grub-core/kern/powerpc/dl.c | 15 +- + grub-core/kern/riscv/dl.c | 23 ++- + grub-core/kern/sparc64/dl.c | 15 +- + include/grub/dl.h | 47 +++--- + include/grub/elf.h | 4 + + util/grub-mkimagexx.c | 3 +- + util/grub-module-verifier.c | 27 ++- + util/grub-module-verifierXX.c | 55 ++++-- + 22 files changed, 505 insertions(+), 291 deletions(-) + create mode 100644 conf/i386-modules.sc + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 3c0ed01..876802d 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -51,7 +51,16 @@ endif + endif + + CFLAGS_MODULE = $(TARGET_CFLAGS) $(CFLAGS_PLATFORM) -ffreestanding +-LDFLAGS_MODULE = $(TARGET_LDFLAGS) $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d ++if COND_emu ++LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib -Wl,-r,-d ++else ++if COND_mips ++LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -shared ++else ++LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -shared -Wl,-Ttext-segment=0 -Wl,-Bstatic -Wl,-T${srcdir}/../conf/i386-modules.sc ++endif ++endif ++ + CPPFLAGS_MODULE = $(TARGET_CPPFLAGS) $(CPPFLAGS_DEFAULT) $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) + CCASFLAGS_MODULE = $(TARGET_CCASFLAGS) $(CCASFLAGS_DEFAULT) $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) + +diff --git a/conf/i386-modules.sc b/conf/i386-modules.sc +new file mode 100644 +index 0000000..aab26e4 +--- /dev/null ++++ b/conf/i386-modules.sc +@@ -0,0 +1,35 @@ ++SECTIONS ++{ ++ .text : ++ { ++ *(.text) ++ } ++ .data : ++ { ++ *(.data) ++ *(.rdata) ++ *(.pdata) ++ } ++ .bss : ++ { ++ *(.bss) ++ *(COMMON) ++ } ++ .edata : ++ { ++ *(.edata) ++ } ++ .stab : ++ { ++ *(.stab) ++ } ++ .stabstr : ++ { ++ *(.stabstr) ++ } ++ ++ /DISCARD/ : ++ { ++ *(.dynamic) ++ } ++} +diff --git a/configure.ac b/configure.ac +index cf5c612..599f04d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -918,16 +918,8 @@ if ( test "x$target_cpu" = xi386 || test "x$target_cpu" = xx86_64 ); then + fi + + if test "x$target_cpu" = xloongarch64; then +- AC_CACHE_CHECK([whether _mno_explicit_relocs works], [grub_cv_cc_mno_explicit_relocs], [ +- CFLAGS="$TARGET_CFLAGS -mno-explicit-relocs -Werror" +- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], +- [grub_cv_cc_mno_explicit_relocs=yes], +- [grub_cv_cc_mno_explicit_relocs=no]) +- ]) +- if test "x$grub_cv_cc_mno_explicit_relocs" = xyes; then +- TARGET_CFLAGS="$TARGET_CFLAGS -mno-explicit-relocs -fno-plt" +- TARGET_CCASFLAGS="$TARGET_CCASFLAGS -mno-explicit-relocs -fno-plt" +- fi ++ 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 +@@ -1269,6 +1261,10 @@ else + TARGET_IMG_CFLAGS= + fi + ++if test x${platform} = xefi || test x${platform} = xemu; then ++ TARGET_LDFLAGS_OLDMAGIC= ++fi ++ + CFLAGS="$TARGET_CFLAGS" + + AC_ARG_ENABLE([efiemu], +@@ -1471,18 +1467,27 @@ grub_CHECK_PIC + [# On most platforms we don't want PIC as it only makes relocations harder + # and code less efficient. On mips we want to have one got table per module + # and reload $gp in every function. +-# GCC implements it using symbol __gnu_local_gp in non-PIC as well. +-# However with clang we need PIC for this reloading to happen. + # With arm64 we need relocations that are in some way representable in + # PE as we need to support arm64-efi. Without -fPIC clang generates + # movk's which aren't representable. + # Since default varies across dictributions use either -fPIC or -fno-PIC + # explicitly. +-if ( test x$target_cpu = xmips || test x$target_cpu = xmipsel || test x$target_cpu = xarm64 ) && test "x$grub_cv_cc_target_clang" = xyes ; then +- TARGET_CFLAGS="$TARGET_CFLAGS -fPIC" +-elif [ x"$pic_possible" = xyes ]; then +- TARGET_CFLAGS="$TARGET_CFLAGS -fno-PIC" +-fi] ++case $target_cpu-$platform in ++ mips-* | mipsel-*) ++ TARGET_CFLAGS="$TARGET_CFLAGS -fPIC -mabicalls" ++ ;; ++ arm64-*) ++ if test "x$grub_cv_cc_target_clang" = xyes ; then ++ TARGET_CFLAGS="$TARGET_CFLAGS -fPIC" ++ fi ++ ;; ++ riscv32-* | ia64-*) ++ TARGET_CFLAGS="$TARGET_CFLAGS -fPIC" ++ ;; ++ *) ++ TARGET_CFLAGS="$TARGET_CFLAGS -fno-PIC" ++ ;; ++esac] + + CFLAGS="$TARGET_CFLAGS" + +diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in +index 337753c..5116787 100644 +--- a/grub-core/genmod.sh.in ++++ b/grub-core/genmod.sh.in +@@ -23,6 +23,7 @@ infile=$2 + outfile=$4 + + tmpfile=${outfile}.tmp ++tmpfile2=${outfile}.tmp2 + modname=`echo $infile | sed -e 's@\.module.*$@@'` + + if ! grep ^$modname: $moddep >/dev/null; then +@@ -33,7 +34,7 @@ fi + deps=`grep ^$modname: $moddep | sed s@^.*:@@` + + # remove old files if any +-rm -f $tmpfile $outfile ++rm -f $tmpfile $tmpfile2 $outfile + + if test x@TARGET_APPLE_LINKER@ != x1; then + # stripout .modname and .moddeps sections from input module +@@ -53,10 +54,8 @@ if test x@TARGET_APPLE_LINKER@ != x1; then + fi + rm -f $t1 $t2 + +- if test x@platform@ != xemu; then +- @TARGET_STRIP@ --strip-unneeded \ +- -K grub_mod_init -K grub_mod_fini \ +- -K _grub_mod_init -K _grub_mod_fini \ ++ if test x@platform@ != xemu; then ++ STRIP_FLAGS="--strip-unneeded \ + -R .note.GNU-stack \ + -R .note.gnu.gold-version \ + -R .note.gnu.property \ +@@ -65,13 +64,20 @@ if test x@TARGET_APPLE_LINKER@ != x1; then + -R .rel.gnu.build.attributes \ + -R .rela.gnu.build.attributes \ + -R .eh_frame -R .rela.eh_frame -R .rel.eh_frame \ +- -R .note -R .comment -R .ARM.exidx $tmpfile || exit 1 ++ -R .note -R .comment -R .gnu.hash -R .ARM.exidx \ ++ -R .symtab -R .strtab -R .shstrtab" ++ if test x@target_cpu@ != xmips && test x@target_cpu@ != xmipsel && test x@target_cpu@ != xia64; then ++ STRIP_FLAGS="$STRIP_FLAGS -R .dynamic" + fi ++ @TARGET_STRIP@ $STRIP_FLAGS -s $tmpfile || exit 1 ++ else ++ @TARGET_CC@ -Wl,--export-dynamic -o $tmpfile2 -shared -nostdlib $tmpfile ++ cp $tmpfile2 $tmpfile ++ fi + if ! test -z "${TARGET_OBJ2ELF}"; then + "${TARGET_OBJ2ELF}" $tmpfile || exit 1 + fi + else +- tmpfile2=${outfile}.tmp2 + t1=${outfile}.t1.c + t2=${outfile}.t2.c + +diff --git a/grub-core/genmoddep.awk b/grub-core/genmoddep.awk +index cc987a5..c01c036 100644 +--- a/grub-core/genmoddep.awk ++++ b/grub-core/genmoddep.awk +@@ -18,7 +18,7 @@ BEGIN { + + { + if ($1 == "defined") { +- if ($3 !~ /^\.refptr\./ && $3 in symtab) { ++ if ($3 !~ /^\.refptr\./ && $3 != "grub_mod_init" && $3 != "grub_mod_fini" && $3 != "__bss_start" && $3 != "_fdata" && $3 != "_ftext" && $3 != "_fbss" && $3 != "_edata" && $3 != "_end" && $3 != "__aeabi_uidivmod" && $3 != "__aeabi_idivmod" && $3 in symtab) { + printf "%s in %s is duplicated in %s\n", $3, $2, symtab[$3] >"/dev/stderr"; + error++; + } +diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c +index 9260737..baf9a9b 100644 +--- a/grub-core/kern/arm/dl.c ++++ b/grub-core/kern/arm/dl.c +@@ -108,8 +108,7 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + * Runtime dynamic linker with helper functions. * + *************************************************/ + grub_err_t +-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, +- Elf_Shdr *s, grub_dl_segment_t seg) ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, Elf_Shdr *s) + { + Elf_Rel *rel, *max; + +@@ -122,10 +121,11 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + grub_err_t retval; + Elf_Sym *sym; + +- if (seg->size < rel->r_offset) ++ if (mod->min_addr + mod->sz <= rel->r_offset || mod->min_addr > rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, +- "reloc offset is out of the segment"); +- target = (void *) ((char *) seg->addr + rel->r_offset); ++ "reloc offset is out of the segment: %x not in [%x..%x]", ++ rel->r_offset, mod->min_addr, mod->min_addr + mod->sz); ++ target = (void *) ((char *) mod->base + rel->r_offset - mod->min_addr); + sym = (Elf_Sym *) ((char *) mod->symtab + + mod->symsize * ELF_R_SYM (rel->r_info)); + +@@ -134,6 +134,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + switch (ELF_R_TYPE (rel->r_info)) + { + case R_ARM_ABS32: ++ case R_ARM_GLOB_DAT: + { + /* Data will be naturally aligned */ + retval = grub_arm_reloc_abs32 (target, sym_addr); +@@ -141,6 +142,14 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + return retval; + } + break; ++ case R_ARM_JUMP_SLOT: ++ *target = sym_addr; ++ break; ++ ++ case R_ARM_RELATIVE: ++ *target += (grub_addr_t) mod->base - mod->min_addr; ++ break; ++ + case R_ARM_CALL: + case R_ARM_JUMP24: + { +diff --git a/grub-core/kern/arm64/dl.c b/grub-core/kern/arm64/dl.c +index 95c6d5b..151b075 100644 +--- a/grub-core/kern/arm64/dl.c ++++ b/grub-core/kern/arm64/dl.c +@@ -52,8 +52,7 @@ grub_arch_dl_check_header (void *ehdr) + * Unified function for both REL and RELA + */ + grub_err_t +-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, +- Elf_Shdr *s, grub_dl_segment_t seg) ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, Elf_Shdr *s) + { + Elf_Rel *rel, *max; + unsigned unmatched_adr_got_page = 0; +@@ -67,9 +66,10 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + void *place; + grub_uint64_t sym_addr; + +- if (rel->r_offset >= seg->size) ++ if (mod->min_addr + mod->sz <= rel->r_offset || mod->min_addr > rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, +- "reloc offset is out of the segment"); ++ "reloc offset is out of the segment: %lx not in [%lx..%lx]", ++ rel->r_offset, mod->min_addr, mod->min_addr + mod->sz); + + sym = (Elf_Sym *) ((char *) mod->symtab + + mod->symsize * ELF_R_SYM (rel->r_info)); +@@ -78,11 +78,13 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + if (s->sh_type == SHT_RELA) + sym_addr += ((Elf_Rela *) rel)->r_addend; + +- place = (void *) ((grub_addr_t) seg->addr + rel->r_offset); ++ place = (void *) ((char *) mod->base + rel->r_offset - mod->min_addr); + + switch (ELF_R_TYPE (rel->r_info)) + { + case R_AARCH64_ABS64: ++ case R_AARCH64_JUMP_SLOT: ++ case R_AARCH64_GLOB_DAT: + { + grub_uint64_t *abs_place = place; + +@@ -125,7 +127,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + 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; ++ (Elf64_Xword) (grub_addr_t) place; + 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", +@@ -155,7 +157,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + && ((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_arm64_set_abs_lo12_ldst64 ((void *) ((char *) mod->base + rel2->r_offset - mod->min_addr), + (grub_uint64_t)gp); + break; + } +@@ -182,6 +184,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + } + break; + ++ case R_AARCH64_RELATIVE: ++ *(grub_uint64_t *)place = (grub_addr_t) mod->base - mod->min_addr; ++ if (s->sh_type == SHT_RELA) ++ *(grub_uint64_t *)place += ((Elf_Rela *) rel)->r_addend; ++ break; ++ + default: + { + char rel_info[17]; /* log16(2^64) = 16, plus NUL. */ +diff --git a/grub-core/kern/backtrace.c b/grub-core/kern/backtrace.c +index 4a82e86..f3459c8 100644 +--- a/grub-core/kern/backtrace.c ++++ b/grub-core/kern/backtrace.c +@@ -30,6 +30,7 @@ static void + grub_backtrace_print_address_default (void *addr) + { + #ifndef GRUB_UTIL ++#if 0 + grub_dl_t mod; + void *start_addr; + +@@ -54,6 +55,7 @@ grub_backtrace_print_address_default (void *addr) + (grub_size_t) + ((grub_uint8_t *)addr - (grub_uint8_t *)start_addr)); + else ++#endif + #endif + grub_printf ("%p", addr); + } +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 9e7a098..8f61838 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -35,6 +35,12 @@ + #include + #include + ++#ifdef GRUB_MACHINE_EFI ++#define DL_ALIGN GRUB_EFI_PAGE_SIZE ++#else ++#define DL_ALIGN 1 ++#endif ++ + /* Platforms where modules are in a readonly area of memory. */ + #if defined(GRUB_MACHINE_QEMU) + #define GRUB_MODULES_MACHINE_READONLY +@@ -232,19 +238,6 @@ grub_dl_unregister_symbols (grub_dl_t mod) + } + } + +-/* Return the address of a section whose index is N. */ +-static void * +-grub_dl_get_section_addr (grub_dl_t mod, unsigned n) +-{ +- grub_dl_segment_t seg; +- +- for (seg = mod->segment; seg; seg = seg->next) +- if (seg->section == n) +- return seg->addr; +- +- return 0; +-} +- + /* Check if EHDR is a valid ELF header. */ + static grub_err_t + grub_dl_check_header (void *ehdr, grub_size_t size) +@@ -277,38 +270,33 @@ static grub_err_t + grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + { + unsigned i; +- const Elf_Shdr *s; +- grub_size_t tsize = 0, talign = 1, arch_addralign = 1; ++ const Elf_Phdr *p; ++ grub_size_t talign = DL_ALIGN; + #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \ + !defined (__loongarch__) + grub_size_t tramp; + grub_size_t tramp_align; + grub_size_t got; + grub_size_t got_align; ++ grub_addr_t tramp_addr = 0; ++ grub_addr_t got_addr = 0; + grub_err_t err; + #endif +- char *ptr; ++ grub_addr_t min_addr = ~(grub_addr_t)0; ++ grub_addr_t max_addr = 0; + + grub_dprintf ("modules", "loading segments for \"%s\"\n", mod->name); + +- arch_addralign = grub_arch_dl_min_alignment (); +- +- for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); +- i < e->e_shnum; +- i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) ++ for (i = 0, p = (const Elf_Phdr *)((const char *) e + e->e_phoff); ++ i < e->e_phnum; ++ i++, p = (const Elf_Phdr *)((const char *) p + e->e_phentsize)) + { +- grub_size_t sh_addralign; +- grub_size_t sh_size; +- +- if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC)) ++ if (p->p_type != PT_LOAD) + continue; + +- sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign); +- sh_size = ALIGN_UP(s->sh_size, sh_addralign); +- +- tsize = ALIGN_UP (tsize, sh_addralign) + sh_size; +- if (talign < sh_addralign) +- talign = sh_addralign; ++ min_addr = grub_min(min_addr, p->p_vaddr); ++ max_addr = grub_max(max_addr, p->p_vaddr + p->p_memsz); ++ talign = grub_max (talign, p->p_align); + } + + #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \ +@@ -316,86 +304,47 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got); + if (err) + return err; +- tramp_align = GRUB_ARCH_DL_TRAMP_ALIGN; +- if (tramp_align < arch_addralign) +- tramp_align = arch_addralign; +- tsize += ALIGN_UP (tramp, tramp_align); +- if (talign < tramp_align) +- talign = tramp_align; +- got_align = GRUB_ARCH_DL_GOT_ALIGN; +- if (got_align < arch_addralign) +- got_align = arch_addralign; +- tsize += ALIGN_UP (got, got_align); +- if (talign < got_align) +- talign = got_align; ++ tramp_align = grub_max (GRUB_ARCH_DL_TRAMP_ALIGN, DL_ALIGN); ++ tramp_addr = ALIGN_UP (max_addr, tramp_align); ++ max_addr = ALIGN_UP (tramp_addr+tramp, tramp_align); ++ talign = grub_max (talign, tramp_align); ++ got_align = grub_max (GRUB_ARCH_DL_GOT_ALIGN, DL_ALIGN); ++ got_addr = ALIGN_UP(max_addr, got_align); ++ max_addr = ALIGN_UP(got_addr + got, got_align); ++ talign = grub_max (talign, got_align); + #endif + ++ min_addr = ALIGN_DOWN(min_addr, talign); ++ + #ifdef GRUB_MACHINE_EMU +- mod->base = grub_osdep_dl_memalign (talign, tsize); ++ mod->base = grub_osdep_dl_memalign (talign, max_addr - min_addr); + #else +- mod->base = grub_memalign (talign, tsize); ++ mod->base = grub_memalign (talign, max_addr - min_addr); + #endif + if (!mod->base) + return grub_errno; +- mod->sz = tsize; +- ptr = mod->base; ++ mod->sz = max_addr - min_addr; ++ mod->min_addr = min_addr; + +- for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff); +- i < e->e_shnum; +- i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize)) ++ for (i = 0, p = (const Elf_Phdr *)((const char *) e + e->e_phoff); ++ i < e->e_phnum; ++ i++, p = (const Elf_Phdr *)((const char *) p + e->e_phentsize)) + { +- grub_size_t sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign); +- grub_size_t sh_size = ALIGN_UP(s->sh_size, sh_addralign); +- +- if (s->sh_flags & SHF_ALLOC) +- { +- grub_dl_segment_t seg; +- +- seg = (grub_dl_segment_t) grub_malloc (sizeof (*seg)); +- if (! seg) +- return grub_errno; +- +- if (s->sh_size) +- { +- void *addr; +- +- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, sh_addralign); +- addr = ptr; +- ptr += sh_size; +- +- switch (s->sh_type) +- { +- case SHT_PROGBITS: +- grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size); +- grub_memset ((char *)addr + s->sh_size, 0, +- sh_size - s->sh_size); +- break; +- case SHT_NOBITS: +- grub_memset (addr, 0, sh_size); +- break; +- } +- +- seg->addr = addr; +- } +- else +- seg->addr = 0; ++#if defined(__mips__) || defined(__ia64__) ++ if (p->p_type == PT_DYNAMIC) ++ grub_arch_dl_parse_dynamic (mod, (Elf_Dyn *) ((char *) e + p->p_offset), p->p_filesz); ++#endif ++ if (p->p_type != PT_LOAD) ++ continue; + +- seg->size = sh_size; +- seg->section = i; +- seg->next = mod->segment; +- mod->segment = seg; +- } ++ void *addr = (char *)mod->base + (p->p_vaddr - mod->min_addr); ++ grub_memcpy (addr, (char *) e + p->p_offset, p->p_filesz); ++ grub_memset ((char *) addr + p->p_filesz, 0, p->p_memsz - p->p_filesz); + } + #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \ + !defined (__loongarch__) +- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, tramp_align); +- mod->tramp = ptr; +- mod->trampptr = ptr; +- ptr += tramp; +- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, got_align); +- mod->got = ptr; +- mod->gotptr = ptr; +- ptr += got; ++ mod->trampptr = mod->tramp = (char *) mod->base + (tramp_addr - mod->min_addr); ++ mod->gotptr = mod->got = (char *) mod->base + (got_addr - mod->min_addr); + #endif + + grub_dprintf ("modules", "done loading segments for \"%s\"\n", mod->name); +@@ -412,10 +361,43 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) + Elf_Word size, entsize; + + grub_dprintf ("modules", "Resolving symbols for \"%s\"\n", mod->name); ++ ++ /* On emu mod_init/mod_fini are not exported. */ ++#ifdef GRUB_MACHINE_EMU ++ for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); ++ i < e->e_shnum; ++ i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) ++ if (s->sh_type == SHT_SYMTAB) ++ { ++ Elf_Shdr *s2; ++ sym = (Elf_Sym *) ((char *) e + s->sh_offset); ++ size = s->sh_size; ++ entsize = s->sh_entsize; ++ ++ s2 = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shentsize * s->sh_link); ++ str = (char *) e + s2->sh_offset; ++ ++ for (i = 0; ++ i < size / entsize; ++ i++, sym = (Elf_Sym *) ((char *) sym + entsize)) ++ { ++ const char *name = str + sym->st_name; ++ ++ if (ELF_ST_TYPE (sym->st_info) == STT_FUNC) ++ { ++ if (grub_strcmp (name, "grub_mod_init") == 0) ++ mod->init = (void (*) (grub_dl_t)) (sym->st_value + (Elf_Addr) mod->base - mod->min_addr); ++ else if (grub_strcmp (name, "grub_mod_fini") == 0) ++ mod->fini = (void (*) (void)) (sym->st_value + (Elf_Addr) mod->base - mod->min_addr); ++ } ++ } ++ } ++#endif ++ + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) +- if (s->sh_type == SHT_SYMTAB) ++ if (s->sh_type == SHT_DYNSYM) + break; + + /* Module without symbol table may still be used to pull in dependencies. +@@ -447,15 +429,19 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) + unsigned char type = ELF_ST_TYPE (sym->st_info); + unsigned char bind = ELF_ST_BIND (sym->st_info); + const char *name = str + sym->st_name; ++ int isfunc = type == STT_FUNC; + + switch (type) + { + case STT_NOTYPE: + case STT_OBJECT: ++ case STT_FUNC: + /* Resolve a global symbol. */ + if (sym->st_name != 0 && sym->st_shndx == 0) + { + grub_symbol_t nsym = grub_dl_resolve_symbol (name); ++ if (! nsym && bind == STB_WEAK) ++ break; + if (! nsym) + return grub_error (GRUB_ERR_BAD_MODULE, + N_("symbol `%s' not found"), name); +@@ -465,41 +451,32 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) + } + else + { +- sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod, +- sym->st_shndx); ++ sym->st_value += (Elf_Addr) mod->base - mod->min_addr; ++#ifdef __ia64__ ++ if (isfunc) ++ { ++ /* FIXME: free descriptor once it's not used anymore. */ ++ char **desc; ++ desc = grub_malloc (2 * sizeof (char *)); ++ if (!desc) ++ return grub_errno; ++ desc[0] = (void *) sym->st_value; ++ desc[1] = (char *) mod->base + mod->pltgot; ++ sym->st_value = (grub_addr_t) desc; ++ } ++#endif + if (bind != STB_LOCAL) +- if (grub_dl_register_symbol (name, (void *) sym->st_value, 0, mod)) ++ if (grub_dl_register_symbol (name, (void *) sym->st_value, isfunc, mod)) + return grub_errno; ++ if (isfunc && grub_strcmp (name, "grub_mod_init") == 0) ++ mod->init = (void (*) (grub_dl_t)) sym->st_value; ++ else if (isfunc && grub_strcmp (name, "grub_mod_fini") == 0) ++ mod->fini = (void (*) (void)) sym->st_value; + } + break; + +- case STT_FUNC: +- sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod, +- sym->st_shndx); +-#ifdef __ia64__ +- { +- /* FIXME: free descriptor once it's not used anymore. */ +- char **desc; +- desc = grub_malloc (2 * sizeof (char *)); +- if (!desc) +- return grub_errno; +- desc[0] = (void *) sym->st_value; +- desc[1] = mod->base; +- sym->st_value = (grub_addr_t) desc; +- } +-#endif +- if (bind != STB_LOCAL) +- if (grub_dl_register_symbol (name, (void *) sym->st_value, 1, mod)) +- return grub_errno; +- if (grub_strcmp (name, "grub_mod_init") == 0) +- mod->init = (void (*) (grub_dl_t)) sym->st_value; +- else if (grub_strcmp (name, "grub_mod_fini") == 0) +- mod->fini = (void (*) (void)) sym->st_value; +- break; +- + case STT_SECTION: +- sym->st_value = (Elf_Addr) grub_dl_get_section_addr (mod, +- sym->st_shndx); ++ sym->st_value = (Elf_Addr) mod->base - mod->min_addr; + break; + + case STT_FILE: +@@ -678,22 +655,14 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) + if (s->sh_type == SHT_REL || s->sh_type == SHT_RELA) + { +- grub_dl_segment_t seg; + grub_err_t err; + +- if (!(s->sh_flags & SHF_INFO_LINK)) +- continue; +- +- seg = grub_dl_find_segment(mod, s->sh_info); +- if (!seg) +- continue; ++ if (!mod->symtab) ++ return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); + +- if (!mod->symtab) +- return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); +- +- err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg); +- if (err) +- return err; ++ err = grub_arch_dl_relocate_symbols (mod, ehdr, s); ++ if (err) ++ return err; + } + + grub_dprintf ("modules", "done relocating symbols for \"%s\"\n", mod->name); +@@ -706,7 +675,7 @@ static grub_err_t + grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr) + { + unsigned i; +- const Elf_Shdr *s; ++ const Elf_Phdr *p; + const Elf_Ehdr *e = ehdr; + grub_err_t err; + #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) +@@ -715,34 +684,34 @@ grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr) + grub_size_t tgsz; + #endif + +- for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); +- i < e->e_shnum; +- i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) ++ for (i = 0, p = (const Elf_Phdr *) ((const char *) e + e->e_phoff); ++ i < e->e_phnum; ++ i++, p = (const Elf_Phdr *) ((const char *) p + e->e_phentsize)) + { +- grub_dl_segment_t seg; + grub_uint64_t set_attrs = GRUB_MEM_ATTR_R; + grub_uint64_t clear_attrs = GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X; + +- seg = grub_dl_find_segment(mod, i); +- if (!seg) +- continue; +- +- if (seg->size == 0 || !(s->sh_flags & SHF_ALLOC)) ++ if (p->p_memsz == 0) + continue; + +- if (s->sh_flags & SHF_WRITE) ++ if (p->p_flags & PF_W) + { + set_attrs |= GRUB_MEM_ATTR_W; + clear_attrs &= ~GRUB_MEM_ATTR_W; + } + +- if (s->sh_flags & SHF_EXECINSTR) ++ if (p->p_flags & PF_X) + { + set_attrs |= GRUB_MEM_ATTR_X; + clear_attrs &= ~GRUB_MEM_ATTR_X; + } +- err = grub_update_mem_attrs ((grub_addr_t)(seg->addr), seg->size, +- set_attrs, clear_attrs); ++ ++ grub_addr_t from = (grub_addr_t) ((char *)mod->base + (p->p_vaddr - mod->min_addr)); ++ grub_addr_t to = from + p->p_memsz; ++ ++ err = grub_update_mem_attrs (ALIGN_DOWN(from, DL_ALIGN), ++ ALIGN_UP(to, DL_ALIGN) - ALIGN_DOWN(from, DL_ALIGN), ++ set_attrs, clear_attrs); + if (err != GRUB_ERR_NONE) + return err; + } +@@ -777,6 +746,7 @@ grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr) + static void + grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e) + { ++#if 0 + void *text, *data = NULL; + long idx; + +@@ -804,6 +774,7 @@ grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e) + "\\\n%p\n", + GRUB_TARGET_CPU, GRUB_PLATFORM, + mod->name, text); ++#endif + } + + /* Load a module from core memory. */ +@@ -819,16 +790,16 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + if (grub_dl_check_header (e, size)) + return 0; + +- if (e->e_type != ET_REL) ++ if (e->e_type != ET_REL && 0) + { + grub_error (GRUB_ERR_BAD_MODULE, N_("this ELF file is not of the right type")); + return 0; + } + + /* Make sure that every section is within the core. */ +- if (size < e->e_shoff + (grub_uint32_t) e->e_shentsize * e->e_shnum) ++ if (size < e->e_phoff + (grub_uint32_t) e->e_phentsize * e->e_phnum) + { +- grub_error (GRUB_ERR_BAD_OS, "ELF sections outside core"); ++ grub_error (GRUB_ERR_BAD_OS, "ELF program headers outside core"); + return 0; + } + +@@ -854,6 +825,9 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + || grub_dl_load_segments (mod, e) + || grub_dl_resolve_symbols (mod, e) + || grub_dl_relocate_symbols (mod, e) ++#ifdef __mips__ ++ || grub_arch_dl_relocate_pltgot (mod) ++#endif + #ifdef GRUB_MACHINE_EFI + || grub_dl_set_mem_attrs (mod, e)) + #else +diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c +index 1de1c28..bcef198 100644 +--- a/grub-core/kern/emu/full.c ++++ b/grub-core/kern/emu/full.c +@@ -39,13 +39,11 @@ grub_arch_dl_check_header (void *ehdr) + } + + grub_err_t +-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, +- Elf_Shdr *s, grub_dl_segment_t seg) ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, Elf_Shdr *s) + { + (void) mod; + (void) ehdr; + (void) s; +- (void) seg; + return GRUB_ERR_BAD_MODULE; + } + +diff --git a/grub-core/kern/i386/dl.c b/grub-core/kern/i386/dl.c +index d6b4681..ab660b4 100644 +--- a/grub-core/kern/i386/dl.c ++++ b/grub-core/kern/i386/dl.c +@@ -41,7 +41,7 @@ grub_arch_dl_check_header (void *ehdr) + /* Relocate symbols. */ + grub_err_t + grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, +- Elf_Shdr *s, grub_dl_segment_t seg) ++ Elf_Shdr *s) + { + Elf_Rel *rel, *max; + +@@ -53,16 +53,22 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + Elf_Word *addr; + Elf_Sym *sym; + +- if (seg->size < rel->r_offset) ++ if (mod->min_addr + mod->sz <= rel->r_offset || mod->min_addr > rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, +- "reloc offset is out of the segment"); ++ "reloc offset is out of the segment: %x not in [%x..%x]", ++ rel->r_offset, mod->min_addr, mod->min_addr + mod->sz); + +- addr = (Elf_Word *) ((char *) seg->addr + rel->r_offset); ++ addr = (Elf_Word *) ((char *) mod->base + rel->r_offset - mod->min_addr); + sym = (Elf_Sym *) ((char *) mod->symtab + + mod->symsize * ELF_R_SYM (rel->r_info)); + + switch (ELF_R_TYPE (rel->r_info)) + { ++ case R_386_JMP_SLOT: ++ *addr = sym->st_value; ++ break; ++ ++ case R_386_GLOB_DAT: + case R_386_32: + *addr += sym->st_value; + break; +@@ -70,6 +76,11 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + case R_386_PC32: + *addr += (sym->st_value - (grub_addr_t) addr); + break; ++ ++ case R_386_RELATIVE: ++ *addr += (grub_addr_t) mod->base - mod->min_addr; ++ break; ++ + default: + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + N_("relocation 0x%x is not implemented yet"), +diff --git a/grub-core/kern/ia64/dl.c b/grub-core/kern/ia64/dl.c +index 92d82c5..b2a1713 100644 +--- a/grub-core/kern/ia64/dl.c ++++ b/grub-core/kern/ia64/dl.c +@@ -43,14 +43,29 @@ grub_arch_dl_check_header (void *ehdr) + return GRUB_ERR_NONE; + } + ++void ++grub_arch_dl_parse_dynamic (grub_dl_t mod, Elf_Dyn *dyn, grub_size_t sz) ++{ ++ unsigned i; ++ for (i = 0; i < sz / sizeof(dyn[0]); i++) ++ switch (dyn[i].d_tag) ++ { ++ case DT_PLTGOT: ++ mod->pltgot = dyn[i].d_un.d_ptr; ++ break; ++ case DT_NULL: ++ return; ++ } ++} ++ + #pragma GCC diagnostic ignored "-Wcast-align" + + /* Relocate symbols. */ + grub_err_t +-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, +- Elf_Shdr *s, grub_dl_segment_t seg) ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, Elf_Shdr *s) + { + Elf_Rela *rel, *max; ++ grub_addr_t gp = (grub_addr_t) mod->base + (grub_addr_t) mod->pltgot; + + for (rel = (Elf_Rela *) ((char *) ehdr + s->sh_offset), + max = (Elf_Rela *) ((char *) rel + s->sh_size); +@@ -61,11 +76,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + Elf_Sym *sym; + grub_uint64_t value; + +- if (seg->size < (rel->r_offset & ~3)) ++ if (mod->min_addr + mod->sz <= rel->r_offset || mod->min_addr > rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, +- "reloc offset is out of the segment"); ++ "reloc offset is out of the segment: %lx not in [%lx..%lx]", ++ rel->r_offset, mod->min_addr, mod->min_addr + mod->sz); + +- addr = (grub_addr_t) seg->addr + rel->r_offset; ++ addr = (grub_addr_t) ((char *) mod->base + rel->r_offset - mod->min_addr); + sym = (Elf_Sym *) ((char *) mod->symtab + + mod->symsize * ELF_R_SYM (rel->r_info)); + +@@ -94,25 +110,27 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + grub_ia64_add_value_to_slot_20b (addr, noff); + } + break; +- case R_IA64_SEGREL64LSB: +- *(grub_uint64_t *) addr += value - (grub_addr_t) seg->addr; ++ case R_IA64_IPLTLSB: ++ grub_memcpy((void *) addr, (void *) value, 16); + break; + case R_IA64_FPTR64LSB: + case R_IA64_DIR64LSB: +- *(grub_uint64_t *) addr += value; ++ *(grub_uint64_t *) addr = value; + break; ++ case R_IA64_REL64LSB: ++ *(grub_uint64_t *) addr = (grub_addr_t) mod->base - mod->min_addr + rel->r_addend; + case R_IA64_PCREL64LSB: + *(grub_uint64_t *) addr += value - addr; + break; + case R_IA64_GPREL64I: +- grub_ia64_set_immu64 (addr, value - (grub_addr_t) mod->base); ++ grub_ia64_set_immu64 (addr, value - gp); + break; + case R_IA64_GPREL22: +- if ((value - (grub_addr_t) mod->base) & ~MASK20) ++ if ((value - gp) & ~MASK20) + return grub_error (GRUB_ERR_BAD_MODULE, + "gprel offset too big (%lx)", +- value - (grub_addr_t) mod->base); +- grub_ia64_add_value_to_slot_21 (addr, value - (grub_addr_t) mod->base); ++ value - gp); ++ grub_ia64_add_value_to_slot_21 (addr, value - gp); + break; + + case R_IA64_LTOFF22X: +@@ -124,11 +142,11 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + { + grub_uint64_t *gpptr = mod->gotptr; + *gpptr = value; +- if (((grub_addr_t) gpptr - (grub_addr_t) mod->base) & ~MASK20) ++ if (((grub_addr_t) gpptr - gp) & ~MASK20) + return grub_error (GRUB_ERR_BAD_MODULE, + "gprel offset too big (%lx)", +- (grub_addr_t) gpptr - (grub_addr_t) mod->base); +- grub_ia64_add_value_to_slot_21 (addr, (grub_addr_t) gpptr - (grub_addr_t) mod->base); ++ (grub_addr_t) gpptr - gp); ++ grub_ia64_add_value_to_slot_21 (addr, (grub_addr_t) gpptr - gp); + mod->gotptr = gpptr + 1; + break; + } +diff --git a/grub-core/kern/loongarch64/dl.c b/grub-core/kern/loongarch64/dl.c +index 951b131..a3f5730 100644 +--- a/grub-core/kern/loongarch64/dl.c ++++ b/grub-core/kern/loongarch64/dl.c +@@ -46,7 +46,7 @@ grub_arch_dl_check_header (void *ehdr) + */ + grub_err_t + grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, +- Elf_Shdr *s, grub_dl_segment_t seg) ++ Elf_Shdr *s) + { + Elf_Rel *rel, *max; + struct grub_loongarch64_stack stack; +@@ -61,9 +61,10 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + void *place; + grub_uint64_t sym_addr; + +- if (rel->r_offset >= seg->size) ++ if (mod->min_addr + mod->sz <= rel->r_offset || mod->min_addr > rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, +- "reloc offset is outside the segment"); ++ "reloc offset is out of the segment: %lx not in [%lx..%lx]", ++ rel->r_offset, mod->min_addr, mod->min_addr + mod->sz); + + sym = (Elf_Sym *) ((char*) mod->symtab + + mod->symsize * ELF_R_SYM (rel->r_info)); +@@ -72,10 +73,14 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + if (s->sh_type == SHT_RELA) + sym_addr += ((Elf_Rela *) rel)->r_addend; + +- place = (void *) ((grub_addr_t) seg->addr + rel->r_offset); ++ place = (void *) ((char *) mod->base + rel->r_offset - mod->min_addr); + + switch (ELF_R_TYPE (rel->r_info)) + { ++ case R_LARCH_JUMP_SLOT: ++ *(grub_uint64_t *)place = sym_addr; ++ break; ++ + case R_LARCH_64: + { + grub_uint64_t *abs_place = place; +@@ -83,9 +88,14 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + grub_dprintf ("dl", "reloc_abs64 %p => 0x%016llx, %p\n", + place, (unsigned long long) sym_addr, abs_place); + +- *abs_place += (grub_uint64_t) sym_addr; ++ *abs_place = (grub_uint64_t) sym_addr; + } + break; ++ case R_LARCH_RELATIVE: ++ *(grub_uint64_t *)place = (grub_addr_t) mod->base - mod->min_addr; ++ if (s->sh_type == SHT_RELA) ++ *(grub_uint64_t *)place += ((Elf_Rela *) rel)->r_addend; ++ break; + case R_LARCH_MARK_LA: + break; + case R_LARCH_SOP_PUSH_PCREL: +diff --git a/grub-core/kern/mips/dl.c b/grub-core/kern/mips/dl.c +index db41189..43daabb 100644 +--- a/grub-core/kern/mips/dl.c ++++ b/grub-core/kern/mips/dl.c +@@ -29,6 +29,53 @@ + static char __gnu_local_gp_dummy; + static char _gp_disp_dummy; + ++void ++grub_arch_dl_parse_dynamic (grub_dl_t mod, Elf_Dyn *dyn, grub_size_t sz) ++{ ++ unsigned i; ++ for (i = 0; i < sz / sizeof(dyn[0]); i++) ++ switch (dyn[i].d_tag) ++ { ++ case DT_PLTGOT: ++ mod->pltgot = dyn[i].d_un.d_ptr; ++ break; ++ case DT_MIPS_GOTSYM: ++ mod->gotsym = dyn[i].d_un.d_val; ++ break; ++ case DT_MIPS_SYMTABNO: ++ mod->symtabno = dyn[i].d_un.d_val; ++ break; ++ case DT_MIPS_LOCAL_GOTNO: ++ mod->local_gotno = dyn[i].d_un.d_val; ++ break; ++ case DT_NULL: ++ return; ++ } ++} ++ ++grub_err_t ++grub_arch_dl_relocate_pltgot (grub_dl_t mod) ++{ ++ grub_uint32_t i = 0; ++ grub_uint32_t *pltgot = (grub_uint32_t *) (void *) ((char *) mod->base + (mod->pltgot - mod->min_addr)); ++ ++ for (i = 0; i < mod->local_gotno; i++) ++ { ++ pltgot[i] += (grub_addr_t)mod->base - mod->min_addr; ++ grub_dprintf("dl", "Locating local %p[%x] to %x\n", &pltgot[i], mod->pltgot + (i) * 4, pltgot[i]); ++ } ++ for (i = 0; i < mod->symtabno - mod->gotsym; i++) ++ { ++ Elf_Sym *sym; ++ sym = (Elf_Sym *) (void *) ((char *) mod->symtab ++ + mod->symsize * (i + mod->gotsym)); ++ pltgot[i+mod->local_gotno] = sym->st_value; ++ grub_dprintf("dl", "Locating %p[%x] to %x\n", &pltgot[i+mod->local_gotno], mod->pltgot + (i+mod->local_gotno) * 4, sym->st_value); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ + /* Check if EHDR is a valid ELF header. */ + grub_err_t + grub_arch_dl_check_header (void *ehdr) +@@ -96,8 +143,7 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + + /* Relocate symbols. */ + grub_err_t +-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, +- Elf_Shdr *s, grub_dl_segment_t seg) ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, Elf_Shdr *s) + { + grub_uint32_t gp0; + Elf_Ehdr *e = ehdr; +@@ -130,11 +176,15 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + Elf_Sym *sym; + grub_uint32_t sym_value; + +- if (seg->size < rel->r_offset) ++ if (ELF_R_TYPE (rel->r_info) == R_MIPS_NONE) ++ continue; ++ ++ if (mod->min_addr + mod->sz <= rel->r_offset || mod->min_addr > rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, +- "reloc offset is out of the segment"); ++ "reloc offset is out of the segment: %x not in [%x..%x]", ++ rel->r_offset, mod->min_addr, mod->min_addr + mod->sz); + +- addr = (grub_uint8_t *) ((char *) seg->addr + rel->r_offset); ++ addr = (void *) ((char *) mod->base + rel->r_offset - mod->min_addr); + sym = (Elf_Sym *) ((char *) mod->symtab + + mod->symsize * ELF_R_SYM (rel->r_info)); + sym_value = sym->st_value; +@@ -174,7 +224,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + && ELF_R_TYPE (rel2->r_info) == R_MIPS_LO16) + { + value += *(grub_int16_t *) +- ((char *) seg->addr + rel2->r_offset ++ (((char *) mod->base + rel2->r_offset - mod->min_addr) + #ifdef GRUB_CPU_WORDS_BIGENDIAN + + 2 + #endif +@@ -190,6 +240,18 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + #endif + *(grub_uint16_t *) addr += sym_value & 0xffff; + break; ++ case R_MIPS_REL32: ++ if (ELF_R_SYM (rel->r_info) == 0 || ELF_ST_TYPE (sym->st_info) == STT_SECTION) ++ { ++ *(grub_uint32_t *) addr += (grub_addr_t) mod->base - mod->min_addr; ++ if (s->sh_type == SHT_RELA) ++ *(grub_uint32_t *) addr += ((Elf_Rela *) rel)->r_addend; ++ } ++ else ++ { ++ *(grub_uint32_t *) addr = (grub_addr_t) sym_value; ++ } ++ break; + case R_MIPS_32: + *(grub_uint32_t *) addr += sym_value; + break; +@@ -226,7 +288,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + && ELF_R_TYPE (rel2->r_info) == R_MIPS_LO16) + { + sym_value += *(grub_int16_t *) +- ((char *) seg->addr + rel2->r_offset ++ (((char *) mod->base + rel2->r_offset - mod->min_addr) + #ifdef GRUB_CPU_WORDS_BIGENDIAN + + 2 + #endif +diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c +index 0eb8bc5..04d5194 100644 +--- a/grub-core/kern/powerpc/dl.c ++++ b/grub-core/kern/powerpc/dl.c +@@ -92,8 +92,7 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + + /* Relocate symbols. */ + grub_err_t +-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, +- Elf_Shdr *s, grub_dl_segment_t seg) ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, Elf_Shdr *s) + { + Elf_Rela *rel, *max; + +@@ -106,11 +105,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + Elf_Sym *sym; + grub_uint32_t value; + +- if (seg->size < rel->r_offset) ++ if (mod->min_addr + mod->sz <= rel->r_offset || mod->min_addr > rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, +- "reloc offset is out of the segment"); ++ "reloc offset is out of the segment: %x not in [%x..%x]", ++ rel->r_offset, mod->min_addr, mod->min_addr + mod->sz); + +- addr = (Elf_Word *) ((char *) seg->addr + rel->r_offset); ++ addr = (Elf_Word *) ((char *) mod->base + rel->r_offset - mod->min_addr); + sym = (Elf_Sym *) ((char *) mod->symtab + + mod->symsize * ELF_R_SYM (rel->r_info)); + +@@ -150,10 +150,15 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + *(Elf_Half *) addr = (value + 0x8000) >> 16; + break; + ++ case GRUB_ELF_R_PPC_JMP_SLOT: + case GRUB_ELF_R_PPC_ADDR32: + *addr = value; + break; + ++ case GRUB_ELF_R_PPC_RELATIVE: ++ *addr += (grub_addr_t) mod->base - mod->min_addr + rel->r_addend; ++ break; ++ + case GRUB_ELF_R_PPC_REL32: + *addr = value - (Elf_Word) addr; + break; +diff --git a/grub-core/kern/riscv/dl.c b/grub-core/kern/riscv/dl.c +index 1fa085b..f1870e4 100644 +--- a/grub-core/kern/riscv/dl.c ++++ b/grub-core/kern/riscv/dl.c +@@ -54,7 +54,7 @@ grub_arch_dl_check_header (void *ehdr) + /* Relocate symbols. */ + grub_err_t + grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, +- Elf_Shdr *s, grub_dl_segment_t seg) ++ Elf_Shdr *s) + { + Elf_Rel *rel, *max; + +@@ -67,9 +67,11 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + void *place; + grub_size_t sym_addr; + +- if (rel->r_offset >= seg->size) ++ if (mod->min_addr + mod->sz <= rel->r_offset || mod->min_addr > rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, +- "reloc offset is out of the segment"); ++ "reloc offset is out of the segment: %lx not in [%lx..%lx]", ++ (unsigned long) rel->r_offset, (unsigned long) mod->min_addr, ++ (unsigned long) mod->min_addr + mod->sz); + + sym = (Elf_Sym *) ((char *) mod->symtab + + mod->symsize * ELF_R_SYM (rel->r_info)); +@@ -78,7 +80,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + if (s->sh_type == SHT_RELA) + sym_addr += ((Elf_Rela *) rel)->r_addend; + +- place = (void *) ((grub_addr_t) seg->addr + rel->r_offset); ++ place = (void *) ((char *) mod->base + rel->r_offset - mod->min_addr); + + switch (ELF_R_TYPE (rel->r_info)) + { +@@ -270,7 +272,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + rel2_offset = rel2->r_offset; + rel2_info = rel2->r_info; +- rel2_loc = (grub_addr_t) seg->addr + rel2_offset; ++ rel2_loc = (Elf_Addr) ((char *) mod->base + rel2_offset - mod->min_addr); + + if (ELF_R_TYPE (rel2_info) == R_RISCV_PCREL_HI20 + && rel2_loc == sym_addr) +@@ -330,6 +332,17 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + case R_RISCV_RELAX: + break; ++ ++ case R_RISCV_JUMP_SLOT: ++ *(grub_size_t *)place = sym_addr; ++ break; ++ ++ case R_RISCV_RELATIVE: ++ *(grub_size_t *)place += (grub_addr_t) mod->base - mod->min_addr; ++ if (s->sh_type == SHT_RELA) ++ *(grub_size_t *)place += ((Elf_Rela *) rel)->r_addend; ++ break; ++ + default: + { + char rel_info[17]; /* log16(2^64) = 16, plus NUL. */ +diff --git a/grub-core/kern/sparc64/dl.c b/grub-core/kern/sparc64/dl.c +index f054f08..5175b97 100644 +--- a/grub-core/kern/sparc64/dl.c ++++ b/grub-core/kern/sparc64/dl.c +@@ -97,8 +97,7 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + + /* Relocate symbols. */ + grub_err_t +-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, +- Elf_Shdr *s, grub_dl_segment_t seg) ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, Elf_Shdr *s) + { + Elf_Rela *rel, *max; + +@@ -111,17 +110,21 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + Elf_Sym *sym; + Elf_Addr value; + +- if (seg->size < rel->r_offset) ++ if (mod->min_addr + mod->sz <= rel->r_offset || mod->min_addr > rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, +- "reloc offset is out of the segment"); ++ "reloc offset is out of the segment: %lx not in [%lx..%lx]", ++ rel->r_offset, mod->min_addr, mod->min_addr + mod->sz); + +- addr = (Elf_Word *) ((char *) seg->addr + rel->r_offset); ++ addr = (Elf_Word *) ((char *) mod->base + rel->r_offset - mod->min_addr); + sym = (Elf_Sym *) ((char *) mod->symtab + + mod->symsize * ELF_R_SYM (rel->r_info)); + + value = sym->st_value + rel->r_addend; + switch (ELF_R_TYPE (rel->r_info) & 0xff) + { ++ case R_SPARC_RELATIVE: ++ *(Elf_Xword *) addr += (grub_addr_t) mod->base - mod->min_addr + rel->r_addend; ++ break; + case R_SPARC_32: /* 3 V-word32 */ + if (value & 0xFFFFFFFF00000000) + return grub_error (GRUB_ERR_BAD_MODULE, +@@ -166,6 +169,8 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + case R_SPARC_LO10: /* 12 T-simm13 */ + *addr = (*addr & 0xFFFFFC00) | (value & 0x3FF); + break; ++ case R_SPARC_JMP_SLOT: ++ case R_SPARC_GLOB_DAT: + case R_SPARC_64: /* 32 V-xwords64 */ + *(Elf_Xword *) addr = value; + break; +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 055bb56..e14b2bd 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -42,13 +42,13 @@ + #if !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_KERNEL) + + #define GRUB_MOD_INIT(name) \ +-static void grub_mod_init (grub_dl_t mod __attribute__ ((unused))) __attribute__ ((used)); \ +-static void \ ++void grub_mod_init (grub_dl_t mod __attribute__ ((unused))) __attribute__ ((used)); \ ++void \ + grub_mod_init (grub_dl_t mod __attribute__ ((unused))) + + #define GRUB_MOD_FINI(name) \ +-static void grub_mod_fini (void) __attribute__ ((used)); \ +-static void \ ++void grub_mod_fini (void) __attribute__ ((used)); \ ++void \ + grub_mod_fini (void) + + #elif defined (GRUB_KERNEL) +@@ -155,15 +155,6 @@ static const char grub_module_name_##name[] \ + + #ifndef ASM_FILE + +-struct grub_dl_segment +-{ +- struct grub_dl_segment *next; +- void *addr; +- grub_size_t size; +- unsigned section; +-}; +-typedef struct grub_dl_segment *grub_dl_segment_t; +- + struct grub_dl; + + struct grub_dl_dep +@@ -180,7 +171,6 @@ struct grub_dl + grub_uint64_t ref_count; + int persistent; + grub_dl_dep_t dep; +- grub_dl_segment_t segment; + Elf_Sym *symtab; + grub_size_t symsize; + void (*init) (struct grub_dl *mod); +@@ -193,9 +183,16 @@ struct grub_dl + #endif + #ifdef __mips__ + grub_uint32_t *reginfo; ++ grub_uint32_t gotsym; ++ grub_uint32_t local_gotno; ++ grub_uint32_t symtabno; ++#endif ++#if defined (__mips__) || defined(__ia64__) ++ grub_size_t pltgot; + #endif + void *base; + grub_size_t sz; ++ grub_addr_t min_addr; + struct grub_dl *next; + }; + #endif +@@ -298,19 +295,6 @@ grub_dl_find_section_index (Elf_Ehdr *e, const char *name) + return -1; + } + +-/* Return the segment for a section of index N */ +-static inline grub_dl_segment_t +-grub_dl_find_segment (grub_dl_t mod, unsigned n) +-{ +- grub_dl_segment_t seg; +- +- for (seg = mod->segment; seg; seg = seg->next) +- if (seg->section == n) +- return seg; +- +- return NULL; +-} +- + #endif + + void * EXPORT_FUNC(grub_resolve_symbol) (const char *name); +@@ -322,7 +306,7 @@ grub_err_t grub_arch_dl_check_header (void *ehdr); + #ifndef GRUB_UTIL + grub_err_t + grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, +- Elf_Shdr *s, grub_dl_segment_t seg); ++ Elf_Shdr *s); + grub_size_t + grub_arch_dl_min_alignment (void); + #endif +@@ -330,6 +314,8 @@ grub_arch_dl_min_alignment (void); + #if defined (_mips) + #define GRUB_LINKER_HAVE_INIT 1 + void grub_arch_dl_init_linker (void); ++ ++grub_err_t grub_arch_dl_relocate_pltgot (grub_dl_t mod); + #endif + + #define GRUB_IA64_DL_TRAMP_ALIGN 16 +@@ -338,6 +324,11 @@ void grub_arch_dl_init_linker (void); + grub_err_t + grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + grub_size_t *got); ++ ++#if defined (__ia64__) || defined (__mips__) ++void grub_arch_dl_parse_dynamic (grub_dl_t mod, Elf_Dyn *dyn, grub_size_t sz); ++#endif ++ + grub_err_t + grub_arm64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + grub_size_t *got); +diff --git a/include/grub/elf.h b/include/grub/elf.h +index bd313a7..113e5cf 100644 +--- a/include/grub/elf.h ++++ b/include/grub/elf.h +@@ -2540,6 +2540,8 @@ typedef Elf32_Addr Elf32_Conflict; + /* LoongArch relocations */ + #define R_LARCH_NONE 0 + #define R_LARCH_64 2 ++#define R_LARCH_RELATIVE 3 ++#define R_LARCH_JUMP_SLOT 5 + #define R_LARCH_MARK_LA 20 + #define R_LARCH_SOP_PUSH_PCREL 22 + #define R_LARCH_SOP_PUSH_ABSOLUTE 23 +@@ -2581,6 +2583,7 @@ typedef Elf32_Addr Elf_Addr; + typedef Elf32_Nhdr Elf_Nhdr; + typedef Elf32_Ehdr Elf_Ehdr; + typedef Elf32_Phdr Elf_Phdr; ++typedef Elf32_Dyn Elf_Dyn; + typedef Elf32_Half Elf_Half; + typedef Elf32_Off Elf_Off; + typedef Elf32_Rel Elf_Rel; +@@ -2611,6 +2614,7 @@ typedef Elf64_Addr Elf_Addr; + typedef Elf64_Nhdr Elf_Nhdr; + typedef Elf64_Ehdr Elf_Ehdr; + typedef Elf64_Phdr Elf_Phdr; ++typedef Elf64_Dyn Elf_Dyn; + typedef Elf64_Half Elf_Half; + typedef Elf64_Off Elf_Off; + typedef Elf64_Rel Elf_Rel; +diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c +index 9488f05..5a66363 100644 +--- a/util/grub-mkimagexx.c ++++ b/util/grub-mkimagexx.c +@@ -1403,9 +1403,10 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, + { + grub_uint32_t hi20, lo12; + ++#if defined(MKIMAGE_ELF64) + if (off != (grub_int32_t)off) + grub_util_error ("target %lx not reachable from pc=%lx", (long)sym_addr, (long)((char *)target - (char *)e)); +- ++#endif + hi20 = (off + 0x800) & 0xfffff000; + lo12 = (off - hi20) & 0xfff; + t32[0] = grub_host_to_target32 ((grub_target_to_host32 (t32[0]) & 0xfff) | hi20); +diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c +index 91d9e8f..d1de715 100644 +--- a/util/grub-module-verifier.c ++++ b/util/grub-module-verifier.c +@@ -10,11 +10,17 @@ struct grub_module_verifier_arch archs[] = { + { "i386", 4, 0, EM_386, GRUB_MODULE_VERIFY_SUPPORTS_REL, (int[]){ + R_386_32, + R_386_PC32, ++ R_386_RELATIVE, ++ R_386_JMP_SLOT, ++ R_386_GLOB_DAT, + -1 + } }, + { "x86_64", 8, 0, EM_X86_64, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_X86_64_64, + R_X86_64_PC64, ++ R_X86_64_RELATIVE, ++ R_X86_64_GLOB_DAT, ++ R_X86_64_JUMP_SLOT, + /* R_X86_64_32, R_X86_64_32S are supported but shouldn't be used because of their limited range. */ + -1 + }, (int[]){ +@@ -46,6 +52,8 @@ struct grub_module_verifier_arch archs[] = { + usually. */ + R_SPARC_HI22, + R_SPARC_32, ++ GRUB_ELF_R_PPC_RELATIVE, ++ GRUB_ELF_R_PPC_JMP_SLOT, + -1 + } }, + { "ia64", 8, 0, EM_IA_64, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ +@@ -56,7 +64,6 @@ struct grub_module_verifier_arch archs[] = { + for anything else, so assume that it always points to a + function. + */ +- R_IA64_SEGREL64LSB, + R_IA64_FPTR64LSB, + R_IA64_DIR64LSB, + R_IA64_PCREL64LSB, +@@ -65,12 +72,16 @@ struct grub_module_verifier_arch archs[] = { + R_IA64_GPREL64I, + R_IA64_LTOFF_FPTR22, + R_IA64_LDXMOV, ++ R_IA64_IPLTLSB, ++ R_IA64_REL64LSB, + -1 + }, (int[]){ + R_IA64_GPREL22, + -1 + } }, + { "mipsel", 4, 0, EM_MIPS, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ ++ R_MIPS_NONE, ++ R_MIPS_REL32, + R_MIPS_HI16, + R_MIPS_LO16, + R_MIPS_32, +@@ -82,6 +93,8 @@ struct grub_module_verifier_arch archs[] = { + -1 + } }, + { "mips", 4, 1, EM_MIPS, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ ++ R_MIPS_NONE, ++ R_MIPS_REL32, + R_MIPS_HI16, + R_MIPS_LO16, + R_MIPS_32, +@@ -103,6 +116,9 @@ struct grub_module_verifier_arch archs[] = { + R_ARM_THM_MOVW_ABS_NC, + R_ARM_THM_MOVT_ABS, + R_ARM_THM_JUMP19, ++ R_ARM_RELATIVE, ++ R_ARM_JUMP_SLOT, ++ R_ARM_GLOB_DAT, + -1 + } }, + { "arm64", 8, 0, EM_AARCH64, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ +@@ -116,12 +132,17 @@ struct grub_module_verifier_arch archs[] = { + R_AARCH64_ADR_PREL_PG_HI21, + R_AARCH64_ADD_ABS_LO12_NC, + R_AARCH64_LDST64_ABS_LO12_NC, ++ R_AARCH64_RELATIVE, ++ R_AARCH64_JUMP_SLOT, ++ R_AARCH64_GLOB_DAT, + R_AARCH64_PREL32, + -1 + } }, + { "loongarch64", 8, 0, EM_LOONGARCH, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_LARCH_NONE, + R_LARCH_64, ++ R_LARCH_RELATIVE, ++ R_LARCH_JUMP_SLOT, + R_LARCH_MARK_LA, + R_LARCH_SOP_PUSH_PCREL, + R_LARCH_SOP_PUSH_ABSOLUTE, +@@ -178,6 +199,8 @@ struct grub_module_verifier_arch archs[] = { + R_RISCV_RELAX, + R_RISCV_RVC_BRANCH, + R_RISCV_RVC_JUMP, ++ R_RISCV_RELATIVE, ++ R_RISCV_JUMP_SLOT, + -1 + } }, + { "riscv64", 8, 0, EM_RISCV, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ +@@ -206,6 +229,8 @@ struct grub_module_verifier_arch archs[] = { + R_RISCV_RELAX, + R_RISCV_RVC_BRANCH, + R_RISCV_RVC_JUMP, ++ R_RISCV_RELATIVE, ++ R_RISCV_JUMP_SLOT, + -1 + } + }, +diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c +index a42c20b..afccdf6 100644 +--- a/util/grub-module-verifierXX.c ++++ b/util/grub-module-verifierXX.c +@@ -163,6 +163,16 @@ get_shdr (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word in + return s; + } + ++static Elf_Phdr * ++get_phdr (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word index) ++{ ++ if (grub_target_to_host (e->e_phoff) == 0) ++ grub_util_error ("Invalid program header offset"); ++ ++ return (Elf_Phdr *) ((char *) e + grub_target_to_host (e->e_phoff) + ++ index * grub_target_to_host16 (e->e_phentsize)); ++} ++ + static Elf_Shnum + get_shnum (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) + { +@@ -252,7 +262,7 @@ get_symtab (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word + { + s = get_shdr (arch, e, i, module_size); + +- if (grub_target_to_host32 (s->sh_type) == SHT_SYMTAB) ++ if (grub_target_to_host32 (s->sh_type) == SHT_DYNSYM) + break; + } + +@@ -357,7 +367,8 @@ is_symbol_local(Elf_Sym *sym) + static void + section_check_relocations (const char * const modname, + const struct grub_module_verifier_arch *arch, void *ehdr, +- Elf_Shdr *s, size_t target_seg_size, size_t module_size) ++ Elf_Shdr *s, size_t module_size, ++ grub_uint64_t min_addr, grub_uint64_t max_addr) + { + Elf_Rel *rel, *max; + Elf_Sym *symtab; +@@ -374,11 +385,16 @@ section_check_relocations (const char * const modname, + { + Elf_Sym *sym; + unsigned i; ++ grub_uint32_t type = ELF_R_TYPE (grub_target_to_host (rel->r_info)); + +- if (target_seg_size < grub_target_to_host (rel->r_offset)) +- grub_util_error ("%s: reloc offset is out of the segment", modname); ++ if (type == 0) ++ continue; + +- grub_uint32_t type = ELF_R_TYPE (grub_target_to_host (rel->r_info)); ++ if (grub_target_to_host (rel->r_offset) < min_addr || grub_target_to_host (rel->r_offset) >= max_addr) ++ grub_util_error ("%s: reloc offset is out of the segment: %llx not in %llx-%llx", ++ modname, ++ (long long) grub_target_to_host (rel->r_offset), ++ (long long) min_addr, (long long) max_addr); + + if (arch->machine == EM_SPARCV9) + type &= 0xff; +@@ -439,7 +455,7 @@ section_check_relocations (const char * const modname, + + static void + check_relocations (const char * const modname, +- const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, size_t module_size) ++ const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, size_t module_size, grub_uint64_t min_addr, grub_uint64_t max_addr) + { + Elf_Shdr *s; + unsigned i; +@@ -457,12 +473,7 @@ check_relocations (const char * const modname, + if (grub_target_to_host32 (s->sh_type) == SHT_RELA && !(arch->flags & GRUB_MODULE_VERIFY_SUPPORTS_RELA)) + grub_util_error ("%s: unsupported SHT_RELA", modname); + +- /* Find the target segment. */ +- if (grub_target_to_host32 (s->sh_info) >= get_shnum (arch, e)) +- grub_util_error ("%s: orphaned reloc section", modname); +- ts = get_shdr (arch, e, grub_target_to_host32 (s->sh_info), module_size); +- +- section_check_relocations (modname, arch, e, s, grub_target_to_host (ts->sh_size), module_size); ++ section_check_relocations (modname, arch, e, s, module_size, min_addr, max_addr); + } + } + } +@@ -493,14 +504,14 @@ SUFFIX(grub_module_verify) (const char * const filename, + || grub_target_to_host16 (e->e_machine) != arch->machine) + grub_util_error ("%s: invalid arch-dependent ELF magic", filename); + +- if (grub_target_to_host16 (e->e_type) != ET_REL) ++ if (grub_target_to_host16 (e->e_type) != ET_DYN) + { + grub_util_error ("%s: this ELF file is not of the right type", filename); + } + + /* Make sure that every section is within the core. */ +- if (size < grub_target_to_host (e->e_shoff) +- + (grub_uint32_t) grub_target_to_host16 (e->e_shentsize) * get_shnum (arch, e)) ++ if (size < grub_target_to_host (e->e_phoff) ++ + (grub_uint32_t) grub_target_to_host16 (e->e_phentsize) * grub_target_to_host16 (e->e_phnum)) + { + grub_util_error ("%s: ELF sections outside core", filename); + } +@@ -516,6 +527,18 @@ SUFFIX(grub_module_verify) (const char * const filename, + + modname = (const char *) e + grub_target_to_host (s->sh_offset); + ++ unsigned i; ++ grub_uint64_t min_addr = ~(grub_uint64_t)0; ++ grub_uint64_t max_addr = 0; ++ ++ for (i = 0; i < grub_target_to_host16 (e->e_phnum); i++) ++ { ++ Elf_Phdr *p = get_phdr (arch, e, i); ++ ++ min_addr = grub_min(min_addr, grub_target_to_host(p->p_vaddr)); ++ max_addr = grub_max(max_addr, grub_target_to_host(p->p_vaddr) + grub_target_to_host(p->p_memsz)); ++ } ++ + check_symbols(arch, e, modname, whitelist_empty, size); +- check_relocations(modname, arch, e, size); ++ check_relocations(modname, arch, e, size, min_addr, max_addr); + } +-- +2.47.3 + diff --git a/1097-loongarch64-Use-la.pcrel-instead-of-la.patch b/1097-loongarch64-Use-la.pcrel-instead-of-la.patch new file mode 100644 index 0000000..fa7466e --- /dev/null +++ b/1097-loongarch64-Use-la.pcrel-instead-of-la.patch @@ -0,0 +1,31 @@ +From a0a4ae340de9daf898cbbee2765cae2a61080b51 Mon Sep 17 00:00:00 2001 +From: Fedora Ninjas +Date: Wed, 4 Feb 2026 16:30:16 +0800 +Subject: [PATCH 2/4] loongarch64: Use la.pcrel instead of la. + +la.pcrel unlike la should work even above 4GiB mark. + +Signed-off-by: Vladimir Serbinenko +--- + grub-core/kern/loongarch64/efi/startup.S | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/loongarch64/efi/startup.S b/grub-core/kern/loongarch64/efi/startup.S +index c8e2e32..0d07e2e 100644 +--- a/grub-core/kern/loongarch64/efi/startup.S ++++ b/grub-core/kern/loongarch64/efi/startup.S +@@ -28,9 +28,9 @@ FUNCTION(_start) + * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in $a1/$a0. + */ + +- la $a2, EXT_C(grub_efi_image_handle) ++ la.pcrel $a2, EXT_C(grub_efi_image_handle) + st.d $a0, $a2, 0 +- la $a2, EXT_C(grub_efi_system_table) ++ la.pcrel $a2, EXT_C(grub_efi_system_table) + st.d $a1, $a2, 0 + + b EXT_C(grub_main) +-- +2.47.3 + diff --git a/1098-Use-ET_DYN-images-and-PHDRs-for-creating-relocatable.patch b/1098-Use-ET_DYN-images-and-PHDRs-for-creating-relocatable.patch new file mode 100644 index 0000000..6b4d0e7 --- /dev/null +++ b/1098-Use-ET_DYN-images-and-PHDRs-for-creating-relocatable.patch @@ -0,0 +1,985 @@ +From 39e6222ada2224bbad6d12ab63aa8f5ed1f66d84 Mon Sep 17 00:00:00 2001 +From: Fedora Ninjas +Date: Mon, 2 Feb 2026 10:35:14 +0800 +Subject: [PATCH 3/4] Use ET_DYN images and PHDRs for creating relocatable + images + +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 +--- + 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 | 6 +- + grub-core/kern/x86_64/efi/startup.S | 6 +- + include/grub/util/mkimage.h | 3 + + util/grub-mkimagexx.c | 432 +++++++++++++++------------- + 8 files changed, 270 insertions(+), 219 deletions(-) + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 876802d..6aed019 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 .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -R .note.gnu.property -R .gnu.build.attributes ++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 = $(TARGET_CFLAGS) $(CFLAGS_PLATFORM) -ffreestanding + if COND_emu + LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib -Wl,-r,-d + else +-if COND_mips +-LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -shared +-else ++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 + endif + endif + +diff --git a/configure.ac b/configure.ac +index 599f04d..09f3a42 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -918,9 +918,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 +@@ -1481,7 +1478,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" + ;; + *) +@@ -2345,6 +2343,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 694ae6d..34e538b 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 8f2a593..e827e4c 100644 +--- a/grub-core/kern/ia64/efi/startup.S ++++ b/grub-core/kern/ia64/efi/startup.S +@@ -30,8 +30,11 @@ start: + _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 1fdb58a..ec80d10 100644 +--- a/grub-core/kern/mips/startup.S ++++ b/grub-core/kern/mips/startup.S +@@ -74,9 +74,9 @@ 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) + addiu $t1, (GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) +diff --git a/grub-core/kern/x86_64/efi/startup.S b/grub-core/kern/x86_64/efi/startup.S +index 9357e5c..024d47f 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 6f1da89..b840d46 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 5a66363..80c6e79 100644 +--- a/util/grub-mkimagexx.c ++++ b/util/grub-mkimagexx.c +@@ -109,11 +109,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; + }; + + static int +@@ -597,7 +599,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; +@@ -635,11 +637,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; +@@ -649,7 +647,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) +@@ -658,13 +656,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) +@@ -689,10 +685,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 +@@ -776,6 +772,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: +@@ -813,20 +811,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; +@@ -839,7 +837,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; + +@@ -852,7 +850,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)); +@@ -877,7 +874,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, +@@ -931,10 +928,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, +@@ -1005,6 +1016,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: + { +@@ -1046,10 +1061,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, +@@ -1073,11 +1096,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; +@@ -1130,7 +1159,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; +@@ -1177,9 +1206,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: +@@ -1236,6 +1271,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)", +@@ -1246,6 +1290,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. + */ +@@ -1351,6 +1398,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; +@@ -1688,7 +1741,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, +@@ -1714,9 +1770,30 @@ translate_relocation_pe (struct translate_context *ctx, + case R_IA64_GPREL64I: + 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%" +@@ -1741,7 +1818,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, +@@ -1781,6 +1860,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, +@@ -1851,6 +1932,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, +@@ -1869,6 +1952,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 +@@ -1878,6 +1965,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 +@@ -2139,7 +2230,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)) +@@ -2157,8 +2247,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)) +@@ -2170,7 +2258,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); + } +@@ -2254,6 +2342,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)) +@@ -2291,31 +2382,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. +@@ -2327,97 +2393,106 @@ 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 * +@@ -2427,11 +2502,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)); +@@ -2456,53 +2532,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; +- +- 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; +- +- 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; +- 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 +@@ -2516,7 +2562,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; +@@ -2574,16 +2620,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 +@@ -2595,25 +2657,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.47.3 + diff --git a/grub.macros b/grub.macros index f656145..21a65b0 100644 --- a/grub.macros +++ b/grub.macros @@ -344,10 +344,22 @@ git config gc.auto 0 \ rm -f configure \ git add . \ git commit -a -q -m "%{tarversion} baseline." \ -git am --whitespace=nowarn %%{patches} - 1:2.12-23 +- Fix grub relocation overflow error + * Tue Dec 23 2025 Yihao Yan - 1:2.12-22 - Support BOOTRISCV64.EFI -- Gitee From 3afab9b1afc89cd3a9222a21bf8e40fb8c289586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=80=84=E5=87=AF=E8=90=8C00355110?= Date: Wed, 4 Mar 2026 16:13:57 +0800 Subject: [PATCH 2/3] Modify the incorrect patch path --- grub.macros | 9 +++++---- grub2.spec | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/grub.macros b/grub.macros index 21a65b0..672b309 100644 --- a/grub.macros +++ b/grub.macros @@ -344,9 +344,11 @@ git config gc.auto 0 \ rm -f configure \ git add . \ git commit -a -q -m "%{tarversion} baseline." \ +rv_patches="" \ for patch in %%{patches}; do \ patch_basename=$(basename "$patch") \ if echo "$patch_basename" | grep -qE "^(1095|1096|1097|1098)-"; then \ + rv_patches="$rv_patches $patch" \ continue \ fi \ git am --whitespace=nowarn "$patch" - 1:2.12-24 +- Modify the incorrect patch path + * Mon Feb 09 2026 Kaimeng Pang - 1:2.12-23 - Fix grub relocation overflow error -- Gitee From 6b81e97456e8bca7efbc70c4fd5c16322f529115 Mon Sep 17 00:00:00 2001 From: "yan.yihao 10263201" Date: Tue, 9 Jun 2026 19:11:06 +0800 Subject: [PATCH 3/3] fix build error against GCC 14 Upstream: https://github.com/rhboot/grub2/commit/c0e57434158318243675145fd5770ed623512987 https://github.com/rhboot/grub2/commit/654470def1ed57b11921b21f641abb9bc8951456 --- ...veral-implicit-function-declarations.patch | 54 +++++++++++++++++++ ...nore-warnings-for-incompatible-types.patch | 28 ++++++++++ grub.macros | 2 +- grub.patches | 4 ++ grub2.spec | 6 ++- 5 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 1099-core-fix-several-implicit-function-declarations.patch create mode 100644 1100-ignore-warnings-for-incompatible-types.patch diff --git a/1099-core-fix-several-implicit-function-declarations.patch b/1099-core-fix-several-implicit-function-declarations.patch new file mode 100644 index 0000000..d768825 --- /dev/null +++ b/1099-core-fix-several-implicit-function-declarations.patch @@ -0,0 +1,54 @@ +From c0e57434158318243675145fd5770ed623512987 Mon Sep 17 00:00:00 2001 +From: Arjun Shankar +Date: Sun, 5 Feb 2023 11:13:55 +0100 +Subject: [PATCH] core: Fix several implicit function declarations + +These #include lines ensure that grub2 continues to build with C99 +where implicit function declarations are removed. + +Related to: + + + +--- + grub-core/commands/efi/connectefi.c | 1 + + grub-core/net/http.c | 1 + + grub-core/term/at_keyboard.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/grub-core/commands/efi/connectefi.c b/grub-core/commands/efi/connectefi.c +index 0f840ea057..6c397f8f50 100644 +--- a/grub-core/commands/efi/connectefi.c ++++ b/grub-core/commands/efi/connectefi.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index ce2b492c35..40df19426c 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c +index 378deb321d..e667d0a862 100644 +--- a/grub-core/term/at_keyboard.c ++++ b/grub-core/term/at_keyboard.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + diff --git a/1100-ignore-warnings-for-incompatible-types.patch b/1100-ignore-warnings-for-incompatible-types.patch new file mode 100644 index 0000000..ad7dacb --- /dev/null +++ b/1100-ignore-warnings-for-incompatible-types.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nicolas Frayer +Date: Wed, 17 Jan 2024 21:15:14 +0100 +Subject: [PATCH] Ignore warnings for incompatible types + +Add -Wno-incompatible-pointer-types to ignore warnings for incompatible +types + +Signed-off-by: Nicolas Frayer +--- + configure.ac | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/configure.ac b/configure.ac +index d223fe3ef6e..4788f3d6adc 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -2166,8 +2166,8 @@ if test x"$enable_wextra" != xno ; then + HOST_CFLAGS="$HOST_CFLAGS -Wextra" + fi + +-TARGET_CFLAGS="$TARGET_CFLAGS -Werror=trampolines -fno-trampolines" +-HOST_CFLAGS="$HOST_CFLAGS -Werror=trampolines -fno-trampolines" ++TARGET_CFLAGS="$TARGET_CFLAGS -Werror=trampolines -fno-trampolines -Wno-incompatible-pointer-types" ++HOST_CFLAGS="$HOST_CFLAGS -Werror=trampolines -fno-trampolines -Wno-incompatible-pointer-types" + + TARGET_CPP="$TARGET_CC -E" + TARGET_CCAS=$TARGET_CC diff --git a/grub.macros b/grub.macros index 672b309..7675c37 100644 --- a/grub.macros +++ b/grub.macros @@ -347,7 +347,7 @@ git commit -a -q -m "%{tarversion} baseline." \ rv_patches="" \ for patch in %%{patches}; do \ patch_basename=$(basename "$patch") \ - if echo "$patch_basename" | grep -qE "^(1095|1096|1097|1098)-"; then \ + if echo "$patch_basename" | grep -qE "^(1095|1096|1097|1098|1100)-"; then \ rv_patches="$rv_patches $patch" \ continue \ fi \ diff --git a/grub.patches b/grub.patches index eb3d196..0b0b3e0 100644 --- a/grub.patches +++ b/grub.patches @@ -299,6 +299,10 @@ Patch1095: 1095-configure-Defer-check-for-mcmodel-large-until-PIC-PI.patch Patch1096: 1096-Use-ET_DYN-instead-of-ET_REL-modules.patch Patch1097: 1097-loongarch64-Use-la.pcrel-instead-of-la.patch Patch1098: 1098-Use-ET_DYN-images-and-PHDRs-for-creating-relocatable.patch +# https://github.com/rhboot/grub2/commit/c0e57434158318243675145fd5770ed623512987 +Patch1099: 1099-core-fix-several-implicit-function-declarations.patch +# https://github.com/rhboot/grub2/commit/654470def1ed57b11921b21f641abb9bc8951456 +Patch1100: 1100-ignore-warnings-for-incompatible-types.patch # UEFI patches must in last Patch1004: 1004-Revert-Add-support-for-Linux-EFI-stub-loading.patch diff --git a/grub2.spec b/grub2.spec index 417bf9a..f23fb99 100644 --- a/grub2.spec +++ b/grub2.spec @@ -1,4 +1,4 @@ -%define anolis_release 24 +%define anolis_release 25 %global _lto_cflags %{nil} %undefine _hardened_build @@ -510,6 +510,10 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg %endif %changelog +* Tue Jun 09 2026 Yihao Yan - 1:2.12-25 +- core: Fix several implicit function declarations +- ignore warnings for incompatible types + * Mon Mar 02 2026 Kaimeng Pang - 1:2.12-24 - Modify the incorrect patch path -- Gitee