]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
elf: Handle the section flag 'o' linked to special sections
authorH.J. Lu <hjl.tools@gmail.com>
Sun, 11 Jan 2026 03:43:40 +0000 (11:43 +0800)
committerH.J. Lu <hjl.tools@gmail.com>
Tue, 13 Jan 2026 22:59:28 +0000 (06:59 +0800)
Call _bfd_elf_section_from_bfd_section to get the sh_link value from
the section flag 'o' directive, which may point to special sections,
like SHN_ABS or SHN_COMM.  Update readelf to print the special section
names in the sh_link field and replace "internal->sh_link > num" with
"internal->sh_link >= num".

bfd/

PR gas/33744
* elf.c (assign_section_numbers): Call
_bfd_elf_section_from_bfd_section to get the sh_link value.

binutils/

PR gas/33744
* readelf.c (special_defined_section_index): New.
(get_32bit_section_headers): Don't warn special section indexes
in the sh_link field.
(get_64bit_section_headers): Likewise.
(process_section_headers): Print special defined section names.

gas/

PR gas/33744
* testsuite/gas/elf/elf.exp: Run PR gas/33744 tests.
* testsuite/gas/elf/sh-link-abs-1.d: New file.
* testsuite/gas/elf/sh-link-abs-2.d: Likewise.
* testsuite/gas/elf/sh-link-abs-3-32.d: Likewise.
* testsuite/gas/elf/sh-link-abs-3-64.d: Likewise.
* testsuite/gas/elf/sh-link-abs-4-32.d: Likewise.
* testsuite/gas/elf/sh-link-abs-4-64.d: Likewise.
* testsuite/gas/elf/sh-link-abs.s: Likewise.
* testsuite/gas/elf/sh-link-common-1.d: Likewise.
* testsuite/gas/elf/sh-link-common-2.d: Likewise.
* testsuite/gas/elf/sh-link-common-3-32.d: Likewise.
* testsuite/gas/elf/sh-link-common-3-64.d: Likewise.
* testsuite/gas/elf/sh-link-common-4-32.d: Likewise.
* testsuite/gas/elf/sh-link-common-4-64.d: Likewise.
* testsuite/gas/elf/sh-link-common.s: Likewise.
* testsuite/gas/elf/sh-link-large-common-1.d: Likewise.
* testsuite/gas/elf/sh-link-large-common-2.d: Likewise.
* testsuite/gas/elf/sh-link-large-common-3.d: Likewise.
* testsuite/gas/elf/sh-link-large-common-4.d: Likewise.
* testsuite/gas/elf/sh-link-large-common.s: Likewise.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
22 files changed:
bfd/elf.c
binutils/readelf.c
gas/testsuite/gas/elf/elf.exp
gas/testsuite/gas/elf/sh-link-abs-1.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-abs-2.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-abs-3-32.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-abs-3-64.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-abs-4-32.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-abs-4-64.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-abs.s [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-common-1.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-common-2.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-common-3-32.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-common-3-64.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-common-4-32.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-common-4-64.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-common.s [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-large-common-1.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-large-common-2.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-large-common-3.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-large-common-4.d [new file with mode: 0644]
gas/testsuite/gas/elf/sh-link-large-common.s [new file with mode: 0644]

index 8b6dd3ce37024e4d41ae4639a6a9692d23f45289..1177c3c3016ed83fc5a6e58798e0a6d882a4f145 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -4333,7 +4333,8 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
                  return false;
                }
              s = s->output_section;
-             d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+             d->this_hdr.sh_link
+               = _bfd_elf_section_from_bfd_section (abfd, s);
            }
        }
 
index d26e2bfa7b954e87da703f2b8da854c2641ce7dc..5b7fc0dc1de37e492ae7436c3f6f34e5e742f539 100644 (file)
@@ -1010,6 +1010,50 @@ is_ia64_vms (Filedata * filedata)
     && filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_OPENVMS;
 }
 
