]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
LoongArch: Add -mignore-start-align option
authormengqinggang <mengqinggang@loongson.cn>
Sun, 7 Apr 2024 08:34:42 +0000 (16:34 +0800)
committerliuzhensong <liuzhensong@loongson.cn>
Sat, 20 Apr 2024 04:10:40 +0000 (12:10 +0800)
Ignore .align at the start of a section may result in misalignment when
partial linking. Manually add -mignore-start-align option without partial
linking.

Gcc -falign-functions add .align 5 to the start of a section, it causes some
error message mismatch. Set these testcases to xfail on LoongArch target.

gas/config/tc-loongarch.c
gas/testsuite/gas/loongarch/relax-align-ignore-start.d [moved from gas/testsuite/gas/loongarch/relax-align-first.d with 87% similarity]
gas/testsuite/gas/loongarch/relax-align-ignore-start.s [moved from gas/testsuite/gas/loongarch/relax-align-first.s with 100% similarity]
include/opcode/loongarch.h
ld/testsuite/ld-elf/dwarf.exp
ld/testsuite/ld-loongarch-elf/partial-link-align-a.s [new file with mode: 0644]
ld/testsuite/ld-loongarch-elf/partial-link-align-b.s [new file with mode: 0644]
ld/testsuite/ld-loongarch-elf/relax-align-ignore-start.d [moved from ld/testsuite/ld-loongarch-elf/relax-align-first.d with 92% similarity]
ld/testsuite/ld-loongarch-elf/relax-align-ignore-start.s [moved from ld/testsuite/ld-loongarch-elf/relax-align-first.s with 100% similarity]
ld/testsuite/ld-loongarch-elf/relax.exp
ld/testsuite/ld-undefined/undefined.exp

index d156477d1e6b76b45aaa2be2b683c9166965ded6..00b8c80c3de677132eff1e824f1fb5fa67bdfa40 100644 (file)
@@ -139,15 +139,17 @@ enum options
 
   OPTION_ABI,
   OPTION_FLOAT_ABI,
-
   OPTION_FLOAT_ISA,
 
   OPTION_LA_LOCAL_WITH_ABS,
   OPTION_LA_GLOBAL_WITH_PCREL,
   OPTION_LA_GLOBAL_WITH_ABS,
+
   OPTION_RELAX,
   OPTION_NO_RELAX,
+
   OPTION_THIN_ADD_SUB,
+  OPTION_IGNORE_START_ALIGN,
 
   OPTION_END_OF_ENUM,
 };
@@ -165,6 +167,7 @@ struct option md_longopts[] =
   { "mrelax", no_argument, NULL, OPTION_RELAX },
   { "mno-relax", no_argument, NULL, OPTION_NO_RELAX },
   { "mthin-add-sub", no_argument, NULL, OPTION_THIN_ADD_SUB},
+  { "mignore-start-align", no_argument, NULL, OPTION_IGNORE_START_ALIGN},
 
   { NULL, no_argument, NULL, 0 }
 };
@@ -247,6 +250,10 @@ md_parse_option (int c, const char *arg)
       LARCH_opts.thin_add_sub = 1;
       break;
 
+    case OPTION_IGNORE_START_ALIGN:
+      LARCH_opts.ignore_start_align = 1;
+      break;
+
     case OPTION_IGNORE:
       break;
 
@@ -1772,7 +1779,9 @@ md_show_usage (FILE *stream)
   -mthin-add-sub         Convert a pair of R_LARCH_ADD32/64 and R_LARCH_SUB32/64 to\n\
                          R_LARCH_32/64_PCREL as much as possible\n\
                          The option does not affect the generation of R_LARCH_32_PCREL\n\
-                         relocations in .eh_frame\n"));
+                         relocations in .eh_frame\n\
+  -mignore-start-align   Ignore .align if it is at the start of a section. This option\n\
+                         can't be used when partial linking (ld -r).\n"));
 }
 
 static void
