aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLulu Cai <cailulu@loongson.cn>2024-11-05 16:21:28 +0800
committerliuzhensong <liuzhensong@loongson.cn>2024-11-19 09:42:23 +0800
commit77bcfb741cbec8cadec7a0d450a32c8a5b161f23 (patch)
tree2c340a41d66881cf10c0b053c111124be4d4adb3
parent0073bda2108b9d9b71a687a9fc17a3f5b455528f (diff)
downloadbinutils-77bcfb741cbec8cadec7a0d450a32c8a5b161f23.zip
binutils-77bcfb741cbec8cadec7a0d450a32c8a5b161f23.tar.gz
binutils-77bcfb741cbec8cadec7a0d450a32c8a5b161f23.tar.bz2
LoongArch: Do not relax pcalau12i+ld.d when there is overflow
There is no overflow check for the relaxation of pcalau12i+ld.d => pcalau12i+addi.d. For instruction sequences that can be relaxed, they are directly relaxed to pcalau12i+addi.d. However, when the relative distance between the symbol and the pc exceeds the 32-bit range, the symbol value cannot be obtained correctly. Adds an overflow check for the relaxation of pcalau12i+ld.d. If it is found that the relaxation will overflow, it will not be relaxed.
-rw-r--r--bfd/elfnn-loongarch.c32
-rw-r--r--ld/testsuite/ld-loongarch-elf/check_got_relax.d60
-rw-r--r--ld/testsuite/ld-loongarch-elf/check_got_relax.s43
-rw-r--r--ld/testsuite/ld-loongarch-elf/check_relax_got.ld25
-rw-r--r--ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp1
5 files changed, 156 insertions, 5 deletions
diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index 608d179..8189a23 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -5099,12 +5099,12 @@ loongarch_relax_call36 (bfd *abfd, asection *sec, asection *sym_sec,
/* Relax pcalau12i,ld.d => pcalau12i,addi.d. */
static bool
loongarch_relax_pcala_ld (bfd *abfd, asection *sec,
- asection *sym_sec ATTRIBUTE_UNUSED,
+ asection *sym_sec,
Elf_Internal_Rela *rel_hi,
- bfd_vma symval ATTRIBUTE_UNUSED,
- struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ bfd_vma symval,
+ struct bfd_link_info *info,
bool *again ATTRIBUTE_UNUSED,
- bfd_vma max_alignment ATTRIBUTE_UNUSED)
+ bfd_vma max_alignment)
{
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
Elf_Internal_Rela *rel_lo = rel_hi + 2;
@@ -5113,10 +5113,32 @@ loongarch_relax_pcala_ld (bfd *abfd, asection *sec,
uint32_t rd = LARCH_GET_RD (pca);
uint32_t addi_d = LARCH_OP_ADDI_D;
+ /* This section's output_offset need to subtract the bytes of instructions
+ relaxed by the previous sections, so it needs to be updated beforehand.
+ size_input_section already took care of updating it after relaxation,
+ so we additionally update once here. */
+ sec->output_offset = sec->output_section->size;
+ bfd_vma pc = sec_addr (sec) + rel_hi->r_offset;
+
+ /* If pc and symbol not in the same segment, add/sub segment alignment. */
+ if (!loongarch_two_sections_in_same_segment (info->output_bfd,
+ sec->output_section,
+ sym_sec->output_section))
+ max_alignment = info->maxpagesize > max_alignment ? info->maxpagesize
+ : max_alignment;
+
+ if (symval > pc)
+ pc -= (max_alignment > 4 ? max_alignment : 0);
+ else if (symval < pc)
+ pc += (max_alignment > 4 ? max_alignment : 0);
+
if ((ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_GOT_PC_LO12)
|| (LARCH_GET_RD (ld) != rd)
|| (LARCH_GET_RJ (ld) != rd)
- || !LARCH_INSN_LD_D (ld))
+ || !LARCH_INSN_LD_D (ld)
+ /* Within +-2G addressing range. */
+ || (bfd_signed_vma)(symval - pc) < (bfd_signed_vma)(int32_t)0x80000000
+ || (bfd_signed_vma)(symval - pc) > (bfd_signed_vma)(int32_t)0x7fffffff)
return false;
addi_d = addi_d | (rd << 5) | rd;
diff --git a/ld/testsuite/ld-loongarch-elf/check_got_relax.d b/ld/testsuite/ld-loongarch-elf/check_got_relax.d
new file mode 100644
index 0000000..da00fec
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/check_got_relax.d
@@ -0,0 +1,60 @@
+#ld: -T check_relax_got.ld
+#objdump: -D
+
+.*: file format .*
+
+
+Disassembly of section .text:
+
+0+10000 <_start>:
+ 10000: 1a03fe04 pcalau12i \$a0, 8176
+ 10004: 28c06084 ld.d \$a0, \$a0, 24
+ 10008: 1a03fe04 pcalau12i \$a0, 8176
+ 1000c: 28c08084 ld.d \$a0, \$a0, 32
+ 10010: 1a03fe04 pcalau12i \$a0, 8176
+ 10014: 28c04084 ld.d \$a0, \$a0, 16
+
+0+10018 <sym_default_1>:
+ 10018: 00000123 .word 0x00000123
+
+0+1001c <sym_hidden_1>:
+ 1001c: 00000123 .word 0x00000123
+
+0+10020 <sym_protected_1>:
+ 10020: 00000123 .word 0x00000123
+
+Disassembly of section .got:
+
+0+2000000 <_GLOBAL_OFFSET_TABLE_>:
+ ...
+ 2000008: 00010018 .word 0x00010018
+ 200000c: 00000000 .word 0x00000000
+ 2000010: 82000020 .word 0x82000020
+ 2000014: 00000000 .word 0x00000000
+ 2000018: 82000018 .word 0x82000018
+ 200001c: 00000000 .word 0x00000000
+ 2000020: 8200001c .word 0x8200001c
+ 2000024: 00000000 .word 0x00000000
+ 2000028: 0001001c .word 0x0001001c
+ 200002c: 00000000 .word 0x00000000
+ 2000030: 00010020 asrtle.d \$ra, \$zero
+ 2000034: 00000000 .word 0x00000000
+
+Disassembly of section .other:
+
+0+82000000 <underflow>:
+ 82000000: 1b000004 pcalau12i \$a0, -524288
+ 82000004: 28c02084 ld.d \$a0, \$a0, 8
+ 82000008: 1b000004 pcalau12i \$a0, -524288
+ 8200000c: 28c0a084 ld.d \$a0, \$a0, 40
+ 82000010: 1b000004 pcalau12i \$a0, -524288
+ 82000014: 28c0c084 ld.d \$a0, \$a0, 48
+
+0+82000018 <sym_default_2>:
+ 82000018: 00000456 .word 0x00000456
+
+0+8200001c <sym_hidden_2>:
+ 8200001c: 00000456 .word 0x00000456
+
+0+82000020 <sym_protected_2>:
+ 82000020: 00000456 .word 0x00000456
diff --git a/ld/testsuite/ld-loongarch-elf/check_got_relax.s b/ld/testsuite/ld-loongarch-elf/check_got_relax.s
new file mode 100644
index 0000000..6bdf817
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/check_got_relax.s
@@ -0,0 +1,43 @@
+ .text
+ .global _start
+_start:
+
+ # dot not relax when overflow
+ la.got $a0,sym_default_2
+ la.got $a0,sym_hidden_2
+ la.got $a0,sym_protected_2
+
+sym_default_1:
+ .word 0x123
+
+ .global sym_hidden_1
+ .hidden sym_hidden_1
+sym_hidden_1:
+ .word 0x123
+
+ .global sym_protected_1
+ .protected sym_protected_1
+sym_protected_1:
+ .word 0x123
+
+
+ .section .other,"ax",@progbits
+underflow:
+ # dot not relax when underflow
+ la.got $a0,sym_default_1
+ la.got $a0,sym_hidden_1
+ la.got $a0,sym_protected_1
+
+ .global sym_default_2
+sym_default_2:
+ .word 0x456
+
+ .global sym_hidden_2
+ .hidden sym_hidden_2
+sym_hidden_2:
+ .word 0x456
+
+ .global sym_protected_2
+ .protected sym_protected_2
+sym_protected_2:
+ .word 0x456
diff --git a/ld/testsuite/ld-loongarch-elf/check_relax_got.ld b/ld/testsuite/ld-loongarch-elf/check_relax_got.ld
new file mode 100644
index 0000000..287f28e
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/check_relax_got.ld
@@ -0,0 +1,25 @@
+OUTPUT_ARCH(loongarch)
+ENTRY(_start)
+SECTIONS
+{
+ PROVIDE (__executable_start = 0x8000);
+ . = 0x10000;
+ .text :
+ {
+ *(.text)
+ } =0
+ . = 0x2000000;
+ .got :
+ {
+ *(.got.plt) *(.got)
+ }
+ . = 0x82000000;
+ .other :
+ {
+ *(.other)
+ }
+ /DISCARD/ :
+ {
+ *(*)
+ }
+}
diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
index 3313f72..e1b038c 100644
--- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
+++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
@@ -47,6 +47,7 @@ if [istarget "loongarch64-*-*"] {
run_dump_test "tls-le-relax"
run_dump_test "relax-medium-call"
run_dump_test "relax-medium-call-1"
+ run_dump_test "check_got_relax"
}
if [istarget "loongarch32-*-*"] {