+/* Return true if NDX is a special defined section index.  */
+
+static bool
+special_defined_section_index (Filedata *filedata, size_t ndx)
+{
+  if (ndx == SHN_ABS || ndx == SHN_COMMON)
+    return true;
+
+  if (filedata != NULL)
+    switch (filedata->file_header.e_machine)
+      {
+      case EM_MIPS:
+       if (ndx == SHN_MIPS_SCOMMON)
+         return true;
+       break;
+
+      case EM_TI_C6000:
+       if (ndx == SHN_TIC6X_SCOMMON)
+         return true;
+       break;
+
+      case EM_X86_64:
+      case EM_L1OM:
+      case EM_K1OM:
+       if (ndx == SHN_X86_64_LCOMMON)
+         return true;
+       break;
+
+      case EM_IA_64:
+       if (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_HPUX
+           && ndx == SHN_IA_64_ANSI_COMMON)
+         return true;
+
+       if (is_ia64_vms (filedata) && ndx == SHN_IA_64_VMS_SYMVEC)
+         return true;
+       break;
+
+      default:
+       break;
+      }
+
+  return false;
+}
+
 static const char *
 printable_section_name_from_index (Filedata *  filedata,
                                   size_t      ndx,
@@ -7833,7 +7877,10 @@ get_32bit_section_headers (Filedata * filedata, bool probe)
       internal->sh_info      = BYTE_GET (shdrs[i].sh_info);
       internal->sh_addralign = BYTE_GET (shdrs[i].sh_addralign);
       internal->sh_entsize   = BYTE_GET (shdrs[i].sh_entsize);
-      if (!probe && internal->sh_link > num)
+      if (!probe
+         && internal->sh_link >= num
+         && !special_defined_section_index (filedata,
+                                            internal->sh_link))
        warn (_("Section %u has an out of range sh_link value of %u\n"), i, internal->sh_link);
       if (!probe && internal->sh_flags & SHF_INFO_LINK && internal->sh_info > num)
        warn (_("Section %u has an out of range sh_info value of %u\n"), i, internal->sh_info);
@@ -7905,7 +7952,10 @@ get_64bit_section_headers (Filedata * filedata, bool probe)
       internal->sh_info      = BYTE_GET (shdrs[i].sh_info);
       internal->sh_offset    = BYTE_GET (shdrs[i].sh_offset);
       internal->sh_addralign = BYTE_GET (shdrs[i].sh_addralign);
-      if (!probe && internal->sh_link > num)
+      if (!probe
+         && internal->sh_link >= num
+         && !special_defined_section_index (filedata,
+                                            internal->sh_link))
        warn (_("Section %u has an out of range sh_link value of %u\n"), i, internal->sh_link);
       if (!probe && internal->sh_flags & SHF_INFO_LINK && internal->sh_info > num)
        warn (_("Section %u has an out of range sh_info value of %u\n"), i, internal->sh_info);
@@ -9004,6 +9054,9 @@ process_section_headers (Filedata * filedata)
       printf (do_wide ? " %-15s " : " %-15.15s ",
              get_section_type_name (filedata, section->sh_type));
 
+      bool special_defined_section
+       = special_defined_section_index (filedata, section->sh_link);
+
       if (is_32bit_elf)
        {
          const char * link_too_big = NULL;
@@ -9020,7 +9073,8 @@ process_section_headers (Filedata * filedata)
          else
            printf (" %3s ", get_elf_section_flags (filedata, section->sh_flags));
 
-         if (section->sh_link >= filedata->file_header.e_shnum)
+         if (!special_defined_section
+             && section->sh_link >= filedata->file_header.e_shnum)
            {
              link_too_big = "";
              /* The sh_link value is out of range.  Normally this indicates
@@ -9046,20 +9100,27 @@ process_section_headers (Filedata * filedata)
                }
            }
 
+         if (special_defined_section)
+           printf ("%2s ",
+                   printable_section_name_from_index (filedata,
+                                                      section->sh_link,
+                                                      NULL));
+
          if (do_section_details)
            {
-             if (link_too_big != NULL && * link_too_big)
-               printf ("<%s> ", link_too_big);
-             else
-               printf ("%2u ", section->sh_link);
-             printf ("%3u %2lu\n", section->sh_info,
-                     (unsigned long) section->sh_addralign);
+             if (!special_defined_section)
+               {
+                 if (link_too_big != NULL && * link_too_big)
+                   printf ("<%s> ", link_too_big);
+                 else
+                   printf ("%2u ", section->sh_link);
+               }
            }
-         else
-           printf ("%2u %3u %2lu\n",
-                   section->sh_link,
-                   section->sh_info,
-                   (unsigned long) section->sh_addralign);
+         else if (!special_defined_section)
+           printf ("%2u ", section->sh_link);
+
+         printf ("%3u %2lu\n", section->sh_info,
+                 (unsigned long) section->sh_addralign);
 
          if (link_too_big && ! * link_too_big)
            warn (_("section %u: sh_link value of %u is larger than the number of sections\n"),
@@ -9096,9 +9157,17 @@ process_section_headers (Filedata * filedata)
          if (do_section_details)
            fputs ("  ", stdout);
          else
-           printf (" %3s ", get_elf_section_flags (filedata, section->sh_flags));
-
-         printf ("%2u %3u ", section->sh_link, section->sh_info);
+           printf (" %3s ", get_elf_section_flags (filedata,
+                                                   section->sh_flags));
+
+         if (special_defined_section)
+           printf ("%2s ",
+                   printable_section_name_from_index (filedata,
+                                                      section->sh_link,
+                                                      NULL));
+         else
+           printf ("%2u ", section->sh_link);
+         printf ("%3u ", section->sh_info);
 
          if ((unsigned long) section->sh_addralign == section->sh_addralign)
            printf ("%2lu\n", (unsigned long) section->sh_addralign);
@@ -9119,7 +9188,13 @@ process_section_headers (Filedata * filedata)
              printf ("  ");
              print_vma (section->sh_offset, LONG_HEX);
            }
-         printf ("  %u\n       ", section->sh_link);
+         if (special_defined_section)
+           printf ("  %s\n       ",
+                   printable_section_name_from_index (filedata,
+                                                      section->sh_link,
+                                                      NULL));
+         else
+           printf ("  %u\n       ", section->sh_link);
          print_vma (section->sh_size, LONG_HEX);
          putchar (' ');
          print_vma (section->sh_entsize, LONG_HEX);
@@ -9146,8 +9221,15 @@ process_section_headers (Filedata * filedata)
 
          printf (" %3s ", get_elf_section_flags (filedata, section->sh_flags));
 
-         printf ("     %2u   %3u     %lu\n",
-                 section->sh_link,
+         if (special_defined_section)
+           printf ("     %2s",
+                   printable_section_name_from_index (filedata,
+                                                      section->sh_link,
+                                                      NULL));
+         else
+           printf ("     %2u",
+                   section->sh_link);
+         printf ("   %3u     %lu\n",
                  section->sh_info,
                  (unsigned long) section->sh_addralign);
        }
index 35e06ce58b3b1660a0769442e65a329f505dd9dc..b4b4272ab9fa0b4a0a33e142e05219a667c747db 100644 (file)
@@ -290,6 +290,25 @@ if { [is_elf_format] } then {
     run_dump_test "section28"
     run_dump_test "section29"
     run_dump_test "section30" $dump_opts
+    run_dump_test "sh-link-abs-1"
+    run_dump_test "sh-link-abs-2"
+    run_dump_test "sh-link-common-1"
+    run_dump_test "sh-link-common-2"
+    if [is_elf64 tmpdir/section30.o] {
+       run_dump_test "sh-link-abs-3-64"
+       run_dump_test "sh-link-abs-4-64"
+       run_dump_test "sh-link-common-3-64"
+       run_dump_test "sh-link-common-4-64"
+       run_dump_test "sh-link-large-common-1"
+       run_dump_test "sh-link-large-common-2"
+       run_dump_test "sh-link-large-common-3"
+       run_dump_test "sh-link-large-common-4"
+    } else {
+       run_dump_test "sh-link-abs-3-32"
+       run_dump_test "sh-link-abs-4-32"
+       run_dump_test "sh-link-common-3-32"
+       run_dump_test "sh-link-common-4-32"
+    }
     run_dump_test "sh-link-zero"
     run_dump_test "string"
     run_dump_test "size"
diff --git a/gas/testsuite/gas/elf/sh-link-abs-1.d b/gas/testsuite/gas/elf/sh-link-abs-1.d
new file mode 100644 (file)
index 0000000..7010df0
--- /dev/null
@@ -0,0 +1,6 @@
+#source: sh-link-abs.s
+#readelf: -SW
+
+#...
+ +\[ *[0-9]+\] +__patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[248] +0+ +WAL +ABS +0 +1
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-abs-2.d b/gas/testsuite/gas/elf/sh-link-abs-2.d
new file mode 100644 (file)
index 0000000..e3058a9
--- /dev/null
@@ -0,0 +1,8 @@
+#source: sh-link-abs.s
+#readelf: -tW
+
+#...
+ +\[ *[0-9]+\] +__patchable_function_entries
+ +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[248] +0+ +ABS +0 +1
+ +\[0+83\]: WRITE, ALLOC, LINK ORDER
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-abs-3-32.d b/gas/testsuite/gas/elf/sh-link-abs-3-32.d
new file mode 100644 (file)
index 0000000..efac2f1
--- /dev/null
@@ -0,0 +1,6 @@
+#source: sh-link-abs.s
+#readelf: -S
+
+#...
+ +\[ *[0-9]+\] +__patchable_\[\.\.\.\] +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[248] +0+ +WAL +ABS +0 +1
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-abs-3-64.d b/gas/testsuite/gas/elf/sh-link-abs-3-64.d
new file mode 100644 (file)
index 0000000..5724d27
--- /dev/null
@@ -0,0 +1,7 @@
+#source: sh-link-abs.s
+#readelf: -S
+
+#...
+ +\[ *[0-9]+\] +__patchable_\[\.\.\.\] +PROGBITS +[0-9a-f]+ +[0-9a-f]+
+ +0+[248] +0+ +WAL +ABS +0 +1
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-abs-4-32.d b/gas/testsuite/gas/elf/sh-link-abs-4-32.d
new file mode 100644 (file)
index 0000000..31387c4
--- /dev/null
@@ -0,0 +1,8 @@
+#source: sh-link-abs.s
+#readelf: -t
+
+#...
+ +\[ *[0-9]+\] +__patchable_function_entries
+ +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[248] +0+ +ABS +0 +1
+ +\[0+83\]: WRITE, ALLOC, LINK ORDER
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-abs-4-64.d b/gas/testsuite/gas/elf/sh-link-abs-4-64.d
new file mode 100644 (file)
index 0000000..d0ae74d
--- /dev/null
@@ -0,0 +1,9 @@
+#source: sh-link-abs.s
+#readelf: -t
+
+#...
+ +\[ *[0-9]+\] +__patchable_function_entries
+ +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +ABS
+ +0+[248] +0+ +0 +1
+ +\[0+83\]: WRITE, ALLOC, LINK ORDER
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-abs.s b/gas/testsuite/gas/elf/sh-link-abs.s
new file mode 100644 (file)
index 0000000..7094c77
--- /dev/null
@@ -0,0 +1,6 @@
+       .section __patchable_function_entries,"awo",%progbits,foo
+       .dc.a   .LPFE1
+       .text
+.LPFE1:
+       .byte 0
+       .set    foo,0x1000
diff --git a/gas/testsuite/gas/elf/sh-link-common-1.d b/gas/testsuite/gas/elf/sh-link-common-1.d
new file mode 100644 (file)
index 0000000..1e042ef
--- /dev/null
@@ -0,0 +1,6 @@
+#source: sh-link-common.s
+#readelf: -SW
+
+#...
+ +\[ *[0-9]+\] +__patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[248] +0+ +WAL +COM +0 +1
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-common-2.d b/gas/testsuite/gas/elf/sh-link-common-2.d
new file mode 100644 (file)
index 0000000..aaed278
--- /dev/null
@@ -0,0 +1,8 @@
+#source: sh-link-common.s
+#readelf: -tW
+
+#...
+ +\[ *[0-9]+\] +__patchable_function_entries
+ +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[248] +0+ +COM +0 +1
+ +\[0+83\]: WRITE, ALLOC, LINK ORDER
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-common-3-32.d b/gas/testsuite/gas/elf/sh-link-common-3-32.d
new file mode 100644 (file)
index 0000000..e2ca20f
--- /dev/null
@@ -0,0 +1,6 @@
+#source: sh-link-common.s
+#readelf: -S
+
+#...
+ +\[ *[0-9]+\] +__patchable_\[\.\.\.\] +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[248] +0+ +WAL +COM +0 +1
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-common-3-64.d b/gas/testsuite/gas/elf/sh-link-common-3-64.d
new file mode 100644 (file)
index 0000000..86a2b9f
--- /dev/null
@@ -0,0 +1,7 @@
+#source: sh-link-common.s
+#readelf: -S
+
+#...
+ +\[ *[0-9]+\] +__patchable_\[\.\.\.\] +PROGBITS +[0-9a-f]+ +[0-9a-f]+
+ +0+[248] +0+ +WAL +COM +0 +1
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-common-4-32.d b/gas/testsuite/gas/elf/sh-link-common-4-32.d
new file mode 100644 (file)
index 0000000..ad0bb1b
--- /dev/null
@@ -0,0 +1,8 @@
+#source: sh-link-common.s
+#readelf: -t
+
+#...
+ +\[ *[0-9]+\] +__patchable_function_entries
+ +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[248] +0+ +COM +0 +1
+ +\[0+83\]: WRITE, ALLOC, LINK ORDER
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-common-4-64.d b/gas/testsuite/gas/elf/sh-link-common-4-64.d
new file mode 100644 (file)
index 0000000..4637b72
--- /dev/null
@@ -0,0 +1,9 @@
+#source: sh-link-common.s
+#readelf: -t
+
+#...
+ +\[ *[0-9]+\] +__patchable_function_entries
+ +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +COM
+ +0+[248] +0+ +0 +1
+ +\[0+83\]: WRITE, ALLOC, LINK ORDER
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-common.s b/gas/testsuite/gas/elf/sh-link-common.s
new file mode 100644 (file)
index 0000000..84ec3e4
--- /dev/null
@@ -0,0 +1,6 @@
+       .section __patchable_function_entries,"awo",%progbits,foo
+       .dc.a   .LPFE1
+       .text
+.LPFE1:
+       .byte 0
+        .comm   foo,8
diff --git a/gas/testsuite/gas/elf/sh-link-large-common-1.d b/gas/testsuite/gas/elf/sh-link-large-common-1.d
new file mode 100644 (file)
index 0000000..acf238c
--- /dev/null
@@ -0,0 +1,8 @@
+#source: sh-link-large-common.s
+#readelf: -S
+#target: x86_64-*-*
+
+#...
+ +\[ *[0-9]+\] +__patchable_\[\.\.\.\] +PROGBITS +[0-9a-f]+ +[0-9a-f]+
+ +0+[248] +0+ +WAL +LARGE_COM +0 +1
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-large-common-2.d b/gas/testsuite/gas/elf/sh-link-large-common-2.d
new file mode 100644 (file)
index 0000000..36d9837
--- /dev/null
@@ -0,0 +1,7 @@
+#source: sh-link-large-common.s
+#readelf: -SW
+#target: x86_64-*-*
+
+#...
+ +\[ *[0-9]+\] +__patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[248] +0+ +WAL +LARGE_COM +0 +1
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-large-common-3.d b/gas/testsuite/gas/elf/sh-link-large-common-3.d
new file mode 100644 (file)
index 0000000..d738a90
--- /dev/null
@@ -0,0 +1,10 @@
+#source: sh-link-large-common.s
+#readelf: -t
+#target: x86_64-*-*
+
+#...
+ +\[ *[0-9]+\] +__patchable_function_entries
+ +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +LARGE_COM
+ +0+[248] +0+ +0 +1
+ +\[0+83\]: WRITE, ALLOC, LINK ORDER
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-large-common-4.d b/gas/testsuite/gas/elf/sh-link-large-common-4.d
new file mode 100644 (file)
index 0000000..0101e54
--- /dev/null
@@ -0,0 +1,9 @@
+#source: sh-link-large-common.s
+#readelf: -tW
+#target: x86_64-*-*
+
+#...
+ +\[ *[0-9]+\] +__patchable_function_entries
+ +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[248] +0+ +LARGE_COM +0 +1
+ +\[0+83\]: WRITE, ALLOC, LINK ORDER
+#pass
diff --git a/gas/testsuite/gas/elf/sh-link-large-common.s b/gas/testsuite/gas/elf/sh-link-large-common.s
new file mode 100644 (file)
index 0000000..b2ef554
--- /dev/null
@@ -0,0 +1,6 @@
+       .section __patchable_function_entries,"awo",%progbits,foo
+       .dc.a   .LPFE1
+       .text
+.LPFE1:
+       .byte 0
+       .largecomm foo,30,8