@@ -1794,39 +1803,60 @@ bool
 loongarch_frag_align_code (int n, int max)
 {
   char *nops;
+  expressionS ex;
   symbolS *s = NULL;
 
-  bfd_vma insn_alignment = 4;
-  bfd_vma bytes = (bfd_vma) 1 << n;
-  bfd_vma worst_case_bytes = bytes - insn_alignment;
+  /* When not relaxing, loongarch_handle_align handles code alignment.  */
+  if (!LARCH_opts.relax)
+    return false;
+
+  bfd_vma align_bytes = (bfd_vma) 1 << n;
+  bfd_vma worst_case_bytes = align_bytes - 4;
+  bfd_vma addend = worst_case_bytes;
+  bool align_max = max > 0 && (bfd_vma) max < worst_case_bytes;
 
   /* If we are moving to a smaller alignment than the instruction size, then no
      alignment is required.  */
-  if (bytes <= insn_alignment)
+  if (align_bytes <= 4)
     return true;
 
-  /* When not relaxing, loongarch_handle_align handles code alignment.  */
-  if (!LARCH_opts.relax)
-    return false;
-
   /* If max <= 0, ignore max.
      If max >= worst_case_bytes, max has no effect.
      Similar to gas/write.c relax_segment function rs_align_code case:
      if (fragP->fr_subtype != 0 && offset > fragP->fr_subtype).  */
-  if (max > 0 && (bfd_vma) max < worst_case_bytes)
+  if (align_max)
     {
       s = symbol_find (now_seg->name);
-      worst_case_bytes = ALIGN_MAX_ADDEND (n, max);
+      addend = ALIGN_MAX_ADDEND (n, max);
+    }
+
+  if (LARCH_opts.ignore_start_align)
+    {
+      frag_grow (worst_case_bytes);
+      /* Use relaxable frag for .align.
+        If .align at the start of section, do nothing. Section alignment can
+        ensure correct alignment.
+        If .align is not at the start of a section, reserve NOP instructions
+        and R_LARCH_ALIGN relocation.  */
+      nops = frag_var (rs_machine_dependent, worst_case_bytes, worst_case_bytes,
+                      rs_align_code, s, addend, NULL);
     }
+  else
+    {
+      nops = frag_more (worst_case_bytes);
+      if (align_max)
+       {
+         ex.X_add_symbol = s;
+         ex.X_op = O_symbol;
+       }
+      else
+         ex.X_op = O_constant;
+
+      ex.X_add_number = addend;
 
-  frag_grow (worst_case_bytes);
-  /* Use relaxable frag for .align.
-     If .align at the start of section, do nothing. Section alignment can
-     ensure correct alignment.
-     If .align is not at the start of a section, reserve NOP instructions
-     and R_LARCH_ALIGN relocation.  */
-  nops = frag_var (rs_machine_dependent, worst_case_bytes, worst_case_bytes,
-                  rs_align_code, s, worst_case_bytes, NULL);
+      fix_new_exp (frag_now, nops - frag_now->fr_literal, 0,
+                  &ex, false, BFD_RELOC_LARCH_ALIGN);
+    }
 
   /* Default write NOP for aligned bytes.  */
   loongarch_make_nops (nops, worst_case_bytes);
similarity index 87%
rename from gas/testsuite/gas/loongarch/relax-align-first.d
rename to gas/testsuite/gas/loongarch/relax-align-ignore-start.d
index ec0698b6995972f32dde232baa0247a4d2f68212..0a67392d1639eac4d1600d05604edfb53fa1987e 100644 (file)
@@ -1,4 +1,4 @@
-#as:
+#as: -mignore-start-align
 #objdump: -dr
 
 .*:[    ]+file format .*
index 251daf139438106bfae30660f204ae29a11a372f..965a164307ff4cbe2415d0ce4da854607c711dca 100644 (file)
@@ -256,6 +256,7 @@ dec2 : [1-9][0-9]?
 
     int relax;
     int thin_add_sub;
+    int ignore_start_align;
   } LARCH_opts;
 
   extern size_t loongarch_insn_length (insn_t insn);
