grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v15 06/10] LoongArch: Add support for ELF psABI v2.00 relocations


From: Xiaotian Wu
Subject: [PATCH v15 06/10] LoongArch: Add support for ELF psABI v2.00 relocations
Date: Tue, 18 Apr 2023 20:04:13 +0800

A new set of relocation types was added in the LoongArch ELF psABI v2.00
spec [1][2] to replace the stack-based scheme in v1.00. Toolchain
support is available from binutils 2.40 and gcc 13 onwards.

This patch adds support for the new relocation types, that are simpler
to handle (in particular, stack operations are gone). Support for the
v1.00 relocs are kept for now, for compatibility with older toolchains.

[1]: https://github.com/loongson/LoongArch-Documentation/pull/57
[2]: 
https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html#_appendix_revision_history

Signed-off-by: Xiaotian Wu <wuxiaotian@loongson.cn>
---
 configure.ac                           | 15 +++++++
 grub-core/kern/loongarch64/dl.c        | 54 +++++++++++++++++++++--
 grub-core/kern/loongarch64/dl_helper.c | 59 ++++++++++++++++++++++++++
 include/grub/elf.h                     |  7 +++
 include/grub/loongarch64/reloc.h       |  6 +++
 util/grub-mkimagexx.c                  | 49 ++++++++++++++++++++-
 util/grub-module-verifier.c            |  7 +++
 7 files changed, 193 insertions(+), 4 deletions(-)

diff --git a/configure.ac b/configure.ac
index ca42ff8f7..1ded95ca3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -860,6 +860,21 @@ if ( test "x$target_cpu" = xi386 || test "x$target_cpu" = 
xx86_64 ); then
   fi
 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 -Wa,-mla-global-with-abs"
+  TARGET_CCASFLAGS="$TARGET_CCASFLAGS -Wa,-mla-global-with-abs"
+fi
+
 # GRUB doesn't use float or doubles at all. Yet some toolchains may decide
 # that floats are a good fit to run instead of what's written in the code.
 # Given that floating point unit is disabled (if present to begin with)
