[binutils-gdb] LoongArch: Fix linker relaxation alignment

liu zhensong via Binutils-cvs <[email protected]> Mon, 6 Jul 2026 06:13:04 +0000 (GMT)
Newsgroups gmane.comp.gnu.binutils.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=7858cadd335b3ffbc8e0250c0c180253d9f09489

commit 7858cadd335b3ffbc8e0250c0c180253d9f09489
Author: mengqinggang <[email protected]>
Date:   Tue Jun 16 19:10:26 2026 +0800

    LoongArch: Fix linker relaxation alignment
    
    When linking multiple objects, relaxation can cause alignment issues.
    Input section's output_offset is updated in relaxation without considering
    alignment. Update section output_offset by align_opwer.

Diff:
---
 bfd/elfnn-loongarch.c                          | 24 +++---------------------
 ld/testsuite/ld-loongarch-elf/relax-align-1.d  | 13 +++++++++++++
 ld/testsuite/ld-loongarch-elf/relax-align-1a.s |  5 +++++
 ld/testsuite/ld-loongarch-elf/relax-align-1b.s |  3 +++
 ld/testsuite/ld-loongarch-elf/relax.exp        |  4 ++++
 5 files changed, 28 insertions(+), 21 deletions(-)

diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index 9d9c68664bb..b7af2041238 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -5725,11 +5725,6 @@ loongarch_relax_pcala_addi (bfd *abfd, asection *sec, asection *sym_sec,
   uint32_t add = bfd_get (32, abfd, contents + rel_lo->r_offset);
   uint32_t rd = LARCH_GET_RD (pca);
 
-  /* 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)
 	       + loongarch_calc_relaxed_addr (info, rel_hi->r_offset);
   if (sym_sec == sec)
@@ -5790,11 +5785,6 @@ loongarch_relax_call36 (bfd *abfd, asection *sec, asection *sym_sec,
   uint32_t jirl = bfd_get (32, abfd, contents + rel->r_offset + 4);
   uint32_t rd = LARCH_GET_RD (jirl);
 
-  /* 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)
 	       + loongarch_calc_relaxed_addr (info, rel->r_offset);
   if (sym_sec == sec)
@@ -5851,11 +5841,6 @@ loongarch_relax_pcala_ld (bfd *abfd, asection *sec,
 			  bool *again ATTRIBUTE_UNUSED,
 			  bfd_vma max_alignment)
 {
-  /* 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)
 	       + loongarch_calc_relaxed_addr (info, rel_hi->r_offset);
   if (sym_sec == sec)
@@ -6008,11 +5993,6 @@ loongarch_relax_tls_ld_gd_desc (bfd *abfd, asection *sec, asection *sym_sec,
   uint32_t add = bfd_get (32, abfd, contents + rel_lo->r_offset);
   uint32_t rd = LARCH_GET_RD (pca);
 
-  /* 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)
 	       + loongarch_calc_relaxed_addr (info, rel_hi->r_offset);
   if (sym_sec == sec)
@@ -6187,7 +6167,9 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
      so we additionally update once here.  */
 
   /* update before tls trans and relax, or may cause same pcadd_hi20 address.  */
-  sec->output_offset = sec->output_section->size;
+
+  sec->output_offset = align_power (sec->output_section->size,
+				    sec->alignment_power);
 
   for (unsigned int i = 0; i < sec->reloc_count; i++)
     {
diff --git a/ld/testsuite/ld-loongarch-elf/relax-align-1.d b/ld/testsuite/ld-loongarch-elf/relax-align-1.d
new file mode 100644
index 00000000000..5681efb16d1
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relax-align-1.d
@@ -0,0 +1,13 @@
+#source: relax-align-1a.s
+#source: relax-align-1b.s
+#ld: -e0
+#objdump: -d
+
+#...
+.*:	54000400 	bl          	4.*<f>
+#...
+.*[0|8]:	02c001ac 	addi.d      	\$t0, \$t1, 0
+#...
+.*0:	02c005ac 	addi.d      	\$t0, \$t1, 1
+#...
+.*0:	02c005ac 	addi.d      	\$t0, \$t1, 1
diff --git a/ld/testsuite/ld-loongarch-elf/relax-align-1a.s b/ld/testsuite/ld-loongarch-elf/relax-align-1a.s
new file mode 100644
index 00000000000..2b7f3ecb6be
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relax-align-1a.s
@@ -0,0 +1,5 @@
+.text
+  call f
+f:
+  .align 3
+  addi.d $t0, $t1, 0
diff --git a/ld/testsuite/ld-loongarch-elf/relax-align-1b.s b/ld/testsuite/ld-loongarch-elf/relax-align-1b.s
new file mode 100644
index 00000000000..2ed480a6c1b
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relax-align-1b.s
@@ -0,0 +1,3 @@
+addi.d $t0, $t1, 1
+.align 4
+addi.d $t0, $t1, 1
diff --git a/ld/testsuite/ld-loongarch-elf/relax.exp b/ld/testsuite/ld-loongarch-elf/relax.exp
index 7c32a65244c..31787a93967 100644
--- a/ld/testsuite/ld-loongarch-elf/relax.exp
+++ b/ld/testsuite/ld-loongarch-elf/relax.exp
@@ -46,6 +46,10 @@ proc run_partial_linking_align_test {} {
   }
 }
 
+if [istarget loongarch*-*-*] {
+  run_dump_test "relax-align-1"
+}
+
 if [istarget loongarch64-*-*] {
   if [isbuild loongarch64-*-*] {
     run_dump_test "relax-align-ignore-start"