]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
LoongArch: Fix resolution of undefined weak hidden/protected symbols
authorXi Ruoyao <xry111@xry111.site>
Wed, 25 Dec 2024 04:41:43 +0000 (12:41 +0800)
committercailulu <cailulu@loongson.cn>
Fri, 27 Dec 2024 09:52:29 +0000 (17:52 +0800)
An undefined weak hidden/protect symbol should be resolved to runtime
address 0, but we were actually resolving it to link-time address 0.  So
in PIE or DSO the runtime address would be incorrect.

Fix the issue by rewriting pcalau12i to lu12i.w, and pcaddi to addi.w.
The latter does not always work because the immediate field of addi.w is
narrower, report an error in the case the addend is too large.

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
bfd/elfnn-loongarch.c
include/opcode/loongarch.h
ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
ld/testsuite/ld-loongarch-elf/weak-undef-hidden-pie.d [new file with mode: 0644]
ld/testsuite/ld-loongarch-elf/weak-undef-hidden-shared.d [new file with mode: 0644]
ld/testsuite/ld-loongarch-elf/weak-undef-hidden.s [new file with mode: 0644]

index 995d67c0b781816006d094652278ecb67e100fba..4cf1512cefe86735d7ac08ca7f1f12b6c0aaeedf 100644 (file)
@@ -3251,6 +3251,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
       char tls_type;
       bfd_vma relocation, off, ie_off, desc_off;
       int i, j;
+      bool resolve_pcrel_undef_weak = false;
 
       /* When an unrecognized relocation is encountered, which usually
         occurs when using a newer assembler but an older linker, an error
@@ -4102,23 +4103,74 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
          break;
 
+       case R_LARCH_PCALA64_HI12:
+         pc -= 4;
+         /* Fall through.  */
+       case R_LARCH_PCALA64_LO20:
+         pc -= 8;
+         /* Fall through.  */
        case R_LARCH_PCREL20_S2:
-         unresolved_reloc = false;
-         if (h && h->plt.offset != MINUS_ONE)
-           relocation = sec_addr (plt) + h->plt.offset;
-         else
-           relocation += rel->r_addend;
-         relocation -= pc;
-         break;
-
        case R_LARCH_PCALA_HI20:
          unresolved_reloc = false;
+
+         /* If sym is hidden undefined weak, (sym + addend) should be
+            resolved to runtime address (0 + addend).  */
+         resolve_pcrel_undef_weak =
+           (is_undefweak
+            && h
+            && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT);
+
+         if (resolve_pcrel_undef_weak)
+           pc = 0;
+
          if (h && h->plt.offset != MINUS_ONE)
            relocation = sec_addr (plt) + h->plt.offset;
          else
            relocation += rel->r_addend;
 
-         RELOCATE_CALC_PC32_HI20 (relocation, pc);
+         switch (r_type)
+           {
+           case R_LARCH_PCREL20_S2:
+             relocation -= pc;
+             if (resolve_pcrel_undef_weak)
+               {
+                 bfd_signed_vma addr = (bfd_signed_vma) relocation;
+                 if (addr >= 2048 || addr < -2048)
+                   {
+                     const char *msg =
+                       _("cannot resolve R_LARCH_PCREL20_S2 against "
+                         "undefined weak symbol with addend out of "
+                         "[-2048, 2048)");
+                     fatal =
+                       loongarch_reloc_is_fatal (info, input_bfd,
+                                                 input_section, rel,
+                                                 howto,
+                                                 bfd_reloc_notsupported,
+                                                 is_undefweak, name, msg);
+                     break;
+                   }
+
+                 uint32_t insn = bfd_get (32, input_bfd,
+                                          contents + rel->r_offset);
+                 insn = LARCH_GET_RD (insn) | LARCH_OP_ADDI_W;
+                 insn |= (relocation & 0xfff) << 10;
+                 bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+                 r = bfd_reloc_continue;
+               }
+             break;
+           case R_LARCH_PCALA_HI20:
+             RELOCATE_CALC_PC32_HI20 (relocation, pc);
+             if (resolve_pcrel_undef_weak)
+               {
+                 uint32_t insn = bfd_get (32, input_bfd,
+                                          contents + rel->r_offset);
+                 insn = LARCH_GET_RD (insn) | LARCH_OP_LU12I_W;
+                 bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+               }
+             break;
+           default:
+             RELOCATE_CALC_PC64_HI32 (relocation, pc);
+           }
          break;
 
        case R_LARCH_TLS_LE_HI20_R:
@@ -4155,19 +4207,6 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
            }
          break;
 
-       case R_LARCH_PCALA64_HI12:
-         pc -= 4;
-         /* Fall through.  */
-       case R_LARCH_PCALA64_LO20:
-         if (h && h->plt.offset != MINUS_ONE)
-           relocation = sec_addr (plt) + h->plt.offset;
-         else
-           relocation += rel->r_addend;
-
-         RELOCATE_CALC_PC64_HI32 (relocation, pc - 8);
-
-         break;
-
        case R_LARCH_GOT_PC_HI20:
        case R_LARCH_GOT_HI20:
          /* Calc got offset.  */
