]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
LoongArch: Fix relaxation overflow caused by ld -z separate-code
authormengqinggang <mengqinggang@loongson.cn>
Wed, 22 May 2024 06:27:08 +0000 (14:27 +0800)
committerliuzhensong <liuzhensong@loongson.cn>
Mon, 27 May 2024 09:41:04 +0000 (17:41 +0800)
ld -z separate-code let .text and .rodata in two different but read only
segment. If the symbol and pc in two segment, the offset from pc to
symbol need to consider segment alignment.

Add a function 'loongarch_two_sections_in_same_segment' to determine
whether two sections are in the same segment.

bfd/elfnn-loongarch.c
ld/testsuite/ld-loongarch-elf/relax-medium-call-1.d
ld/testsuite/ld-loongarch-elf/relax-medium-call-1.s
ld/testsuite/ld-loongarch-elf/relax-medium-call.d
ld/testsuite/ld-loongarch-elf/relax-medium-call.s
ld/testsuite/ld-loongarch-elf/relax-separate-code-overflow.s [new file with mode: 0644]
ld/testsuite/ld-loongarch-elf/relax.exp

index 4f1754e58d831995109071f4a061208873534354..e60bd4db51efec72f405f55ea74c759e9fa850fe 100644 (file)
@@ -3949,6 +3949,12 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          info->callbacks->reloc_overflow
            (info, h ? &h->root : NULL, name, howto->name, rel->r_addend,
             input_bfd, input_section, rel->r_offset);
+         if (r_type == R_LARCH_PCREL20_S2
+             || r_type == R_LARCH_TLS_LD_PCREL20_S2
+             || r_type == R_LARCH_TLS_GD_PCREL20_S2
+             || r_type == R_LARCH_TLS_DESC_PCREL20_S2)
+           _bfd_error_handler (_("recompile with 'gcc -mno-relax' or"
+                                 " 'as -mno-relax' or 'ld --no-relax'"));
          break;
 
        case bfd_reloc_outofrange:
@@ -4313,6 +4319,30 @@ loongarch_relax_tls_le (bfd *abfd, asection *sec,
   return true;
 }
 
