]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
LoongArch: only insert align section for ld -r if an input has R_LARCH_ALIGN or R_LAR...
authorXi Ruoyao <xry111@xry111.site>
Tue, 14 Jul 2026 15:51:32 +0000 (23:51 +0800)
committermengqinggang <mengqinggang@loongson.cn>
Thu, 16 Jul 2026 11:08:06 +0000 (19:08 +0800)
Commit 8bf4b69718d4 ("LoongArch: Fix relaxation alignment with ld -r (PR
33236)") has broken the kernel modules on Debian sid.  The expectation
of the kernel is all the source files which would be linked into a
module are compiled with -mno-relax so the module should not contain
R_LARCH_ALIGN, thus the module loader rejects any module containing
R_LARCH_ALIGN.

To restore the correctness of the expectation, only insert the align
section if an input has R_LARCH_ALIGN or R_LARCH_ALIGN (i.e. bytes may
be removed from that input).  Regardless of the kernel modules, it also
does not make too much sense to bloat the output with NOPs and
R_LARCH_ALIGN if no input ever contains R_LARCH_ALIGN and R_LARCH_ALIGN
anyway.

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
bfd/elfnn-loongarch.c
ld/testsuite/ld-loongarch-elf/relax-align-ld-r-norelax.d [new file with mode: 0644]
ld/testsuite/ld-loongarch-elf/relax.exp

index 03b0eb40ac70aa78048c22356846d85ef578c2b5..4bdc3f2628596c18afbd95e8ce47004c74f7a348 100644 (file)
@@ -139,6 +139,10 @@ struct loongarch_elf_link_hash_table
   /* Pending relaxation (byte deletion) operations meant for roughly
      sequential access.  */
   splay_tree pending_delete_ops;
+
+  /* If any input contains a reloc potentially removing bytes, i.e.
+     R_LARCH_ALIGN or R_LARCH_RELAX.  */
+  bool reloc_may_remove_bytes;
 };
 
 struct loongarch_elf_section_data
@@ -1109,10 +1113,26 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   const Elf_Internal_Rela *rel;
   asection *sreloc = NULL;
 
+  htab = loongarch_elf_hash_table (info);
+
   if (bfd_link_relocatable (info))
-    return true;
+    {
+      if (!htab->reloc_may_remove_bytes)
+       for (rel = relocs; rel < relocs + sec->reloc_count; rel++)
+         switch (ELFNN_R_TYPE (rel->r_info))
+           {
+           case R_LARCH_ALIGN:
+           case R_LARCH_RELAX:
+             htab->reloc_may_remove_bytes = true;
+             return true;
+           default:
+             continue;
+           }
+
+      /* No need for more checks with ld -r.  */
+      return true;
+    }
 
-  htab = loongarch_elf_hash_table (info);
   symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
 
@@ -7098,7 +7118,14 @@ elfNN_loongarch_size_aligns (bfd *output_bfd,
                                          (const char *, asection *),
                             void (*layout_sections_again) (void))
 {
+
+  struct loongarch_elf_link_hash_table *htab;
   bool need_laying_out = false;
+
+  htab = loongarch_elf_hash_table (info);
+  if (!htab->reloc_may_remove_bytes)
+    return true;
+
   for (bfd *input_bfd = info->input_bfds; input_bfd != NULL;
        input_bfd = input_bfd->link.next)
     {
diff --git a/ld/testsuite/ld-loongarch-elf/relax-align-ld-r-norelax.d b/ld/testsuite/ld-loongarch-elf/relax-align-ld-r-norelax.d
new file mode 100644 (file)
index 0000000..5f33b8b
--- /dev/null
@@ -0,0 +1,9 @@
+#source: relax-align-ld-r.s
+#as: -mno-relax
+#ld: -r
+#objdump: -Dr
+
+#failif
+#...
+.*R_LARCH_ALIGN.*
+#...
index bb8429ab515023a100ace7d74b8fba348d577ae7..bf4955f4c62712cf4ef34c09146b9008275e32fc 100644 (file)
@@ -49,6 +49,7 @@ proc run_partial_linking_align_test {} {
 if [istarget loongarch*-*-*] {
   run_dump_test "relax-align-1"
   run_dump_test "relax-align-ld-r"
+  run_dump_test "relax-align-ld-r-norelax"
 }
 
 if [istarget loongarch64-*-*] {