diff --git a/grub-core/kern/loongarch64/dl.c b/grub-core/kern/loongarch64/dl.c
index 3a6aa91cd..47196a219 100644
--- a/grub-core/kern/loongarch64/dl.c
+++ b/grub-core/kern/loongarch64/dl.c
@@ -58,7 +58,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
        rel = (Elf_Rel *) ((char *) rel + s->sh_entsize))
     {
       Elf_Sym *sym;
-      grub_uint64_t *place;
+      void *place;
       grub_uint64_t sym_addr;
 
       if (rel->r_offset >= seg->size)
@@ -72,12 +72,19 @@ 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 = (grub_uint64_t *) ((grub_addr_t)seg->addr + rel->r_offset);
+      place = (void *) ((grub_addr_t)seg->addr + rel->r_offset);
 
       switch (ELF_R_TYPE (rel->r_info))
        {
        case R_LARCH_64:
-         *place = sym_addr;
+         {
+           grub_uint64_t *abs_place = place;
+
+           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;
+         }
          break;
        case R_LARCH_MARK_LA:
          break;
@@ -85,6 +92,47 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
        case R_LARCH_SOP_PUSH_PLT_PCREL:
          grub_loongarch64_sop_push (&stack, sym_addr - (grub_uint64_t)place);
          break;
+       case R_LARCH_B26:
+         {
+           grub_uint32_t *abs_place = place;
+           grub_ssize_t off = sym_addr - (grub_addr_t) place;
+
+           grub_loongarch64_b26 (abs_place, off);
+         }
+         break;
+       case R_LARCH_ABS_HI20:
+         {
+           grub_uint32_t *abs_place = place;
+           grub_loongarch64_xxx_hi20 (abs_place, sym_addr);
+         }
+         break;
+       case R_LARCH_ABS64_LO20:
+         {
+           grub_uint32_t *abs_place = place;
+           grub_loongarch64_xxx64_lo20 (abs_place, sym_addr);
+         }
+         break;
+       case R_LARCH_ABS64_HI12:
+         {
+           grub_uint32_t *abs_place = place;
+           grub_loongarch64_xxx64_hi12 (abs_place, sym_addr);
+         }
+         break;
+       case R_LARCH_PCALA_HI20:
+         {
+           grub_uint32_t *abs_place = place;
+           grub_int32_t off = (((sym_addr + 0x800) & ~0xfffULL) - 
((grub_addr_t)place & ~0xfffULL));
+
+           grub_loongarch64_xxx_hi20 (abs_place, off);
+         }
+         break;
+       case R_LARCH_ABS_LO12:
+       case R_LARCH_PCALA_LO12:
+         {
+           grub_uint32_t *abs_place = place;
+           grub_loongarch64_xxx_lo12 (abs_place, sym_addr);
+         }
+         break;
        GRUB_LOONGARCH64_RELOCATION (&stack, place, sym_addr)
        default:
          {
diff --git a/grub-core/kern/loongarch64/dl_helper.c 
b/grub-core/kern/loongarch64/dl_helper.c
index 627d1fff2..c15cd739f 100644
--- a/grub-core/kern/loongarch64/dl_helper.c
+++ b/grub-core/kern/loongarch64/dl_helper.c
@@ -200,3 +200,62 @@ grub_loongarch64_sop_32_s_0_10_10_16_s2 
(grub_loongarch64_stack_t stack,
   *place =(*place) | (((a >> 2) & 0xffff) << 10);
   *place =(*place) | ((a >> 18) & 0x3ff);
 }
+
+void grub_loongarch64_b26 (grub_uint32_t *place, grub_int64_t offset)
+{
+  grub_uint32_t val;
+  const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xfc000000);
+
+  grub_dprintf ("dl", "  reloc_xxxx64 %p %c= 0x%llx\n",
+               place, offset > 0 ? '+' : '-',
+               offset < 0 ? (long long) -(unsigned long long) offset : offset);
+
+  val = ((offset >> 18) & 0x3ff) | (((offset >> 2) & 0xffff) << 10);
+
+  *place &= insmask;
+  *place |= grub_cpu_to_le32 (val) & ~insmask;
+}
+
+void grub_loongarch64_xxx_hi20 (grub_uint32_t *place, grub_int64_t offset)
+{
+  const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xfe00001f);
+  grub_uint32_t val;
+
+  offset >>= 12;
+  val = ((offset & 0xfffff) << 5);
+
+  *place &= insmask;
+  *place |= grub_cpu_to_le32 (val) & ~insmask;
+}
+
+void grub_loongarch64_xxx_lo12 (grub_uint32_t *place, grub_int64_t offset)
+{
+  const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xffc003ff);
+
+  *place &= insmask;
+  *place |= grub_cpu_to_le32 (offset << 10) & ~insmask;
+}
+
+void grub_loongarch64_xxx64_hi12 (grub_uint32_t *place, grub_int64_t offset)
+{
+  const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xffc003ff);
+  grub_uint32_t val;
+
+  offset >>= 52;
+  val = ((offset & 0xfff) << 10);
+
+  *place &= insmask;
+  *place |= grub_cpu_to_le32 (val) & ~insmask;
+}
+
+void grub_loongarch64_xxx64_lo20 (grub_uint32_t *place, grub_int64_t offset)
+{
+  const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xfe00001f);
+  grub_uint32_t val;
+
+  offset >>= 32;
+  val = ((offset & 0xfffff) << 5);
+
+  *place &= insmask;
+  *place |= grub_cpu_to_le32 (val) & ~insmask;
+}
diff --git a/include/grub/elf.h b/include/grub/elf.h
index c36d7dab2..bd313a70b 100644
--- a/include/grub/elf.h
+++ b/include/grub/elf.h
@@ -2558,6 +2558,13 @@ typedef Elf32_Addr Elf32_Conflict;
 #define R_LARCH_SOP_POP_32_S_5_20            43
 #define R_LARCH_SOP_POP_32_S_0_5_10_16_S2     44
 #define R_LARCH_SOP_POP_32_S_0_10_10_16_S2    45
