]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
LoongArch: Adapt R_LARCH_{PCALA,GOT,TLS_IE,TLS_DESC}64_* handling per psABI v2.30
authorXi Ruoyao <xry111@xry111.site>
Tue, 16 Jan 2024 07:00:16 +0000 (15:00 +0800)
committerliuzhensong <liuzhensong@loongson.cn>
Wed, 17 Jan 2024 07:15:33 +0000 (15:15 +0800)
In LoongArch psABI v2.30, an offset (-8 for LO20 and -12 for HI12)
should be applied on PC for these reloc types to avoid wrong relocation
when the instruction sequence crosses a page boundary.

The lld linker has already adapted the change.  Make it for the bfd
linker too.

Link: https://github.com/loongson/la-abi-specs/releases/v2.30
Link: https://github.com/loongson-community/discussions/issues/17
Link: https://github.com/llvm/llvm-project/pull/73387
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
bfd/elfnn-loongarch.c
ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
ld/testsuite/ld-loongarch-elf/pcala64.d [new file with mode: 0644]
ld/testsuite/ld-loongarch-elf/pcala64.s [new file with mode: 0644]

index 7905cdf7564626003d09b07ecf7113f03fe6b80b..64ccc559952a4ff44fd97df9213c620eff1e2bce 100644 (file)
@@ -2529,7 +2529,7 @@ loongarch_reloc_is_fatal (struct bfd_link_info *info,
   ({                                                   \
     bfd_vma __lo = (relocation & (bfd_vma)0xfff);      \
     relocation = (relocation & ~(bfd_vma)0xfff)                \
-                 - (pc & ~(bfd_vma)0xfff);             \
+                 - ((pc) & ~(bfd_vma)0xfff);           \
     if (__lo > 0x7ff)                                  \
        relocation += (0x1000 - 0x100000000);           \
     if (relocation & 0x80000000)                       \
@@ -3534,14 +3534,16 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
            }
          break;
 
-       case R_LARCH_PCALA64_LO20:
        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);
+         RELOCATE_CALC_PC64_HI32 (relocation, pc - 8);
 
          break;
 
@@ -3668,9 +3670,10 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
              relocation = got_off + sec_addr (got);
            }
 
-         if (r_type == R_LARCH_GOT64_PC_HI12
-             || r_type == R_LARCH_GOT64_PC_LO20)
-           RELOCATE_CALC_PC64_HI32 (relocation, pc);
+         if (r_type == R_LARCH_GOT64_PC_HI12)
+           RELOCATE_CALC_PC64_HI32 (relocation, pc - 12);
+         else if (r_type == R_LARCH_GOT64_PC_LO20)
+           RELOCATE_CALC_PC64_HI32 (relocation, pc - 8);
 
          break;
 
@@ -3871,13 +3874,14 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
            /* Use both TLS_GD and TLS_DESC.  */
            if ((tls_type & GOT_TLS_GD) && (tls_type & GOT_TLS_GDESC))
              relocation += 2 * GOT_ENTRY_SIZE;
-         }
 
-           if (r_type == R_LARCH_TLS_DESC64_PC_LO20
-               || r_type == R_LARCH_TLS_DESC64_PC_HI12)
-             RELOCATE_CALC_PC64_HI32 (relocation, pc);
+           if (r_type == R_LARCH_TLS_DESC64_PC_LO20)
+             RELOCATE_CALC_PC64_HI32 (relocation, pc - 8);
+           else if (r_type == R_LARCH_TLS_DESC64_PC_HI12)
+             RELOCATE_CALC_PC64_HI32 (relocation, pc - 12);
 
            break;
+         }
 
        case R_LARCH_TLS_DESC_LD:
        case R_LARCH_TLS_DESC_CALL:
@@ -3906,9 +3910,10 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          else if (GOT_TLS_GD_ANY_P (tls_type) && (tls_type & GOT_TLS_IE))
            relocation += 2 * GOT_ENTRY_SIZE;
 
-         if (r_type == R_LARCH_TLS_IE64_PC_LO20
-             || r_type == R_LARCH_TLS_IE64_PC_HI12)
-           RELOCATE_CALC_PC64_HI32 (relocation, pc);
+         if (r_type == R_LARCH_TLS_IE64_PC_LO20)
+           RELOCATE_CALC_PC64_HI32 (relocation, pc - 8);
+         else if (r_type == R_LARCH_TLS_IE64_PC_HI12)
+           RELOCATE_CALC_PC64_HI32 (relocation, pc - 12);
 
          break;
 
index 29560073abbb0729a7b5d00f10cd59bbe0e9e330..1b5994c7d84ae12523b60ce2e7c6bb6d67f71f12 100644 (file)
@@ -33,6 +33,7 @@ if [istarget "loongarch64-*-*"] {
     run_dump_test "disas-jirl"
     run_dump_test "local-ifunc-reloc"
     run_dump_test "anno-sym"
+    run_dump_test "pcala64"
 }
 
 if [istarget "loongarch32-*-*"] {
diff --git a/ld/testsuite/ld-loongarch-elf/pcala64.d b/ld/testsuite/ld-loongarch-elf/pcala64.d
new file mode 100644 (file)
index 0000000..e0e9819
--- /dev/null
@@ -0,0 +1,15 @@
+#ld: -Ttext=0x180000ff8 -Tdata=0x1000000000
+#objdump: -d
+
+.*:[    ]+file format .*
+
+
+Disassembly of section .text:
+
+0000000180000ff8 <_start>:
+[      ]+180000ff8:[   ]+1b000004[     ]+pcalau12i[    ]+\$a0,[        ]+-524288
+[      ]+180000ffc:[   ]+02c0000c[     ]+li.d[         ]+\$t0,[        ]+0
+[      ]+180001000:[   ]+160001ec[     ]+lu32i.d[      ]+\$t0,[        ]+15
+[      ]+180001004:[   ]+0300018c[     ]+lu52i.d[      ]+\$t0,[        ]+\$t0,[        ]+0
+[      ]+180001008:[   ]+0010b084[     ]+add.d[        ]+\$a0,[        ]+\$a0,[        ]+\$t0
+[      ]+18000100c:[   ]+4c000020[     ]+ret
diff --git a/ld/testsuite/ld-loongarch-elf/pcala64.s b/ld/testsuite/ld-loongarch-elf/pcala64.s
new file mode 100644 (file)
index 0000000..dfef0e2
--- /dev/null
@@ -0,0 +1,8 @@
+.text
+.globl _start
+_start:
+       la.pcrel $a0, $t0, sym
+       jr $ra
+.data
+sym:
+       .dword 0