[PATCH 3/4] ELF: SHF_STRINGS isn't really tied to SHF_MERGE

Jan Beulich jbeulich@suse.com
Mon Nov 11 08:44:19 GMT 2024


It's not overly useful without it, but the spec doesn't name any
dependency between the two. People may want to use it for purely
informational purposes, for example. Adjust, in particular, entity size
processing to be engaged if either flag is set, as mandated by the spec.

--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -846,7 +846,10 @@ _bfd_elf_make_section_from_shdr (bfd *ab
       newsect->entsize = hdr->sh_entsize;
     }
   if ((hdr->sh_flags & SHF_STRINGS) != 0)
-    flags |= SEC_STRINGS;
+    {
+      flags |= SEC_STRINGS;
+      newsect->entsize = hdr->sh_entsize;
+    }
   if ((hdr->sh_flags & SHF_TLS) != 0)
     flags |= SEC_THREAD_LOCAL;
   if ((hdr->sh_flags & SHF_EXCLUDE) != 0)
@@ -3709,7 +3712,10 @@ elf_fake_sections (bfd *abfd, asection *
       this_hdr->sh_entsize = asect->entsize;
     }
   if ((asect->flags & SEC_STRINGS) != 0)
-    this_hdr->sh_flags |= SHF_STRINGS;
+    {
+      this_hdr->sh_flags |= SHF_STRINGS;
+      this_hdr->sh_entsize = asect->entsize;
+    }
   if ((asect->flags & SEC_GROUP) == 0 && elf_group_name (asect) != NULL)
     this_hdr->sh_flags |= SHF_GROUP;
   if ((asect->flags & SEC_THREAD_LOCAL) != 0)
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -7001,17 +7001,18 @@ Note - some sections, eg @code{.text} an
 special and have fixed types.  Any attempt to declare them with a different
 type will generate an error from the assembler.
 
-If @var{flags} contains the @code{M} symbol then the @var{type} argument must
-be specified as well as an extra argument---@var{entsize}---like this:
+If @var{flags} contains the @code{M} and/or @code{S} symbol then the @var{type}
+argument must be specified as well as an extra argument---@var{entsize}---like
+this:
 
 @smallexample
 .section @var{name} , "@var{flags}"M, @@@var{type}, @var{entsize}
 @end smallexample
 
 Sections with the @code{M} flag but not @code{S} flag must contain fixed size
-constants, each @var{entsize} octets long. Sections with both @code{M} and
-@code{S} must contain zero terminated strings where each character is
-@var{entsize} bytes long. The linker may remove duplicates within sections with
+constants, each @var{entsize} octets long. Sections with @code{S} must contain
+zero terminated strings where each character is @var{entsize} bytes long. For
+@code{M} sections the linker may remove duplicates within sections with
 the same name, same entity size and same flags.  @var{entsize} must be an
 absolute expression.  For sections with both @code{M} and @code{S}, a string
 which is a suffix of a larger string is considered a duplicate.  Thus
@@ -7031,8 +7032,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 the @var{M} and @var{o} flags are present, then the fields
-for the Merge flag should come first, like this:
+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:
 
 @smallexample
 .section @var{name},"@var{flags}"Mo,@@@var{type},@var{entsize},@var{SymbolName}
@@ -7055,8 +7056,8 @@ indicates that only one copy of this sec
 an alias for comdat
 @end table
 
-Note: if both the @var{M} and @var{G} flags are present then the fields for
-the Merge flag should come first, like this:
+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:
 
 @smallexample
 .section @var{name} , "@var{flags}"MG, @@@var{type}, @var{entsize}, @var{GroupName}[, @var{linkage}]
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -809,7 +809,7 @@ change_section (const char *name,
 	= match_p->linked_to_symbol_name;
 
       bfd_set_section_flags (sec, flags);
-      if (flags & SEC_MERGE)
+      if (flags & (SEC_MERGE | SEC_STRINGS))
 	sec->entsize = entsize;
       elf_group_name (sec) = match_p->group_name;
 
@@ -864,7 +864,8 @@ change_section (const char *name,
 	       processor or application specific attribute as suspicious?  */
 	    elf_section_flags (sec) = attr;
 
-	  if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
+	  if ((flags & (SEC_MERGE | SEC_STRINGS))
+	      && old_sec->entsize != (unsigned) entsize)
 	    as_bad (_("changed section entity size for %s"), name);
 	}
     }
@@ -1318,36 +1319,39 @@ obj_elf_section (int push)
 	    }
 
 	  SKIP_WHITESPACE ();
