]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
LoongArch: Force relocation for every reference to the global offset table
authorLulu Cai <cailulu@loongson.cn>
Thu, 17 Oct 2024 07:08:47 +0000 (15:08 +0800)
committerliuzhensong <liuzhensong@loongson.cn>
Tue, 22 Oct 2024 04:01:41 +0000 (12:01 +0800)
Local absolute symbols are resolved at assembly stage and the symbol
value is placed in the relocation addend. But non-zero addend will
cause an assertion failure during linking.

Forces emission of relocations to defer resolution of local abs symbols
until link time.

bfd/

        * elfnn-loongarch.c (loongarch_elf_relax_section): Determine
          absolute symbols in advance to avoid ld crash.

gas/

        * config/tc-loongarch.c (loongarch_force_relocation): New
          function to force relocation.
        * config/tc-loongarch.h (TC_FORCE_RELOCATION): New macros
          to force relocation.
        (loongarch_force_relocation): Function declaration.
        * testsuite/gas/loongarch/localpic.d: New test.
        * testsuite/gas/loongarch/localpic.s: New test.

bfd/elfnn-loongarch.c
gas/config/tc-loongarch.c
gas/config/tc-loongarch.h
gas/testsuite/gas/loongarch/localpic.d [new file with mode: 0644]
gas/testsuite/gas/loongarch/localpic.s [new file with mode: 0644]

index 3b1a6a4f95ac06d6a33ec3c99d4cb4553c94f700..2486aa9500e01de6597029a7a178f58c69ec1ee8 100644 (file)
@@ -5350,7 +5350,6 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
       bfd_vma symval;
       asection *sym_sec;
       bool local_got = false;
-      bool is_abs_symbol = false;
       Elf_Internal_Rela *rel = relocs + i;
       struct elf_link_hash_entry *h = NULL;
       unsigned long r_type = ELFNN_R_TYPE (rel->r_info);
@@ -5456,8 +5455,9 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
          Elf_Internal_Sym *sym = (Elf_Internal_Sym *)symtab_hdr->contents
                                    + r_symndx;
 
