On Tue, 8 Apr 2025 15:16:23 +0000 Vladimir Serbinenko <phco...@gmail.com> wrote:
> 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 <phco...@gmail.com> > --- > conf/Makefile.common | 10 +- > conf/i386-modules.sc | 35 +++ > configure.ac | 39 +-- > .../commands/tpm2_key_protector/tpm2key.c | 7 + > grub-core/genmod.sh.in | 20 +- > grub-core/genmoddep.awk | 2 +- > grub-core/kern/arm/dl.c | 20 +- > grub-core/kern/arm64/dl.c | 22 +- > grub-core/kern/dl.c | 274 ++++++++---------- > grub-core/kern/emu/full.c | 4 +- > grub-core/kern/i386/dl.c | 19 +- > grub-core/kern/ia64/dl.c | 49 +++- > grub-core/kern/loongarch64/dl.c | 20 +- > grub-core/kern/mips/dl.c | 78 ++++- > grub-core/kern/powerpc/dl.c | 15 +- > grub-core/kern/riscv/dl.c | 23 +- > grub-core/kern/sparc64/dl.c | 15 +- > grub-core/kern/x86_64/dl.c | 21 +- > grub-core/lib/backtrace.c | 9 +- > include/grub/dl.h | 33 ++- > include/grub/elf.h | 4 + > util/grub-mkimagexx.c | 2 + > util/grub-module-verifier.c | 30 +- > util/grub-module-verifierXX.c | 56 +++- > 24 files changed, 519 insertions(+), 288 deletions(-) > create mode 100644 conf/i386-modules.sc > > diff --git a/conf/Makefile.common b/conf/Makefile.common > index c60f55386..3e2dff090 100644 > --- a/conf/Makefile.common > +++ b/conf/Makefile.common > @@ -51,7 +51,15 @@ endif > endif > > CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding > -LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) > -Wl,-r > +if COND_emu > +LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib -Wl,-r > +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/modules.sc > +endif > +endif > CPPFLAGS_MODULE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) > CCASFLAGS_MODULE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) > > diff --git a/conf/i386-modules.sc b/conf/i386-modules.sc > new file mode 100644 > index 000000000..aab26e4a1 > --- /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 ad1e7bea5..cdb6a5c41 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -876,16 +876,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 > @@ -1215,6 +1207,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], > @@ -1395,18 +1391,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/commands/tpm2_key_protector/tpm2key.c > b/grub-core/commands/tpm2_key_protector/tpm2key.c > index 3b6001d84..b8d5227dd 100644 > --- a/grub-core/commands/tpm2_key_protector/tpm2key.c > +++ b/grub-core/commands/tpm2_key_protector/tpm2key.c > @@ -39,6 +39,13 @@ asn1_allocate_and_read (asn1_node node, const char *name, > void **content, grub_s > return ASN1_MEM_ERROR; > > ret = asn1_read_value (node, name, NULL, &tmpstr_size); > + if (ret == ASN1_SUCCESS) > + { > + *content = NULL; > + *content_size = 0; > + > + return ASN1_SUCCESS; > + } Am I wrong in thinking that this change was mistakenly added? Glenn > if (ret != ASN1_MEM_ERROR) > return ret; > > diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in > index 337753c57..fb15b6608 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 ab457cb2b..09832ab91 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 eab9d17ff..3d8bd9f9a 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,15 @@ 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 a2b5789a9..7aceff077 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/dl.c b/grub-core/kern/dl.c > index de8c3aa8d..e5fd16bd5 100644 > --- a/grub-core/kern/dl.c > +++ b/grub-core/kern/dl.c > @@ -187,19 +187,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) > @@ -232,35 +219,31 @@ 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; > > - arch_addralign = DL_ALIGN; > - > - 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; > - talign = grub_max (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) && \ > @@ -268,79 +251,48 @@ 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_max (GRUB_ARCH_DL_TRAMP_ALIGN, arch_addralign); > - tsize += ALIGN_UP (tramp, tramp_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, arch_addralign); > - tsize += ALIGN_UP (got, got_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; > - } > +#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 > > - seg->addr = addr; > - } > - else > - seg->addr = 0; > + 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 > > return GRUB_ERR_NONE; > @@ -355,10 +307,42 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) > const char *str; > Elf_Word size, entsize; > > + /* 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. > @@ -390,15 +374,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); > @@ -408,41 +396,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: > @@ -620,26 +599,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; > - > - /* Find the target segment. */ > - for (seg = mod->segment; seg; seg = seg->next) > - if (seg->section == s->sh_info) > - break; > - > - if (seg) > - { > - 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; > } > > return GRUB_ERR_NONE; > @@ -651,7 +618,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) && \ > @@ -661,39 +628,33 @@ 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; > > - for (seg = mod->segment; seg; seg = seg->next) > - /* Does this ELF section's index match GRUB DL segment? */ > - if (seg->section == i) > - break; > - > - /* No GRUB DL segment found for this ELF section, skip it. */ > - if (!seg) > + if (p->p_memsz == 0) > continue; > > - if (seg->size == 0 || !(s->sh_flags & SHF_ALLOC)) > - 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, > + 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; > @@ -746,16 +707,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; > } > > @@ -780,6 +741,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 > || grub_dl_set_mem_attrs (mod, e)) > { > mod->fini = 0; > diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c > index e8d63b1f5..18e1ab346 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 1346da5cc..7c4353bab 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 db59300fe..75b63a79f 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,28 @@ 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; > break; > 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 +143,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 7f923b415..670ca887e 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 5b02f97fc..cda40fd07 100644 > --- a/grub-core/kern/mips/dl.c > +++ b/grub-core/kern/mips/dl.c > @@ -29,6 +29,54 @@ > 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 +144,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 +177,14 @@ 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) > - return grub_error (GRUB_ERR_BAD_MODULE, > - "reloc offset is out of the segment"); > + if (ELF_R_TYPE (rel->r_info) == R_MIPS_NONE) > + continue; > > - addr = (grub_uint8_t *) ((char *) seg->addr + 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: %x not in > [%x..%x]", > + rel->r_offset, mod->min_addr, mod->min_addr + > mod->sz); > + 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 7b6418eab..03cca93f0 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 896653bb4..5b343f342 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 f3d960186..6571edaea 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/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c > index e5a8bdcf4..5cd05039b 100644 > --- a/grub-core/kern/x86_64/dl.c > +++ b/grub-core/kern/x86_64/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) > { > Elf64_Rela *rel, *max; > > @@ -54,11 +54,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, > Elf64_Xword *addr64; > Elf64_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: %lx not in > [%lx..%lx]", > + rel->r_offset, mod->min_addr, mod->min_addr + > mod->sz); > > - addr32 = (Elf64_Word *) ((char *) seg->addr + rel->r_offset); > + addr32 = (Elf64_Word *) ((char *) mod->base + rel->r_offset - > mod->min_addr); > addr64 = (Elf64_Xword *) addr32; > sym = (Elf64_Sym *) ((char *) mod->symtab > + mod->symsize * ELF_R_SYM (rel->r_info)); > @@ -66,7 +67,13 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, > switch (ELF_R_TYPE (rel->r_info)) > { > case R_X86_64_64: > - *addr64 += rel->r_addend + sym->st_value; > + case R_X86_64_GLOB_DAT: > + case R_X86_64_JUMP_SLOT: > + *addr64 = rel->r_addend + sym->st_value; > + break; > + > + case R_X86_64_RELATIVE: > + *addr64 = (grub_addr_t) mod->base - mod->min_addr + rel->r_addend; > break; > > case R_X86_64_PC32: > @@ -74,7 +81,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, > { > grub_int64_t value; > value = ((grub_int32_t) *addr32) + rel->r_addend + sym->st_value - > - (Elf64_Xword) (grub_addr_t) seg->addr - rel->r_offset; > + (Elf64_Xword) (grub_addr_t) addr32; > if (value != (grub_int32_t) value) > return grub_error (GRUB_ERR_BAD_MODULE, "relocation out of > range"); > *addr32 = value; > @@ -84,7 +91,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, > case R_X86_64_PC64: > { > *addr64 += rel->r_addend + sym->st_value - > - (Elf64_Xword) (grub_addr_t) seg->addr - rel->r_offset; > + (Elf64_Xword) (grub_addr_t) addr64; > } > break; > > diff --git a/grub-core/lib/backtrace.c b/grub-core/lib/backtrace.c > index 825a8800e..23f4d18af 100644 > --- a/grub-core/lib/backtrace.c > +++ b/grub-core/lib/backtrace.c > @@ -33,13 +33,10 @@ grub_backtrace_print_address (void *addr) > > FOR_DL_MODULES (mod) > { > - grub_dl_segment_t segment; > - for (segment = mod->segment; segment; segment = segment->next) > - if (segment->addr <= addr && (grub_uint8_t *) segment->addr > - + segment->size > (grub_uint8_t *) addr) > + if (mod->base <= addr && (grub_uint8_t *) mod->base + mod->sz > > (grub_uint8_t *) addr) > { > - grub_printf ("%s.%x+%" PRIxGRUB_SIZE, mod->name, segment->section, > - (grub_size_t) ((grub_uint8_t *) addr - (grub_uint8_t *) > segment->addr)); > + grub_printf ("%s[0x%" PRIxGRUB_SIZE "]", mod->name, > + (grub_size_t) (mod->min_addr + ((grub_uint8_t *) addr - > (grub_uint8_t *) mod->base))); > return; > } > } > diff --git a/include/grub/dl.h b/include/grub/dl.h > index 84509c5c1..b30e9506c 100644 > --- a/include/grub/dl.h > +++ b/include/grub/dl.h > @@ -41,13 +41,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) > @@ -152,15 +152,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 > @@ -177,7 +168,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); > @@ -190,9 +180,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 > @@ -263,12 +260,14 @@ 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); > #endif > > #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 > @@ -281,6 +280,10 @@ grub_err_t > grub_arm64_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 > + > #if defined (__ia64__) > #define GRUB_ARCH_DL_TRAMP_ALIGN GRUB_IA64_DL_TRAMP_ALIGN > #define GRUB_ARCH_DL_GOT_ALIGN GRUB_IA64_DL_GOT_ALIGN > diff --git a/include/grub/elf.h b/include/grub/elf.h > index bd313a70b..fc9148458 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 448862b2e..97e83671a 100644 > --- a/util/grub-mkimagexx.c > +++ b/util/grub-mkimagexx.c > @@ -1410,8 +1410,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; > diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c > index 91d9e8f88..802aa8899 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[]){ > @@ -30,6 +36,8 @@ struct grub_module_verifier_arch archs[] = { > GRUB_ELF_R_PPC_ADDR32, > GRUB_ELF_R_PPC_REL32, > GRUB_ELF_R_PPC_PLTREL24, > + GRUB_ELF_R_PPC_RELATIVE, > + GRUB_ELF_R_PPC_JMP_SLOT, > -1 > } }, > { "sparc64", 8, 1, EM_SPARCV9, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ > @@ -46,6 +54,9 @@ struct grub_module_verifier_arch archs[] = { > usually. */ > R_SPARC_HI22, > R_SPARC_32, > + R_SPARC_RELATIVE, > + R_SPARC_GLOB_DAT, > + R_SPARC_JMP_SLOT, > -1 > } }, > { "ia64", 8, 0, EM_IA_64, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ > @@ -56,7 +67,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 +75,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 +96,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 +119,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[]){ > @@ -111,6 +130,9 @@ struct grub_module_verifier_arch archs[] = { > R_AARCH64_JUMP26, > R_AARCH64_ADR_GOT_PAGE, > R_AARCH64_LD64_GOT_LO12_NC, > + R_AARCH64_RELATIVE, > + R_AARCH64_JUMP_SLOT, > + R_AARCH64_GLOB_DAT, > -1 > }, (int[]){ > R_AARCH64_ADR_PREL_PG_HI21, > @@ -122,6 +144,8 @@ struct grub_module_verifier_arch archs[] = { > { "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 +202,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 +232,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 a42c20bd1..3724f696e 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,19 @@ 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); > } _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel