]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gas/ELF: allow specifying entity size for arbitrary sections
authorJan Beulich <jbeulich@suse.com>
Fri, 15 Aug 2025 10:19:59 +0000 (12:19 +0200)
committerJan Beulich <jbeulich@suse.com>
Fri, 15 Aug 2025 10:19:59 +0000 (12:19 +0200)
The spec doesn't tie entity size to just SHF_MERGE and SHF_STRINGS
sections. Introduce a new "section letter" 'E' to allow recording (and
checking) of entity size even without 'M' or 'S'.

bfd/elf.c
gas/NEWS
gas/config/obj-elf.c
gas/doc/as.texi
gas/testsuite/gas/elf/elf.exp
gas/testsuite/gas/elf/entsize.d [new file with mode: 0644]
gas/testsuite/gas/elf/entsize.s [new file with mode: 0644]

index 596c1ec3de20599d83d077a42aa2edf4a7e13a3e..589400ec681de3450d904895e5b3ea8deaba2745 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -869,20 +869,16 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
   else if ((flags & SEC_LOAD) != 0)
     flags |= SEC_DATA;
   if ((hdr->sh_flags & SHF_MERGE) != 0)
-    {
-      flags |= SEC_MERGE;
-      newsect->entsize = hdr->sh_entsize;
-    }
+    flags |= SEC_MERGE;
   if ((hdr->sh_flags & SHF_STRINGS) != 0)
-    {
-      flags |= SEC_STRINGS;
-      newsect->entsize = hdr->sh_entsize;
-    }
+    flags |= SEC_STRINGS;
   if ((hdr->sh_flags & SHF_TLS) != 0)
     flags |= SEC_THREAD_LOCAL;
   if ((hdr->sh_flags & SHF_EXCLUDE) != 0)
     flags |= SEC_EXCLUDE;
 
+  newsect->entsize = hdr->sh_entsize;
+
   switch (elf_elfheader (abfd)->e_ident[EI_OSABI])
     {
       /* FIXME: We should not recognize SHF_GNU_MBIND for ELFOSABI_NONE,
@@ -3770,6 +3766,9 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
   if ((asect->flags & (SEC_GROUP | SEC_EXCLUDE)) == SEC_EXCLUDE)
     this_hdr->sh_flags |= SHF_EXCLUDE;
 
+  if (this_hdr->sh_entsize == 0)
+    this_hdr->sh_entsize = asect->entsize;
+
   /* If the section has relocs, set up a section header for the
      SHT_REL[A] section.  If two relocation sections are required for
      this section, it is up to the processor-specific back-end to
index a9858939f06e45ca5f05d61f6931632b88b934a1..5908f769fddd91a262b70af23f5cd0fc130f0e7d 100644 (file)
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* ELF targets can now have section entity size specified for arbitrary
+  sections, using the new attribute letter 'E'.
+
 * NaCl target support is removed.
 
 Changes in 2.45:
index b39c59e54b8d3b7b4a5b6c8176fe4644acf7053a..ccf020f5a8406df92e5b6187b7d434447d8bba6e 100644 (file)
@@ -792,7 +792,7 @@ change_section (const char *name,
        = match_p->linked_to_symbol_name;
 
       bfd_set_section_flags (sec, flags);
-      if (flags & (SEC_MERGE | SEC_STRINGS))
+      if (entsize != 0)
        sec->entsize = entsize;
       elf_group_name (sec) = match_p->group_name;
 
@@ -847,7 +847,7 @@ change_section (const char *name,
               processor or application specific attribute as suspicious?  */
            elf_section_flags (sec) = attr;
 
-         if ((flags & (SEC_MERGE | SEC_STRINGS))
+         if (entsize != 0
              && old_sec->entsize != (unsigned) entsize)
            as_bad (_("changed section entity size for %s"), name);
        }
@@ -871,7 +871,8 @@ obj_elf_change_section (const char *name,
 
 static bfd_vma
 obj_elf_parse_section_letters (char *str, size_t len, bool push,
-                              bool *is_clone, int *inherit, bfd_vma *gnu_attr)
+                              bool *is_clone, int *inherit, bfd_vma *gnu_attr,
+                              bool *has_entsize)
 {
   bfd_vma attr = 0;
 
@@ -913,6 +914,9 @@ obj_elf_parse_section_letters (char *str, size_t len, bool push,
        case 'x':
          attr |= SHF_EXECINSTR;
          break;
+       case 'E':
+         *has_entsize = true;
+         break;
        case 'G':
          attr |= SHF_GROUP;
          break;
@@ -978,8 +982,8 @@ obj_elf_parse_section_letters (char *str, size_t len, bool push,
                {
                  as_bad (_("unrecognized .%ssection attribute: want %s%s%s,? or number"),
                    push ? "push" : "",
-                   gnu_attr != NULL ? "a,d,e,o,w,x,G,M,R,S,T"
-                                    : "a,e,o,w,x,G,M,S,T",
+                   gnu_attr != NULL ? "a,d,e,o,w,x,E,G,M,R,S,T"
+                                    : "a,e,o,w,x,E,G,M,S,T",
                    md_extra != NULL ? "," : "", md_extra);
                  return attr;
                }
@@ -1187,7 +1191,7 @@ obj_elf_section (int push)
   bfd_vma attr;
   bfd_vma gnu_attr;
   int entsize;
-  bool linkonce;
+  bool linkonce, has_entsize;
   subsegT new_subsection = 0;
   struct elf_section_match match;
   unsigned long linked_to_section_index = -1UL;
@@ -1232,6 +1236,7 @@ obj_elf_section (int push)
   attr = 0;
   gnu_attr = 0;
   entsize = 0;
+  has_entsize = false;
   linkonce = 0;
 
   if (*input_line_pointer == ',')
@@ -1276,7 +1281,8 @@ obj_elf_section (int push)
                                                    == ELFOSABI_GNU)
                                                || (bed->elf_osabi
                                                    == ELFOSABI_FREEBSD)
-                                               ? &gnu_attr : NULL);
+                                               ? &gnu_attr : NULL,
+                                               &has_entsize);
 
          if (inherit > 0)
            attr |= elf_section_flags (now_seg);
@@ -1285,6 +1291,9 @@ obj_elf_section (int push)
          if (inherit)
            type = elf_section_type (now_seg);
 
+         if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0)
+           has_entsize = true;
+
          SKIP_WHITESPACE ();
          if (*input_line_pointer == ',')
            {
@@ -1324,16 +1333,18 @@ obj_elf_section (int push)
            }
 
          SKIP_WHITESPACE ();
