[PATCH v2 5/5] gas/ELF: allow specifying entity size for arbitrary sections

Jan Beulich jbeulich@suse.com
Fri Aug 1 13:26:10 GMT 2025
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'.
---
Right now the behavior is that

	.section .custom,"aE",4
	.section .custom,"a",@progbits

would work fine, while

	.section .custom,"a",@progbits
	.section .custom,"aE",4

causes a "changed section entity size" error. Is it really a problem if
the entity size is specified only later? (Of course an error wants to be
issued in all cases when different non-zero sizes are used.)

As far as the linker is concerned, I find it difficult to establish a
sensible checking strategy: On one hand multiple sections with otherwise
similar attributes would better have matching entity size too. Otoh all
kinds of input sections may be merged into a single output one, and we
likely can't expect them to all match in this regard. Maybe the
granularity of such checking would want to be any single Input Section
Description? (As of now, entity sizes are simply lost in the course of
linking. Which may be the intended behavior.)
---
v2: New.

--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -865,20 +865,16 @@ _bfd_elf_make_section_from_shdr (bfd *ab
   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,
@@ -3766,6 +3762,9 @@ elf_fake_sections (bfd *abfd, asection *
   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
--- 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:
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -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
 	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
 		{
 		  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"));
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -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
 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 sec
 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}]
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -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
--- /dev/null
+++ b/gas/testsuite/gas/elf/entsize.d
@@ -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
--- /dev/null
+++ b/gas/testsuite/gas/elf/entsize.s
@@ -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



More information about the Binutils mailing list