+/* Whether two sections in the same segment.  */
+static bool
+loongarch_two_sections_in_same_segment (bfd *abfd, asection *a, asection *b)
+{
+  struct elf_segment_map *m;
+  for (m = elf_seg_map (abfd); m != NULL; m = m->next)
+    {
+      int i;
+      int j = 0;
+      for (i = m->count - 1; i >= 0; i--)
+       {
+         if (m->sections[i] == a)
+           j++;
+         if (m->sections[i] == b)
+           j++;
+       }
+      if (1 == j)
+       return false;
+      if (2 == j)
+       return true;
+    }
+  return false;
+}
+
 /* Relax pcalau12i,addi.d => pcaddi.  */
 static bool
 loongarch_relax_pcala_addi (bfd *abfd, asection *sec, asection *sym_sec,
@@ -4333,23 +4363,17 @@ loongarch_relax_pcala_addi (bfd *abfd, asection *sec, asection *sym_sec,
   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.
-     FIXME: if there are multiple readonly segments? How to determine if
-     two sections are in the same segment.  */
-  if (!(sym_sec->flags & SEC_READONLY))
-    {
-      max_alignment = info->maxpagesize > max_alignment ? info->maxpagesize
-                                                         : max_alignment;
-      if (symval > pc)
-       pc -= max_alignment;
-      else if (symval < pc)
-       pc += max_alignment;
-    }
-  else
-    if (symval > pc)
-      pc -= max_alignment;
-    else if (symval < pc)
-      pc += max_alignment;
+  /* 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);
 
   const uint32_t addi_d = 0x02c00000;
   const uint32_t pcaddi = 0x18000000;
@@ -4388,7 +4412,7 @@ loongarch_relax_pcala_addi (bfd *abfd, asection *sec, asection *sym_sec,
 /* call36 f -> bl f
    tail36 $t0, f -> b f.  */
 static bool
-loongarch_relax_call36 (bfd *abfd, asection *sec,
+loongarch_relax_call36 (bfd *abfd, asection *sec, asection *sym_sec,
                            Elf_Internal_Rela *rel, bfd_vma symval,
                            struct bfd_link_info *info, bool *again,
                            bfd_vma max_alignment)
@@ -4404,9 +4428,13 @@ loongarch_relax_call36 (bfd *abfd, asection *sec,
   sec->output_offset = sec->output_section->size;
   bfd_vma pc = sec_addr (sec) + rel->r_offset;
 
-  /* If pc and symbol not in the same segment, add/sub segment alignment.
-     FIXME: if there are multiple readonly segments? How to determine if
-     two sections are in the same segment.  */
+  /* 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)
@@ -4560,22 +4588,17 @@ loongarch_relax_tls_ld_gd_desc (bfd *abfd, asection *sec, asection *sym_sec,
   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.
-     FIXME: if there are multiple readonly segments?  */
-  if (!(sym_sec->flags & SEC_READONLY))
-    {
-      max_alignment = info->maxpagesize > max_alignment ? info->maxpagesize
-                                                         : max_alignment;
-      if (symval > pc)
-       pc -= max_alignment;
-      else if (symval < pc)
-       pc += max_alignment;
-    }
-  else
-    if (symval > pc)
-      pc -= max_alignment;
-    else if (symval < pc)
-      pc += max_alignment;
+  /* 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);
 
   const uint32_t addi_d = 0x02c00000;
   const uint32_t pcaddi = 0x18000000;
@@ -4859,8 +4882,8 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
          break;
        case R_LARCH_CALL36:
          if (0 == info->relax_pass && (i + 2) <= sec->reloc_count)
-           loongarch_relax_call36 (abfd, sec, rel, symval, info, again,
-                                   max_alignment);
+           loongarch_relax_call36 (abfd, sec, sym_sec, rel, symval,
+                                   info, again, max_alignment);
          break;
 
        case R_LARCH_TLS_LE_HI20_R:
index c8ee93337db41ca776e06828625e73a36f58b390..96e7bb0924695b44027bb72f559acfcad67b1b98 100644 (file)
@@ -1,21 +1,42 @@
-#ld: -e0 -Ttext=0x120000000 --section-start=ta=0x118000000 --section-start=tb=0x127fffffc
-#objdump: -d -j .text
+#ld: -e0
+#objdump: -d
 
 .*:[    ]+file format .*
 
 
 Disassembly of section .text:
 
-[      ]*0000000120000000 <__bss_start-0x4030>:
-[      ]+120000000:[   ]+54000200[     ]+bl[   ]+-134217728[   ]+# 118000000 <a>
-[      ]+120000004:[   ]+1fffc001[     ]+pcaddu18i[    ]+\$ra, -512
-[      ]+120000008:[   ]+4ffffc21[     ]+jirl[         ]+\$ra, \$ra, -4
-[      ]+12000000c:[   ]+50000200[     ]+b[    ]+-134217728[   ]+# 11800000c <b>
-[      ]+120000010:[   ]+1fffc00c[     ]+pcaddu18i[    ]+\$t0, -512
-[      ]+120000014:[   ]+4ffffd80[     ]+jirl[         ]+\$zero, \$t0, -4
-[      ]+120000018:[   ]+1e004001[     ]+pcaddu18i[    ]+\$ra, 512
-[      ]+12000001c:[   ]+4c000421[     ]+jirl[         ]+\$ra, \$ra, 4
-[      ]+120000020:[   ]+57fffdff[     ]+bl[   ]+134217724[    ]+# 12800001c <c>
-[      ]+120000024:[   ]+1e00400c[     ]+pcaddu18i[    ]+\$t0, 512
-[      ]+120000028:[   ]+4c000580[     ]+jirl[         ]+\$zero, \$t0, 4
-[      ]+12000002c:[   ]+53fffdff[     ]+b[    ]+134217724[    ]+# 128000028 <d>
+[      ]*0000000120000078 <a>:
+[      ]+120000078:[   ]+4c000020[     ]+ret
+[      ]+12000007c:[   ]+4c000020[     ]+ret
+[      ]+120000080:[   ]+4c000020[     ]+ret
+[      ]*0000000120000084 <b>:
+[      ]+120000084:[   ]+4c000020[     ]+ret
+[      ]+...
+[      ]+128000078:[   ]+54000200[     ]+bl[   ]+-134217728[   ]+# 120000078 <a>
+[      ]+12800007c:[   ]+1fffc001[     ]+pcaddu18i[    ]+\$ra, -512
+[      ]+128000080:[   ]+4ffffc21[     ]+jirl[         ]+\$ra, \$ra, -4
+[      ]+128000084:[   ]+50000200[     ]+b[    ]+-134217728[   ]+# 120000084 <b>
+[      ]+128000088:[   ]+1fffc00c[     ]+pcaddu18i[    ]+\$t0, -512
+[      ]+12800008c:[   ]+4ffffd80[     ]+jirl[         ]+\$zero, \$t0, -4
+[      ]+128000090:[   ]+1e004001[     ]+pcaddu18i[    ]+\$ra, 512
+[      ]+128000094:[   ]+4c000021[     ]+jirl[         ]+\$ra, \$ra, 0
+[      ]+128000098:[   ]+57fff9ff[     ]+bl[   ]+134217720[    ]+# 130000090 <c>
+[      ]+12800009c:[   ]+1e00400c[     ]+pcaddu18i[    ]+\$t0, 512
+[      ]+1280000a0:[   ]+4c000180[     ]+jr[   ]+\$t0
+[      ]+1280000a4:[   ]+53fff9ff[     ]+b[    ]+134217720[    ]+# 13000009c <d>
+[      ]+...
+[      ]+130000070:[   ]+4c000020[     ]+ret
+[      ]+130000074:[   ]+4c000020[     ]+ret
+[      ]+130000078:[   ]+4c000020[     ]+ret
+[      ]+13000007c:[   ]+4c000020[     ]+ret
+[      ]+130000080:[   ]+4c000020[     ]+ret
+[      ]+130000084:[   ]+4c000020[     ]+ret
+[      ]+130000088:[   ]+4c000020[     ]+ret
+[      ]+13000008c:[   ]+4c000020[     ]+ret
+[      ]*0000000130000090 <c>:
+[      ]+130000090:[   ]+4c000020[     ]+ret
+[      ]+130000094:[   ]+4c000020[     ]+ret
+[      ]+130000098:[   ]+4c000020[     ]+ret
+[      ]*000000013000009c <d>:
+[      ]+13000009c:[   ]+4c000020[     ]+ret
index 5266fdaba7a32bfa57dd952ee6a42cb9175d7c9e..1770ec9f6c24658ae8dd8dc946b4d102816665c6 100644 (file)
@@ -1,12 +1,12 @@
-.section "ta", "ax"
+.text
 a:
   ret
   ret
   ret
 b:
   ret
+  .fill 0x7fffff0
 
-.text
   pcaddu18i $ra, %call36(a) # min offset, can relax
   jirl     $ra, $ra, 0
   pcaddu18i $ra, %call36(a) # overflow, not relax
@@ -25,7 +25,7 @@ b:
   pcaddu18i $t0, %call36(d) # max offset, can relax
   jirl     $zero, $t0, 0
 
-.section "tb", "ax"
+  .fill 0x7ffffc8
   ret
   ret
   ret
index c8ee93337db41ca776e06828625e73a36f58b390..96e7bb0924695b44027bb72f559acfcad67b1b98 100644 (file)
@@ -1,21 +1,42 @@
-#ld: -e0 -Ttext=0x120000000 --section-start=ta=0x118000000 --section-start=tb=0x127fffffc
-#objdump: -d -j .text
+#ld: -e0
+#objdump: -d
 
 .*:[    ]+file format .*
 
 
 Disassembly of section .text:
 
-[      ]*0000000120000000 <__bss_start-0x4030>:
-[      ]+120000000:[   ]+54000200[     ]+bl[   ]+-134217728[   ]+# 118000000 <a>
-[      ]+120000004:[   ]+1fffc001[     ]+pcaddu18i[    ]+\$ra, -512
-[      ]+120000008:[   ]+4ffffc21[     ]+jirl[         ]+\$ra, \$ra, -4
-[      ]+12000000c:[   ]+50000200[     ]+b[    ]+-134217728[   ]+# 11800000c <b>
-[      ]+120000010:[   ]+1fffc00c[     ]+pcaddu18i[    ]+\$t0, -512
-[      ]+120000014:[   ]+4ffffd80[     ]+jirl[         ]+\$zero, \$t0, -4
-[      ]+120000018:[   ]+1e004001[     ]+pcaddu18i[    ]+\$ra, 512
-[      ]+12000001c:[   ]+4c000421[     ]+jirl[         ]+\$ra, \$ra, 4
-[      ]+120000020:[   ]+57fffdff[     ]+bl[   ]+134217724[    ]+# 12800001c <c>
-[      ]+120000024:[   ]+1e00400c[     ]+pcaddu18i[    ]+\$t0, 512
-[      ]+120000028:[   ]+4c000580[     ]+jirl[         ]+\$zero, \$t0, 4
-[      ]+12000002c:[   ]+53fffdff[     ]+b[    ]+134217724[    ]+# 128000028 <d>
+[      ]*0000000120000078 <a>:
+[      ]+120000078:[   ]+4c000020[     ]+ret
+[      ]+12000007c:[   ]+4c000020[     ]+ret
+[      ]+120000080:[   ]+4c000020[     ]+ret
+[      ]*0000000120000084 <b>:
+[      ]+120000084:[   ]+4c000020[     ]+ret
+[      ]+...
+[      ]+128000078:[   ]+54000200[     ]+bl[   ]+-134217728[   ]+# 120000078 <a>
+[      ]+12800007c:[   ]+1fffc001[     ]+pcaddu18i[    ]+\$ra, -512
+[      ]+128000080:[   ]+4ffffc21[     ]+jirl[         ]+\$ra, \$ra, -4
+[      ]+128000084:[   ]+50000200[     ]+b[    ]+-134217728[   ]+# 120000084 <b>
+[      ]+128000088:[   ]+1fffc00c[     ]+pcaddu18i[    ]+\$t0, -512
+[      ]+12800008c:[   ]+4ffffd80[     ]+jirl[         ]+\$zero, \$t0, -4
+[      ]+128000090:[   ]+1e004001[     ]+pcaddu18i[    ]+\$ra, 512
+[      ]+128000094:[   ]+4c000021[     ]+jirl[         ]+\$ra, \$ra, 0
+[      ]+128000098:[   ]+57fff9ff[     ]+bl[   ]+134217720[    ]+# 130000090 <c>
+[      ]+12800009c:[   ]+1e00400c[     ]+pcaddu18i[    ]+\$t0, 512
+[      ]+1280000a0:[   ]+4c000180[     ]+jr[   ]+\$t0
+[      ]+1280000a4:[   ]+53fff9ff[     ]+b[    ]+134217720[    ]+# 13000009c <d>
+[      ]+...
+[      ]+130000070:[   ]+4c000020[     ]+ret
+[      ]+130000074:[   ]+4c000020[     ]+ret
+[      ]+130000078:[   ]+4c000020[     ]+ret
+[      ]+13000007c:[   ]+4c000020[     ]+ret
+[      ]+130000080:[   ]+4c000020[     ]+ret
+[      ]+130000084:[   ]+4c000020[     ]+ret
+[      ]+130000088:[   ]+4c000020[     ]+ret
+[      ]+13000008c:[   ]+4c000020[     ]+ret
+[      ]*0000000130000090 <c>:
+[      ]+130000090:[   ]+4c000020[     ]+ret
+[      ]+130000094:[   ]+4c000020[     ]+ret
+[      ]+130000098:[   ]+4c000020[     ]+ret
+[      ]*000000013000009c <d>:
+[      ]+13000009c:[   ]+4c000020[     ]+ret
index c0521b65732a5f48509077c8e0203af4252bdb91..7b149620f2925987c3f6ae382208472c12a5e5a4 100644 (file)
@@ -1,12 +1,12 @@
-.section "ta", "ax"
+.text
 a:
   ret
   ret
   ret
 b:
   ret
+  .fill 0x7fffff0
 
-.text
   call36 a     # min offset, can relax
   call36 a     # overflow, not relax
   tail36 $t0, b        # min offset, can relax
@@ -17,7 +17,7 @@ b:
   tail36 $t0, d        # overflow, no relax
   tail36 $t0, d # max offset, can relax
 
-.section "tb", "ax"
+  .fill 0x7ffffc8
   ret
   ret
   ret
diff --git a/ld/testsuite/ld-loongarch-elf/relax-separate-code-overflow.s b/ld/testsuite/ld-loongarch-elf/relax-separate-code-overflow.s
new file mode 100644 (file)
index 0000000..df5dd5f
--- /dev/null
@@ -0,0 +1,21 @@
+# ld -z separate-code let .text and .rodata in two segment,
+# need to consider segment alignment
+.text
+  # first two la.local relax in the second trip, and result in the third
+  # la.local (relax to pcaddi) overflow
+  la.local $r12, a
+  la.local $r12, b
+  .fill 0x3ff8
+  # relax in the first trip
+  la.local $r12, c
+  .fill 0x1fbfec
+a:
+  .fill 8
+b:
+  .fill 0x1000
+d:
+  .fill 0x1
+
+.section .rodata
+c:
+  .8byte 0x1
index 6137bd1cf67037e35c15d574d87878c75e7d2ca9..35caa73c11d2ebc6ab529244bf9eec1cae76aef7 100644 (file)
@@ -308,6 +308,21 @@ if [istarget loongarch64-*-*] {
                "relax-section-align-overflow" \
            ] \
        ]
+
+    # # loongarch*-elf target do not support -z separate-code
+    if [check_shared_lib_support] {
+      run_ld_link_tests \
+         [list \
+             [list \
+                 "loongarch relax separate code overflow" \
+                 "-e0 -z separate-code" "" \
+                 "" \
+                 {relax-separate-code-overflow.s} \
+                 {} \
+                 "relax-separate-code-overflow" \
+             ] \
+         ]
+    }
   }
 
   if [check_shared_lib_support] {