index 6a63269562ce87f66a9a7e7909e47a752ee2c1e9..a4748a47c988fa5e0496c2567fd32b33380bba45 100644 (file)
@@ -52,6 +52,9 @@ set build_tests {
   {"DWARF parse during linker error"
    "" "-fno-toplevel-reorder"
    {dwarf2a.c dwarf2b.c} {{error_output "dwarf2.err"}} "dwarf2.x"}
+}
+
+set build_tests_dwarf3 {
   {"Handle no DWARF information"
    "" "-g0"
    {dwarf3.c} {{error_output "dwarf3.err"}} "dwarf3.x"}
@@ -72,6 +75,8 @@ set run_tests {
 set old_CFLAGS "$CFLAGS_FOR_TARGET"
 append CFLAGS_FOR_TARGET " $NOSANITIZE_CFLAGS"
 run_cc_link_tests $build_tests
+setup_xfail loongarch*-*-*
+run_cc_link_tests $build_tests_dwarf3
 run_ld_link_exec_tests $run_tests
 set CFLAGS_FOR_TARGET "$old_CFLAGS"
 
diff --git a/ld/testsuite/ld-loongarch-elf/partial-link-align-a.s b/ld/testsuite/ld-loongarch-elf/partial-link-align-a.s
new file mode 100644 (file)
index 0000000..a8b4f29
--- /dev/null
@@ -0,0 +1,2 @@
+.text
+la.local $t0, .text
diff --git a/ld/testsuite/ld-loongarch-elf/partial-link-align-b.s b/ld/testsuite/ld-loongarch-elf/partial-link-align-b.s
new file mode 100644 (file)
index 0000000..46fa058
--- /dev/null
@@ -0,0 +1,3 @@
+.text
+.align 4
+ret
similarity index 92%
rename from ld/testsuite/ld-loongarch-elf/relax-align-first.d
rename to ld/testsuite/ld-loongarch-elf/relax-align-ignore-start.d
index 9a4fad8ea460ec8d73b93c86be2770e4d7ac5683..939cf427b4bebde8a2386da26013cb9d962eb210 100644 (file)
@@ -1,3 +1,4 @@
+#as: -mignore-start-align
 #ld: -e0
 #objdump: -d
 
index 23452142cd21a4e0a6f5aede45bdefac37a841ff..890f139d428cb16a1607a68875978ce44c5054d7 100644 (file)
 # MA 02110-1301, USA.
 #
 
-if [istarget loongarch64-*-*] {
-  run_dump_test "relax-align-first"
+proc run_partial_linking_align_test {} {
+  global as
+  global ld
+  global srcdir
+  global subdir
+  global runtests
+
+  set testname "partial-link-align"
+  if ![runtest_file_p $runtests $testname] then {
+    return
+  }
 
+  if { ![ld_assemble $as "$srcdir/$subdir/$testname-a.s" tmpdir/a.o]
+      || ![ld_assemble $as "$srcdir/$subdir/$testname-b.s" tmpdir/b.o]
+      || ![ld_link $ld tmpdir/$testname.os "tmpdir/a.o tmpdir/b.o -r"]
+      || ![ld_link $ld tmpdir/$testname "tmpdir/$testname.os -e0 -Ttext 0x1000"] } {
+    fail $testname
+  } else {
+    set objdump_output [run_host_cmd "objdump" "-d tmpdir/$testname"]
+    if { [ regexp ".*1010:\\s*4c000020\\s*jirl.*" $objdump_output ] } {
+      pass $testname
+    } else {
+      fail $testname
+    }
+  }
+}
+
+if [istarget loongarch64-*-*] {
   if [isbuild loongarch64-*-*] {
+    run_dump_test "relax-align-ignore-start"
+    run_partial_linking_align_test
+
     set testname "loongarch relax .exe build"
     set pre_builds [list \
       [list \
index 6f7ea003c96ed5f9b4b0d73549c239218db1f8a6..2cc67fef16e7e448c172f3d100d1e3836b04f261 100644 (file)
@@ -74,6 +74,7 @@ if { ![check_compiler_available] } {
     # in a literal pool outside the function, so that both the
     # "undefined function" and "undefined line" tests fail.
     setup_xfail xtensa*-*-linux*
+    setup_xfail loongarch*-*-*
 
     set mf "tmpdir/undefined.o* in function `function':"
     checkund $mf $testfn
@@ -154,6 +155,7 @@ if { ![check_compiler_available] } {
 
     # eBPF doesn't support dwarf yet.
     setup_xfail bpf-*-*
+    setup_xfail loongarch*-*-*
 
     checkund $ml $testline
 }