-         if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0
-             && *input_line_pointer == ',')
+         if (has_entsize && *input_line_pointer == ',')
            {
              ++input_line_pointer;
              SKIP_WHITESPACE ();
              if (inherit && *input_line_pointer == ','
+                 && ((bfd_section_flags (now_seg)
+                      & (SEC_MERGE | SEC_STRINGS)) != 0
+                     || now_seg->entsize))
+               goto fetch_entsize;
+             if (is_end_of_stmt (*input_line_pointer)
                  && (bfd_section_flags (now_seg)
                      & (SEC_MERGE | SEC_STRINGS)) != 0)
-               goto fetch_entsize;
-             if (is_end_of_stmt (*input_line_pointer))
                {
                  /* ??? This is here for older versions of gcc that
                     test for gas string merge support with
@@ -1341,7 +1352,7 @@ obj_elf_section (int push)
                     Unfortunately '@' begins a comment on arm.
                     This isn't as_warn because gcc tests with
                     --fatal-warnings. */
-                 as_tsktsk (_("missing merge / string entity size, 1 assumed"));
+                 as_tsktsk (_("missing section entity size, 1 assumed"));
                  entsize = 1;
                }
              else
@@ -1350,15 +1361,17 @@ obj_elf_section (int push)
                  SKIP_WHITESPACE ();
                  if (entsize <= 0)
                    {
-                     as_warn (_("invalid merge / string entity size"));
+                     as_warn (_("invalid section entity size"));
                      attr &= ~(SHF_MERGE | SHF_STRINGS);
+                     has_entsize = false;
                      entsize = 0;
                    }
                }
            }
-         else if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0 && inherit
-                   && (bfd_section_flags (now_seg)
-                       & (SEC_MERGE | SEC_STRINGS)) != 0)
+         else if (has_entsize && inherit
+                   && ((bfd_section_flags (now_seg)
+                        & (SEC_MERGE | SEC_STRINGS)) != 0
+                       || now_seg->entsize))
            {
            fetch_entsize:
              entsize = now_seg->entsize;
@@ -1369,6 +1382,7 @@ obj_elf_section (int push)
                 entsize must be specified if SHF_MERGE is set.  */
              as_warn (_("entity size for SHF_MERGE not specified"));
              attr &= ~(SHF_MERGE | SHF_STRINGS);
+             has_entsize = false;
            }
          else if ((attr & SHF_STRINGS) != 0)
            {
@@ -1378,6 +1392,11 @@ obj_elf_section (int push)
                 compatibility.  */
              entsize = 1;
            }
