[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH 1/3] Use ET_DYN instead of ET_REL modules
From: |
Glenn Washburn |
Subject: |
Re: [PATCH 1/3] Use ET_DYN instead of ET_REL modules |
Date: |
Wed, 23 Apr 2025 17:36:05 -0500 |
On Tue, 8 Apr 2025 15:16:23 +0000
Vladimir Serbinenko <phcoder@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 <phcoder@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);
> }