index 493fe9bcce3f5d3f40622f6ed4ce227923f3647a..35799696c5567903d65c0fb94e436822d079d326 100644 (file)
@@ -36,6 +36,7 @@ extern "C"
 
   #define LARCH_MK_ADDI_D 0xffc00000
   #define LARCH_OP_ADDI_D 0x02c00000
+  #define LARCH_OP_ADDI_W 0x02800000
   #define LARCH_MK_PCADDI 0xfe000000
   #define LARCH_OP_PCADDI 0x18000000
   #define LARCH_MK_B 0xfc000000
@@ -44,6 +45,7 @@ extern "C"
   #define LARCH_OP_BL 0x54000000
   #define LARCH_MK_ORI 0xffc00000
   #define LARCH_OP_ORI 0x03800000
+  #define LARCH_OP_OR 0x00150000
   #define LARCH_MK_LU12I_W 0xfe000000
   #define LARCH_OP_LU12I_W 0x14000000
   #define LARCH_MK_LD_D 0xffc00000
index 004c1994673893771b94bd855fa97ec1fdc3e850..35a3a4fc4307e2e85b80a076a00dd40dec8611d8 100644 (file)
@@ -184,6 +184,7 @@ if [istarget "loongarch64-*-*"] {
     run_dump_test "bad_pcala_hi20_weak_pie"
     run_dump_test "bad_pcrel20_s2_global"
     run_dump_test "bad_pcrel20_s2_weak"
+    run_dump_test "weak-undef-hidden-shared"
   }
 
   if [check_pie_support] {
@@ -194,6 +195,7 @@ if [istarget "loongarch64-*-*"] {
     run_dump_test "relr-got-start"
     run_dump_test "relr-text-pie"
     run_dump_test "abssym_pie"
+    run_dump_test "weak-undef-hidden-pie"
   }
 
   run_dump_test "max_imm_b16"
diff --git a/ld/testsuite/ld-loongarch-elf/weak-undef-hidden-pie.d b/ld/testsuite/ld-loongarch-elf/weak-undef-hidden-pie.d
new file mode 100644 (file)
index 0000000..913bc96
--- /dev/null
@@ -0,0 +1,14 @@
+#source: weak-undef-hidden.s
+#ld: -pie -Ttext=0x1111222233334ff0
+#objdump: -d
+
+#...
+1111222233334ff0:[     ]+159999a4[     ]+lu12i.w[      ]+\$a0,[        ]+-209715
+1111222233334ff4:[     ]+02f77405[     ]+li.d[         ]+\$a1,[        ]+-547
+1111222233334ff8:[     ]+17777765[     ]+lu32i.d[      ]+\$a1,[        ]+-279621
+1111222233334ffc:[     ]+032aa8a5[     ]+lu52i.d[      ]+\$a1,[        ]+\$a1,[        ]+-1366
+1111222233335000:[     ]+00109484[     ]+add.d[        ]+\$a0,[        ]+\$a0,[        ]+\$a1
+1111222233335004:[     ]+029ffc06[     ]+li.w[         ]+\$a2,[        ]+2047
+1111222233335008:[     ]+02a00007[     ]+li.w[         ]+\$a3,[        ]+-2048
+111122223333500c:[     ]+4c000020[     ]+ret
+#pass
diff --git a/ld/testsuite/ld-loongarch-elf/weak-undef-hidden-shared.d b/ld/testsuite/ld-loongarch-elf/weak-undef-hidden-shared.d
new file mode 100644 (file)
index 0000000..fdb215e
--- /dev/null
@@ -0,0 +1,14 @@
+#source: weak-undef-hidden.s
+#ld: -shared -Ttext=0x1111222233334ff0
+#objdump: -d
+
+#...
+1111222233334ff0:[     ]+159999a4[     ]+lu12i.w[      ]+\$a0,[        ]+-209715
+1111222233334ff4:[     ]+02f77405[     ]+li.d[         ]+\$a1,[        ]+-547
+1111222233334ff8:[     ]+17777765[     ]+lu32i.d[      ]+\$a1,[        ]+-279621
+1111222233334ffc:[     ]+032aa8a5[     ]+lu52i.d[      ]+\$a1,[        ]+\$a1,[        ]+-1366
+1111222233335000:[     ]+00109484[     ]+add.d[        ]+\$a0,[        ]+\$a0,[        ]+\$a1
+1111222233335004:[     ]+029ffc06[     ]+li.w[         ]+\$a2,[        ]+2047
+1111222233335008:[     ]+02a00007[     ]+li.w[         ]+\$a3,[        ]+-2048
+111122223333500c:[     ]+4c000020[     ]+ret
+#pass
diff --git a/ld/testsuite/ld-loongarch-elf/weak-undef-hidden.s b/ld/testsuite/ld-loongarch-elf/weak-undef-hidden.s
new file mode 100644 (file)
index 0000000..ac67007
--- /dev/null
@@ -0,0 +1,9 @@
+.weak undef
+.hidden undef
+
+.globl _start
+_start:
+  la.pcrel $a0, $a1, undef + 0xaaabbbbbcccccddd
+  pcaddi   $a2, undef + 0x7ff
+  pcaddi   $a3, undef - 0x800
+  ret