-	  if ((attr & SHF_MERGE) != 0 && *input_line_pointer == ',')
+	  if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0
+	      && *input_line_pointer == ',')
 	    {
 	      ++input_line_pointer;
 	      SKIP_WHITESPACE ();
 	      if (inherit && *input_line_pointer == ','
-		  && (bfd_section_flags (now_seg) & SEC_MERGE) != 0)
+		  && (bfd_section_flags (now_seg)
+		      & (SEC_MERGE | SEC_STRINGS)) != 0)
 		goto fetch_entsize;
 	      entsize = get_absolute_expression ();
 	      SKIP_WHITESPACE ();
 	      if (entsize <= 0)
 		{
-		  as_warn (_("invalid merge entity size"));
-		  attr &= ~SHF_MERGE;
+		  as_warn (_("invalid merge / string entity size"));
+		  attr &= ~(SHF_MERGE | SHF_STRINGS);
 		  entsize = 0;
 		}
 	    }
-	  else if ((attr & SHF_MERGE) != 0 && inherit
-		    && (bfd_section_flags (now_seg) & SEC_MERGE) != 0)
+	  else if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0 && inherit
+		    && (bfd_section_flags (now_seg)
+			& (SEC_MERGE | SEC_STRINGS)) != 0)
 	    {
 	    fetch_entsize:
 	      entsize = now_seg->entsize;
 	    }
-	  else if ((attr & SHF_MERGE) != 0)
+	  else if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0)
 	    {
-	      as_warn (_("entity size for SHF_MERGE not specified"));
-	      attr &= ~SHF_MERGE;
+	      as_warn (_("entity size for SHF_MERGE / SHF_STRINGS not specified"));
+	      attr &= ~(SHF_MERGE | SHF_STRINGS);
 	    }
 
-	  if ((attr & SHF_MERGE) != 0 && type == SHT_NOBITS)
-	    as_warn (_("bogus SHF_MERGE for SHT_NOBITS section"));
+	  if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0 && type == SHT_NOBITS)
+	    as_warn (_("bogus SHF_MERGE / SHF_STRINGS for SHT_NOBITS section"));
 
 	  if ((attr & SHF_LINK_ORDER) != 0 && *input_line_pointer == ',')
 	    {
--- a/gas/write.c
+++ b/gas/write.c
@@ -1864,7 +1864,7 @@ subsegs_finish_section (asection *s)
 	do_not_pad_sections_to_alignment = 1;
 
       alignment = SUB_SEGMENT_ALIGN (now_seg, frchainP);
-      if ((bfd_section_flags (now_seg) & SEC_MERGE)
+      if ((bfd_section_flags (now_seg) & (SEC_MERGE | SEC_STRINGS))
 	  && now_seg->entsize)
 	{
 	  unsigned int entsize = now_seg->entsize;
It's not overly useful without it, but the spec doesn't name any
dependency between the two. People may want to use it for purely
informational purposes, for example. Adjust in particular entity size
processing to be engaged if either flag is set, as mandated by the spec.

--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -846,7 +846,10 @@ _bfd_elf_make_section_from_shdr (bfd *ab
       newsect->entsize = hdr->sh_entsize;
     }
   if ((hdr->sh_flags & SHF_STRINGS) != 0)
-    flags |= SEC_STRINGS;
+    {
+      flags |= SEC_STRINGS;
+      newsect->entsize = hdr->sh_entsize;
+    }
   if ((hdr->sh_flags & SHF_TLS) != 0)
     flags |= SEC_THREAD_LOCAL;
   if ((hdr->sh_flags & SHF_EXCLUDE) != 0)
@@ -3709,7 +3712,10 @@ elf_fake_sections (bfd *abfd, asection *
       this_hdr->sh_entsize = asect->entsize;
     }
   if ((asect->flags & SEC_STRINGS) != 0)
-    this_hdr->sh_flags |= SHF_STRINGS;
+    {
+      this_hdr->sh_flags |= SHF_STRINGS;
+      this_hdr->sh_entsize = asect->entsize;
+    }
   if ((asect->flags & SEC_GROUP) == 0 && elf_group_name (asect) != NULL)
     this_hdr->sh_flags |= SHF_GROUP;
   if ((asect->flags & SEC_THREAD_LOCAL) != 0)
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -7001,17 +7001,18 @@ Note - some sections, eg @code{.text} an
 special and have fixed types.  Any attempt to declare them with a different
 type will generate an error from the assembler.
 
-If @var{flags} contains the @code{M} symbol then the @var{type} argument must
-be specified as well as an extra argument---@var{entsize}---like this:
+If @var{flags} contains the @code{M} and/or @code{S} symbol then the @var{type}
+argument must be specified as well as an extra argument---@var{entsize}---like
+this:
 
 @smallexample
 .section @var{name} , "@var{flags}"M, @@@var{type}, @var{entsize}
 @end smallexample
 
 Sections with the @code{M} flag but not @code{S} flag must contain fixed size
-constants, each @var{entsize} octets long. Sections with both @code{M} and
-@code{S} must contain zero terminated strings where each character is
-@var{entsize} bytes long. The linker may remove duplicates within sections with
+constants, each @var{entsize} octets long. Sections with @code{S} must contain
+zero terminated strings where each character is @var{entsize} bytes long. For
+@code{M} sections the linker may remove duplicates within sections with
 the same name, same entity size and same flags.  @var{entsize} must be an
 absolute expression.  For sections with both @code{M} and @code{S}, a string
 which is a suffix of a larger string is considered a duplicate.  Thus
@@ -7031,8 +7032,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 the @var{M} and @var{o} flags are present, then the fields
-for the Merge flag should come first, like this:
+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:
 
 @smallexample
 .section @var{name},"@var{flags}"Mo,@@@var{type},@var{entsize},@var{SymbolName}
@@ -7055,8 +7056,8 @@ indicates that only one copy of this sec
 an alias for comdat
 @end table
 
-Note: if both the @var{M} and @var{G} flags are present then the fields for
-the Merge flag should come first, like this:
+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:
 
 @smallexample
 .section @var{name} , "@var{flags}"MG, @@@var{type}, @var{entsize}, @var{GroupName}[, @var{linkage}]
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -809,7 +809,7 @@ change_section (const char *name,
 	= match_p->linked_to_symbol_name;
 
       bfd_set_section_flags (sec, flags);
-      if (flags & SEC_MERGE)
+      if (flags & (SEC_MERGE | SEC_STRINGS))
 	sec->entsize = entsize;
       elf_group_name (sec) = match_p->group_name;
 
@@ -864,7 +864,8 @@ change_section (const char *name,
 	       processor or application specific attribute as suspicious?  */
 	    elf_section_flags (sec) = attr;
 
-	  if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
+	  if ((flags & (SEC_MERGE | SEC_STRINGS))
+	      && old_sec->entsize != (unsigned) entsize)
 	    as_bad (_("changed section entity size for %s"), name);
 	}
     }
@@ -1318,36 +1319,39 @@ obj_elf_section (int push)
 	    }
 
 	  SKIP_WHITESPACE ();
-	  if ((attr & SHF_MERGE) != 0 && *input_line_pointer == ',')
+	  if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0
+	      && *input_line_pointer == ',')
 	    {
 	      ++input_line_pointer;
 	      SKIP_WHITESPACE ();
 	      if (inherit && *input_line_pointer == ','
-		  && (bfd_section_flags (now_seg) & SEC_MERGE) != 0)
+		  && (bfd_section_flags (now_seg)
+		      & (SEC_MERGE | SEC_STRINGS)) != 0)
 		goto fetch_entsize;
 	      entsize = get_absolute_expression ();
 	      SKIP_WHITESPACE ();
 	      if (entsize <= 0)
 		{
-		  as_warn (_("invalid merge entity size"));
-		  attr &= ~SHF_MERGE;
+		  as_warn (_("invalid merge / string entity size"));
+		  attr &= ~(SHF_MERGE | SHF_STRINGS);
 		  entsize = 0;
 		}
 	    }
