grub-devel
[Top][All Lists]
Advanced

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

[PATCH v12 09/10] LoongArch: Support new relocation types in v2.00 ABI


From: Xiaotian Wu
Subject: [PATCH v12 09/10] LoongArch: Support new relocation types in v2.00 ABI
Date: Mon, 5 Dec 2022 18:48:21 +0800

Link: https://github.com/loongson/LoongArch-Documentation/pull/57
Signed-off-by: Xiaotian Wu <wuxiaotian@loongson.cn>
---
 configure.ac                           | 17 ++++----
 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, 187 insertions(+), 12 deletions(-)

diff --git a/configure.ac b/configure.ac
index 575cd0c17..08a1df527 100644
--- a/configure.ac
+++ b/configure.ac
@@ -864,17 +864,18 @@ 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 -Wa,-mla-global-with-abs works], 
[grub_cv_cc_mla_global_with_abs], [
-    CFLAGS="$TARGET_CFLAGS -Wa,-mla-global-with-abs -Werror"
+  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_mla_global_with_abs=yes],
-       [grub_cv_cc_mla_global_with_abs=no])
+       [grub_cv_cc_mno_explicit_relocs=yes],
+       [grub_cv_cc_mno_explicit_relocs=no])
   ])
-
-  if test "x$grub_cv_cc_mla_global_with_abs" = xyes; then
-    TARGET_CFLAGS="$TARGET_CFLAGS -Wa,-mla-global-with-abs"
-    TARGET_CCASFLAGS="$TARGET_CCASFLAGS -Wa,-mla-global-with-abs"
+  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
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 358b9ab47..baf3a472d 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"),
@@ -1736,6 +1776,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.38.1




reply via email to

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