ET_REL images contain lots of complicated relocations. One new relocation
we need to support is R_LARCH_GOT_PC_HI20/LO12. Rather than the eternal chasing
of complicated we can use linker to handle them and then only relatively
simple dynamic relocs remain to handle.

This required small adjustments to the asm code to be compatible with
-shared.

Signed-off-by: Vladimir Serbinenko <phco...@gmail.com>
---
 conf/Makefile.common                |   8 +-
 configure.ac                        |   7 +-
 grub-core/Makefile.core.def         |  20 +-
 grub-core/kern/ia64/efi/startup.S   |   7 +-
 grub-core/kern/mips/startup.S       |   4 +-
 grub-core/kern/x86_64/efi/startup.S |   6 +-
 include/grub/util/mkimage.h         |   3 +
 util/grub-mkimagexx.c               | 451 +++++++++++++++-------------
 8 files changed, 270 insertions(+), 236 deletions(-)

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


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to