]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
LoongArch: Do not relax pcalau12i+ld.d when there is overflow
authorLulu Cai <cailulu@loongson.cn>
Tue, 5 Nov 2024 08:21:28 +0000 (16:21 +0800)
committerliuzhensong <liuzhensong@loongson.cn>
Tue, 19 Nov 2024 01:42:23 +0000 (09:42 +0800)
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.

bfd/elfnn-loongarch.c
ld/testsuite/ld-loongarch-elf/check_got_relax.d [new file with mode: 0644]
ld/testsuite/ld-loongarch-elf/check_got_relax.s [new file with mode: 0644]
ld/testsuite/ld-loongarch-elf/check_relax_got.ld [new file with mode: 0644]
ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp

index 608d179c168ecef46d8440abd389a8207fe1d21d..8189a23a3a99aadc8f89ef4952a77f11fa9f460f 100644 (file)
@@ -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 (file)
index 0000000..da00fec
--- /dev/null
@@ -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 (file)
index 0000000..6bdf817
--- /dev/null
@@ -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 (file)
index 0000000..287f28e
--- /dev/null
@@ -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/ :
+  {
+    *(*)
+  }
+}
index 3313f72eee419818cd0209fd767532126a581764..e1b038cb579be53f41f8f431fc15bf5452a5f77e 100644 (file)
@@ -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-*-*"] {