LoongArch: Adapt R_LARCH_{PCALA,GOT,TLS_IE,TLS_DESC}64_* handling per psABI v2.30

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>
This commit is contained in:
Xi Ruoyao 2024-01-16 15:00:16 +08:00 committed by liuzhensong
parent 5e35a3a8bb
commit 6590ec8097
4 changed files with 42 additions and 13 deletions

View 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;

View 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-*-*"] {

View file

@ -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

View file

@ -0,0 +1,8 @@
.text
.globl _start
_start:
la.pcrel $a0, $t0, sym
jr $ra
.data
sym:
.dword 0