+         else if (has_entsize)
+           {
+             as_warn (_("entity size not specified"));
+             has_entsize = false;
+           }
 
          if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0 && type == SHT_NOBITS)
            as_warn (_("bogus SHF_MERGE / SHF_STRINGS for SHT_NOBITS section"));
index 1cb1fd879a44d6b35ebd0b20900b1658cc0a7a02..2db5f4896ee76b3de5df0db2d72f3a2893128a51 100644 (file)
@@ -7004,12 +7004,14 @@ section) in the same file.
 section is writable
 @item x
 section is executable
+@item E
+section has a (non-zero) element/entry size
+@item G
+section is a member of a section group
 @item M
 section is mergeable
 @item S
 section contains zero terminated strings
-@item G
-section is a member of a section group
 @item T
 section is used for thread-local-storage
 @item ?
@@ -7118,8 +7120,8 @@ is not generally a good idea as section indices are rarely known at assembly
 time, but the facility is provided for testing purposes.  An index of zero is
 allowed.  It indicates that the linked-to section has already been discarded.
 
-Note: If both one of @var{M} or @var{S} and @var{o} flags are present, then the
-fields for the Merge/String flag should come first, like this:
+Note: If both one of @var{M}, @var{S}, or @var{E} and @var{o} flags are present,
+then the type and entry size fields should come first, like this:
 
 @smallexample
 .section @var{name},"@var{flags}"Mo,@@@var{type},@var{entsize},@var{SymbolName}
@@ -7142,8 +7144,8 @@ indicates that only one copy of this section should be retained
 an alias for comdat
 @end table
 
-Note: Uf both one of @var{M} or @var{S} and @var{G} flags are present then the
-fields for the Merge/String flag should come first, like this:
+Note: If both one of @var{M}, @var{S}, or @var{E} and @var{G} flags are present
+then the type and entry size fields should come first, like this:
 
 @smallexample
 .section @var{name} , "@var{flags}"MG, @@@var{type}, @var{entsize}, @var{GroupName}[, @var{linkage}]
index ab97e5e751b7783699d2141302b949ab26891963..1988788fbcd86f63a7923c03089a0379ebce964e 100644 (file)
@@ -293,6 +293,7 @@ if { [is_elf_format] } then {
     run_dump_test "sh-link-zero"
     run_dump_test "string"
     run_dump_test "size"
+    run_dump_test "entsize"
     run_dump_test "dwarf2-1" $dump_opts
     run_dump_test "dwarf2-2" $dump_opts
     run_dump_test "dwarf2-3" $dump_opts
diff --git a/gas/testsuite/gas/elf/entsize.d b/gas/testsuite/gas/elf/entsize.d
new file mode 100644 (file)
index 0000000..77835cb
--- /dev/null
@@ -0,0 +1,9 @@
+#readelf: -SW
+#name: sections with entity size
+
+#...
+[      ]*\[.*\][       ]+\.merge[      ]+PROGBITS[     ]+0+[   ]+[0-9a-f]+[    ]+0+18[         ]+0c[   ]+AM[   ].*
+[      ]*\[.*\][       ]+\.string[     ]+PROGBITS[     ]+0+[   ]+[0-9a-f]+[    ]+0+6[  ]+02[   ]+AS[   ].*
+[      ]*\[.*\][       ]+\.custom[     ]+PROGBITS[     ]+0+[   ]+[0-9a-f]+[    ]+0+c[  ]+06[   ]+A[    ].*
+[      ]*\[.*\][       ]+\.bss\.custom[        ]+NOBITS[       ]+0+[   ]+[0-9a-f]+[    ]+0+1e[         ]+06[   ]+WA[   ].*
+#pass
diff --git a/gas/testsuite/gas/elf/entsize.s b/gas/testsuite/gas/elf/entsize.s
new file mode 100644 (file)
index 0000000..490de34
--- /dev/null
@@ -0,0 +1,8 @@
+       .section .merge, "aM", 12
+       .dc.l 1, 2, 3, 4, 5, 6
+       .section .string, "aS", %progbits, 2
+       .dc.w 0x0020, 0x0021, 0x0022
+       .section .custom, "aE", 6
+       .dc.w 5, 6, 7, 8, 9, 0
+       .section .bss.custom, "awE", %nobits, 6
+       .skip 30