[binutils-gdb] MIPS/BFD: Avoid section ordering breaking DYNAMIC segment for IRIX 5

Maciej W. Rozycki macro@sourceware.org
Wed Feb 18 08:00:46 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=a5b91b33252959d679a777dd6a455f11b91f90a1

commit a5b91b33252959d679a777dd6a455f11b91f90a1
Author: Maciej W. Rozycki <macro@orcam.me.uk>
Date:   Wed Feb 18 07:58:31 2026 +0000

    MIPS/BFD: Avoid section ordering breaking DYNAMIC segment for IRIX 5
    
    With MIPS targets using the IRIX 5 linker emulation the DYNAMIC segment,
    unusually, gets all of: `.dynamic', `.hash', `.dynsym', and `.dynstr'
    sections mapped to, as well as any other sections placed in between.
    
    No attention is paid as to which of these sections comes first though,
    which would make such a DYNAMIC segment unusable at load time unless it
    starts with the `.dynamic' section, if not for LD terminating the link
    with:
    
    The first section in the PT_DYNAMIC segment is not the .dynamic section
    
    error message.
    
    Our standard linker scripts ensure the correct section ordering, however
    a user-supplied script may not, and it seems suboptimal to prevent users
    from reordering sections to their liking.
    
    Modify MIPS IRIX 5 linker emulation handling then so that only `.hash',
    `.dynsym', and `.dynstr' sections that come after `.dynamic' in output,
    and any other sections placed in between, get mapped to the DYNAMIC
    segment.
    
    This preserves exact IRIX 5 semantics for all the conforming scripts,
    while letting people use a different order rather than getting a link
    error.  The error result previously issued means there is no backwards
    compatibility to consider as no output used to be produced.
    
    This removes a number of test failures:
    
    -FAIL: PROVIDE_HIDDEN test (auxiliary shared object)
    -FAIL: PROVIDE_HIDDEN test 4
    -FAIL: PROVIDE_HIDDEN test 6
    -FAIL: PROVIDE_HIDDEN test 10
    -FAIL: PROVIDE_HIDDEN test 12
    -FAIL: readelf version information
    -FAIL: PR ld/20828 forcibly exported symbol version without section GC
    -FAIL: PR ld/21233 dynamic symbols with section GC (auxiliary shared library)
    
    across MIPS targets using the IRIX 5 linker emulation, such as
    `mips-sgi-irix5', `mips-elf', `mips-rtems', etc.

Diff:
---
 bfd/elfxx-mips.c                                | 15 +++++++++------
 ld/testsuite/ld-mips-elf/dynamic-sections-3.d   |  6 ++++++
 ld/testsuite/ld-mips-elf/dynamic-sections-3.ld  | 12 ++++++++++++
 ld/testsuite/ld-mips-elf/dynamic-sections-3i1.d | 21 +++++++++++++++++++++
 ld/testsuite/ld-mips-elf/dynamic-sections-3i2.d |  6 ++++++
 ld/testsuite/ld-mips-elf/dynamic-sections-4.d   |  6 ++++++
 ld/testsuite/ld-mips-elf/dynamic-sections-4.ld  | 12 ++++++++++++
 ld/testsuite/ld-mips-elf/dynamic-sections-4i1.d | 21 +++++++++++++++++++++
 ld/testsuite/ld-mips-elf/dynamic-sections-4i2.d |  6 ++++++
 ld/testsuite/ld-mips-elf/mips-elf.exp           |  2 ++
 10 files changed, 101 insertions(+), 6 deletions(-)

diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index 6d38e492dfc..6feaa706029 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -12889,7 +12889,9 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
 	}
       /* On IRIX5, the PT_DYNAMIC segment includes the .dynamic,
 	 .dynstr, .dynsym, and .hash sections, and everything in
-	 between.  */
+	 between.  We avoid any sections though ahead of .dynamic,
+	 which needs to be first to be usable.  This can only ever
+	 happen with a non-standard linker script.  */
       for (pm = &elf_seg_map (abfd); *pm != NULL;
 	   pm = &(*pm)->next)
 	if ((*pm)->p_type == PT_DYNAMIC)
@@ -12906,18 +12908,19 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
       if (SGI_COMPAT (abfd)
 	  && m != NULL
 	  && m->count == 1
-	  && strcmp (m->sections[0]->name, ".dynamic") == 0)
+	  && strcmp (m->sections[0]->name, ".dynamic") == 0
+	  && (m->sections[0]->flags & SEC_LOAD) != 0)
 	{
 	  static const char *sec_names[] =
 	  {
-	    ".dynamic", ".dynstr", ".dynsym", ".hash"
+	    ".dynstr", ".dynsym", ".hash"
 	  };
 	  bfd_vma low, high;
 	  unsigned int i, c;
 	  struct elf_segment_map *n;
 
-	  low = ~(bfd_vma) 0;
-	  high = 0;
+	  low = m->sections[0]->vma;
+	  high = low + m->sections[0]->size;
 	  for (i = 0; i < sizeof sec_names / sizeof sec_names[0]; i++)
 	    {
 	      s = bfd_get_section_by_name (abfd, sec_names[i]);
@@ -12926,7 +12929,7 @@ _bfd_mips_elf_modify_segment_map (bfd *abfd,
 		  bfd_size_type sz;
 
 		  if (low > s->vma)
-		    low = s->vma;
+		    continue;
 		  sz = s->size;
 		  if (high < s->vma + sz)
 		    high = s->vma + sz;
diff --git a/ld/testsuite/ld-mips-elf/dynamic-sections-3.d b/ld/testsuite/ld-mips-elf/dynamic-sections-3.d
new file mode 100644
index 00000000000..2ee3baf1a75
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/dynamic-sections-3.d
@@ -0,0 +1,6 @@
+#name: Dynamic segment sections 3
+#ld: -shared -T dynamic-sections-3.ld
+#readelf: -Wl
+#target: [check_shared_lib_support]
+#source: dynamic-sections.s
+#dump: dynamic-sections-1.d
diff --git a/ld/testsuite/ld-mips-elf/dynamic-sections-3.ld b/ld/testsuite/ld-mips-elf/dynamic-sections-3.ld
new file mode 100644
index 00000000000..b3dbff0952a
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/dynamic-sections-3.ld
@@ -0,0 +1,12 @@
+SECTIONS
+{
+  .MIPS.abiflags : { *(.MIPS.abiflags) }
+  .dynsym : { *(.dynsym) }
+  .dynstr : { *(.dynstr) }
+  .dynamic : { *(.dynamic) }
+  .hash : { *(.hash) }
+  .rel.dyn : { *(.rel.dyn) }
+  .data : { *(.data) }
+  .got : { *(.got) }
+  /DISCARD/ : { *(*) }
+}
diff --git a/ld/testsuite/ld-mips-elf/dynamic-sections-3i1.d b/ld/testsuite/ld-mips-elf/dynamic-sections-3i1.d
new file mode 100644
index 00000000000..c00fbf862fc
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/dynamic-sections-3i1.d
@@ -0,0 +1,21 @@
+#name: Dynamic segment sections 3
+#ld: -shared -T dynamic-sections-3.ld
+#readelf: -Wl
+#target: [check_shared_lib_support]
+#source: dynamic-sections.s
+
+Elf file type is DYN \(Shared object file\)
+Entry point 0x0
+There are 3 program headers, starting at offset .*
+
+Program Headers:
+  Type           Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg +Align
+  ABIFLAGS       .*
+  LOAD           .*
+  DYNAMIC        [^ ]+ +[^ ]+ +[^ ]+ +(0x[0-9a-f]+) +\1 +.*
+
+ Section to Segment mapping:
+  Segment Sections\.\.\.
+   00     .*
+   01     .*
+   02     \.dynamic \.hash 
diff --git a/ld/testsuite/ld-mips-elf/dynamic-sections-3i2.d b/ld/testsuite/ld-mips-elf/dynamic-sections-3i2.d
new file mode 100644
index 00000000000..e16d35c2d51
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/dynamic-sections-3i2.d
@@ -0,0 +1,6 @@
+#name: Dynamic segment sections 3
+#ld: -shared -T dynamic-sections-3.ld
+#readelf: -Wl
+#target: [check_shared_lib_support]
+#source: dynamic-sections.s
+#dump: dynamic-sections-1i2.d
diff --git a/ld/testsuite/ld-mips-elf/dynamic-sections-4.d b/ld/testsuite/ld-mips-elf/dynamic-sections-4.d
new file mode 100644
index 00000000000..2479105e816
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/dynamic-sections-4.d
@@ -0,0 +1,6 @@
+#name: Dynamic segment sections 4
+#ld: -shared -T dynamic-sections-4.ld
+#readelf: -Wl
+#target: [check_shared_lib_support]
+#source: dynamic-sections.s
+#dump: dynamic-sections-1.d
diff --git a/ld/testsuite/ld-mips-elf/dynamic-sections-4.ld b/ld/testsuite/ld-mips-elf/dynamic-sections-4.ld
new file mode 100644
index 00000000000..247cdd22c62
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/dynamic-sections-4.ld
@@ -0,0 +1,12 @@
+SECTIONS
+{
+  .MIPS.abiflags : { *(.MIPS.abiflags) }
+  .dynsym : { *(.dynsym) }
+  .dynstr : { *(.dynstr) }
+  .dynamic : { *(.dynamic) }
+  .data : { *(.data) }
+  .hash : { *(.hash) }
+  .rel.dyn : { *(.rel.dyn) }
+  .got : { *(.got) }
+  /DISCARD/ : { *(*) }
+}
diff --git a/ld/testsuite/ld-mips-elf/dynamic-sections-4i1.d b/ld/testsuite/ld-mips-elf/dynamic-sections-4i1.d
new file mode 100644
index 00000000000..6d0fcce480e
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/dynamic-sections-4i1.d
@@ -0,0 +1,21 @@
+#name: Dynamic segment sections 4
+#ld: -shared -T dynamic-sections-4.ld
+#readelf: -Wl
+#target: [check_shared_lib_support]
+#source: dynamic-sections.s
+
+Elf file type is DYN \(Shared object file\)
+Entry point 0x0
+There are 3 program headers, starting at offset .*
+
+Program Headers:
+  Type           Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg +Align
+  ABIFLAGS       .*
+  LOAD           .*
+  DYNAMIC        [^ ]+ +[^ ]+ +[^ ]+ +(0x[0-9a-f]+) +\1 +.*
+
+ Section to Segment mapping:
+  Segment Sections\.\.\.
+   00     .*
+   01     .*
+   02     \.dynamic \.data \.hash 
diff --git a/ld/testsuite/ld-mips-elf/dynamic-sections-4i2.d b/ld/testsuite/ld-mips-elf/dynamic-sections-4i2.d
new file mode 100644
index 00000000000..dd9a7239594
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/dynamic-sections-4i2.d
@@ -0,0 +1,6 @@
+#name: Dynamic segment sections 4
+#ld: -shared -T dynamic-sections-4.ld
+#readelf: -Wl
+#target: [check_shared_lib_support]
+#source: dynamic-sections.s
+#dump: dynamic-sections-1i2.d
diff --git a/ld/testsuite/ld-mips-elf/mips-elf.exp b/ld/testsuite/ld-mips-elf/mips-elf.exp
index 7f51eb62538..f1bbd81827f 100644
--- a/ld/testsuite/ld-mips-elf/mips-elf.exp
+++ b/ld/testsuite/ld-mips-elf/mips-elf.exp
@@ -1808,3 +1808,5 @@ foreach { abi } $abis {
 
 run_dump_test "dynamic-sections-1${irixn}"
 run_dump_test "dynamic-sections-2${irixn}"
+run_dump_test "dynamic-sections-3${irixn}"
+run_dump_test "dynamic-sections-4${irixn}"


More information about the Binutils-cvs mailing list