+#define R_LARCH_B26                          66
+#define R_LARCH_ABS_HI20                     67
+#define R_LARCH_ABS_LO12                     68
+#define R_LARCH_ABS64_LO20                   69
+#define R_LARCH_ABS64_HI12                   70
+#define R_LARCH_PCALA_HI20                   71
+#define R_LARCH_PCALA_LO12                   72
 
 extern grub_err_t grub_elf32_get_shnum (Elf32_Ehdr *e, Elf32_Shnum *shnum);
 extern grub_err_t grub_elf32_get_shstrndx (Elf32_Ehdr *e, Elf32_Word 
*shstrndx);
diff --git a/include/grub/loongarch64/reloc.h b/include/grub/loongarch64/reloc.h
index 0b7d66ddc..2106ba22c 100644
--- a/include/grub/loongarch64/reloc.h
+++ b/include/grub/loongarch64/reloc.h
@@ -57,6 +57,12 @@ void grub_loongarch64_sop_32_s_0_5_10_16_s2  
(grub_loongarch64_stack_t stack,
 void grub_loongarch64_sop_32_s_0_10_10_16_s2 (grub_loongarch64_stack_t stack,
                                              grub_uint64_t *place);
 
+void grub_loongarch64_b26        (grub_uint32_t *place, grub_int64_t offset);
+void grub_loongarch64_xxx_hi20   (grub_uint32_t *place, grub_int64_t offset);
+void grub_loongarch64_xxx_lo12   (grub_uint32_t *place, grub_int64_t offset);
+void grub_loongarch64_xxx64_hi12  (grub_uint32_t *place, grub_int64_t offset);
+void grub_loongarch64_xxx64_lo20  (grub_uint32_t *place, grub_int64_t offset);
+
 #define GRUB_LOONGARCH64_RELOCATION(STACK, PLACE, OFFSET)      \
   case R_LARCH_SOP_PUSH_ABSOLUTE:                              \
     grub_loongarch64_sop_push (STACK, OFFSET);                 \
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
index 76d07fe33..e7d5bc631 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -1128,11 +1128,20 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct 
section_metadata *smd,
               }
             case EM_LOONGARCH:
               {
+                grub_int64_t pc;
+
+                grub_uint32_t *t32 = (grub_uint32_t *) target;
                 sym_addr += addend;
+
+                pc = offset + target_section_addr + image_target->vaddr_offset;
+
                 switch (ELF_R_TYPE (info))
                   {
                   case R_LARCH_64:
-                    *target = grub_host_to_target64 (grub_target_to_host64 
(*target) + sym_addr);
+                    {
+                      grub_uint64_t *t64 = (grub_uint64_t *) target;
+                      *t64 = grub_host_to_target64 (grub_target_to_host64 
(*t64) + sym_addr);
+                    }
                     break;
                   case R_LARCH_MARK_LA:
                     break;
@@ -1143,6 +1152,37 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct 
section_metadata *smd,
                                                  +offset
                                                  +image_target->vaddr_offset));
                     break;
+                  case R_LARCH_B26:
+                    {
+                      grub_int64_t off;
+
+                      off = sym_addr - target_section_addr - offset - 
image_target->vaddr_offset;
+
+                      grub_loongarch64_b26 (t32, off);
+                    }
+                    break;
+                  case R_LARCH_ABS_HI20:
+                    grub_loongarch64_xxx_hi20 (t32, sym_addr);
+                    break;
+                  case R_LARCH_ABS64_LO20:
+                    grub_loongarch64_xxx64_lo20 (t32, sym_addr);
+                    break;
+                  case R_LARCH_ABS64_HI12:
+                    grub_loongarch64_xxx64_hi12 (t32, sym_addr);
+                    break;
+                  case R_LARCH_PCALA_HI20:
+                    {
+                      grub_int32_t hi20;
+
+                      hi20 = (((sym_addr + 0x800) & ~0xfffULL) - (pc & 
~0xfffULL));
+
+                      grub_loongarch64_xxx_hi20 (t32, hi20);
+                    }
+                    break;
+                  case R_LARCH_ABS_LO12:
+                  case R_LARCH_PCALA_LO12:
+                    grub_loongarch64_xxx_lo12 (t32, sym_addr);
+                    break;
                   GRUB_LOONGARCH64_RELOCATION (&stack, target, sym_addr)
                   default:
                     grub_util_error (_("relocation 0x%x is not implemented 
yet"),
@@ -1737,6 +1777,13 @@ translate_relocation_pe (struct translate_context *ctx,
        case R_LARCH_SOP_POP_32_S_5_20:
        case R_LARCH_SOP_POP_32_S_0_5_10_16_S2:
        case R_LARCH_SOP_POP_32_S_0_10_10_16_S2:
+       case R_LARCH_B26:
+       case R_LARCH_ABS_HI20:
+       case R_LARCH_ABS_LO12:
+       case R_LARCH_ABS64_LO20:
+       case R_LARCH_ABS64_HI12:
+       case R_LARCH_PCALA_HI20:
+       case R_LARCH_PCALA_LO12:
          grub_util_info ("  %s:  not adding fixup: 0x%08x : 0x%08x",
                          __FUNCTION__,
                          (unsigned int) addr,
diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c
index b510461fa..91d9e8f88 100644
--- a/util/grub-module-verifier.c
+++ b/util/grub-module-verifier.c
@@ -140,6 +140,13 @@ struct grub_module_verifier_arch archs[] = {
       R_LARCH_SOP_POP_32_S_5_20,
       R_LARCH_SOP_POP_32_S_0_5_10_16_S2,
       R_LARCH_SOP_POP_32_S_0_10_10_16_S2,
+      R_LARCH_B26,
+      R_LARCH_ABS_HI20,
+      R_LARCH_ABS_LO12,
+      R_LARCH_ABS64_LO20,
+      R_LARCH_ABS64_HI12,
+      R_LARCH_PCALA_HI20,
+      R_LARCH_PCALA_LO12,
       -1
     }, (int[]){
       -1
-- 
2.39.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]