-         if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
-             && r_type != R_LARCH_CALL36)
+         if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+              && r_type != R_LARCH_CALL36)
+             || sym->st_shndx == SHN_ABS)
            continue;
 
          /* Only TLS instruction sequences that are accompanied by
@@ -5486,12 +5486,13 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
              symval = sym->st_value;
            }
          symtype = ELF_ST_TYPE (sym->st_info);
-         is_abs_symbol = sym->st_shndx == SHN_ABS;
        }
       else
        {
-         if (h != NULL && h->type == STT_GNU_IFUNC
-             && r_type != R_LARCH_CALL36)
+         if (h != NULL
+             && ((h->type == STT_GNU_IFUNC
+                  && r_type != R_LARCH_CALL36)
+                 || bfd_is_abs_section (h->root.u.def.section)))
            continue;
 
          /* The GOT entry of tls symbols must in current execute file or
@@ -5533,7 +5534,6 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
          else
            continue;
 
-         is_abs_symbol = bfd_is_abs_section (h->root.u.def.section);
          if (h && LARCH_REF_LOCAL (info, h))
            local_got = true;
          symtype = h->type;
@@ -5566,7 +5566,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
 
       symval += sec_addr (sym_sec);
 
-      if (r_type == R_LARCH_GOT_PC_HI20 && (!local_got || is_abs_symbol))
+      if (r_type == R_LARCH_GOT_PC_HI20 && !local_got)
        continue;
 
       if (relax_func (abfd, sec, sym_sec, rel, symval,
index eee2badcdca8241dd8e3c0eb790c2afe5378cd1d..ab98a83e6f8d98b5795f4ff89273890b87c1a4e1 100644 (file)
@@ -1456,6 +1456,30 @@ md_pcrel_from (fixS *fixP ATTRIBUTE_UNUSED)
   return 0;
 }
 
+/* Return 1 if the relocation must be forced, and 0 if the relocation
+   should never be forced.  */
+int
+loongarch_force_relocation (struct fix *fixp)
+{
+  /* Ensure we emit a relocation for every reference to the global
+     offset table.  */
+  switch (fixp->fx_r_type)
+    {
+      case BFD_RELOC_LARCH_GOT_PC_HI20:
+      case BFD_RELOC_LARCH_GOT_PC_LO12:
+      case BFD_RELOC_LARCH_GOT64_PC_LO20:
+      case BFD_RELOC_LARCH_GOT64_PC_HI12:
+      case BFD_RELOC_LARCH_GOT_HI20:
+      case BFD_RELOC_LARCH_GOT_LO12:
+      case BFD_RELOC_LARCH_GOT64_LO20:
+      case BFD_RELOC_LARCH_GOT64_HI12:
+       return 1;
+      default:
+       break;
+    }
+  return generic_force_reloc (fixp);
+}
+
 static void fix_reloc_insn (fixS *fixP, bfd_vma reloc_val, char *buf)
 {
   reloc_howto_type *howto;
index 64d95e44277af7b1a01431fe8345ea684bdadf71..b815ebbef6e0f82b09343b8121669d30761caa50 100644 (file)
@@ -74,6 +74,9 @@ extern bool loongarch_frag_align_code (int, int);
    relaxation, so do not resolve such expressions in the assembler.  */
 #define md_allow_local_subtract(l,r,s) 0
 
+#define TC_FORCE_RELOCATION(FIX) loongarch_force_relocation (FIX)
+extern int loongarch_force_relocation (struct fix *);
+
 /* If subsy of BFD_RELOC32/64 and PC in same segment, and without relax
    or PC at start of subsy or with relax but sub_symbol_segment not in
    SEC_CODE, we generate 32/64_PCREL.  */
diff --git a/gas/testsuite/gas/loongarch/localpic.d b/gas/testsuite/gas/loongarch/localpic.d
new file mode 100644 (file)
index 0000000..bea1957
--- /dev/null
@@ -0,0 +1,22 @@
+#as:
+#readelf: -rWs
+#name: loongarch64 local PIC
+
+Relocation section '.rela.text' at offset 0x[0-9a-f]+ contains 12 entries:
+    Offset             Info             Type               Symbol's Value  Symbol's Name \+ Addend
+[0-9a-f]+  [0-9a-f]+ R_LARCH_GOT_PC_HI20    [0-9a-f]+ sym \+ 0
+[0-9a-f]+  [0-9a-f]+ R_LARCH_GOT_PC_LO12    [0-9a-f]+ sym \+ 0
+[0-9a-f]+  [0-9a-f]+ R_LARCH_GOT_PC_HI20    [0-9a-f]+ foo \+ 0
+[0-9a-f]+  [0-9a-f]+ R_LARCH_GOT_PC_LO12    [0-9a-f]+ foo \+ 0
+[0-9a-f]+  [0-9a-f]+ R_LARCH_GOT64_PC_LO20  [0-9a-f]+ foo \+ 0
+[0-9a-f]+  [0-9a-f]+ R_LARCH_GOT64_PC_HI12  [0-9a-f]+ foo \+ 0
+[0-9a-f]+  [0-9a-f]+ R_LARCH_GOT_HI20       [0-9a-f]+ foo \+ 0
+[0-9a-f]+  [0-9a-f]+ R_LARCH_GOT_LO12       [0-9a-f]+ foo \+ 0
+[0-9a-f]+  [0-9a-f]+ R_LARCH_GOT_HI20       [0-9a-f]+ sym \+ 0
+[0-9a-f]+  [0-9a-f]+ R_LARCH_GOT_LO12       [0-9a-f]+ sym \+ 0
+[0-9a-f]+  [0-9a-f]+ R_LARCH_GOT64_LO20     [0-9a-f]+ sym \+ 0
+[0-9a-f]+  [0-9a-f]+ R_LARCH_GOT64_HI12     [0-9a-f]+ sym \+ 0
+#...
+     +[0-9a-f]+: +[0-9a-f]+     0 NOTYPE  LOCAL  DEFAULT    +[0-9a-f]+ foo
+     +[0-9a-f]+: 0+abba     0 NOTYPE  LOCAL  DEFAULT  ABS sym
+#pass
diff --git a/gas/testsuite/gas/loongarch/localpic.s b/gas/testsuite/gas/loongarch/localpic.s
new file mode 100644 (file)
index 0000000..55548e4
--- /dev/null
@@ -0,0 +1,26 @@
+.text
+foo:
+  .quad 0
+  # 32-bit PC-relative
+  pcalau12i $a0,%got_pc_hi20(sym)
+  ld.d     $a0,$a0,%got_pc_lo12(sym)
+  # 64-bit PC-relative
+  pcalau12i $a0,%got_pc_hi20(foo)
+  addi.d    $a1,$zero,%got_pc_lo12(foo)
+  lu32i.d   $a1,%got64_pc_lo20(foo)
+  lu52i.d   $a1,$a1,%got64_pc_hi12(foo)
+  ldx.d            $a0,$a0,$a1
+
+  # 32-bit absolute
+  lu12i.w   $a0,%got_hi20(foo)
+  ori      $a0,$a0,%got_lo12(foo)
+  ld.w     $a0,$a0,0
+
+  #64-bit absolute
+  lu12i.w   $a0,%got_hi20(sym)
+  ori      $a0,$a0,%got_lo12(sym)
+  lu32i.d   $a0,%got64_lo20(sym)
+  lu52i.d   $a0,$a0,%got64_hi12(sym)
+  ld.d     $a0,$a0,0
+
+.set sym,0xabba