-	  else if ((attr & SHF_MERGE) != 0 && inherit
-		    && (bfd_section_flags (now_seg) & SEC_MERGE) != 0)
+	  else if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0 && inherit
+		    && (bfd_section_flags (now_seg)
+			& (SEC_MERGE | SEC_STRINGS)) != 0)
 	    {
 	    fetch_entsize:
 	      entsize = now_seg->entsize;
 	    }
-	  else if ((attr & SHF_MERGE) != 0)
+	  else if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0)
 	    {
-	      as_warn (_("entity size for SHF_MERGE not specified"));
-	      attr &= ~SHF_MERGE;
+	      as_warn (_("entity size for SHF_MERGE / SHF_STRINGS not specified"));
+	      attr &= ~(SHF_MERGE | SHF_STRINGS);
 	    }
 
-	  if ((attr & SHF_MERGE) != 0 && type == SHT_NOBITS)
-	    as_warn (_("bogus SHF_MERGE for SHT_NOBITS section"));
+	  if ((attr & (SHF_MERGE | SHF_STRINGS)) != 0 && type == SHT_NOBITS)
+	    as_warn (_("bogus SHF_MERGE / SHF_STRINGS for SHT_NOBITS section"));
 
 	  if ((attr & SHF_LINK_ORDER) != 0 && *input_line_pointer == ',')
 	    {
--- a/gas/write.c
+++ b/gas/write.c
@@ -1864,7 +1864,7 @@ subsegs_finish_section (asection *s)
 	do_not_pad_sections_to_alignment = 1;
 
       alignment = SUB_SEGMENT_ALIGN (now_seg, frchainP);
-      if ((bfd_section_flags (now_seg) & SEC_MERGE)
+      if ((bfd_section_flags (now_seg) & (SEC_MERGE | SEC_STRINGS))
 	  && now_seg->entsize)
 	{
 	  unsigned int entsize = now_seg->entsize;



More information about the Binutils mailing list