[PATCH v2 3/5] gas/ELF: re-work SHF_GNU_* handling

Jan Beulich jbeulich@suse.com
Fri Aug 1 13:24:33 GMT 2025


Indicate to obj_elf_parse_section_letters() whether to recognize GNU-
specific flags by conditionally passing NULL in place of a pointer to
the GNU attributes. This way wrong use of d and R can be diagnosed just
like any other use of unrecognized letters.

Furthermore adjust the md_elf_section_letter() interface: Have targets
merely return the extra letters they support. There's no point having
them customize the entire diagnostic. Even more so that additions in
common code would then reflecting in every target's diagnostic as well,
which - as can be seen - wasn't always properly done.

There's also no reason for wrong letters to be a fatal error; switch to
as_bad() while making other adjustments there.

While making the target specific adjustments, also drop IA-64's dead
handling of 'o' (SHF_LINK_ORDER), which has been covered by common code
for a long time.

Also re-arrange the switch() in obj_elf_parse_section_letters() to be
alphabetically sorted again.
---
What doesn't fit well with the diagnostic are + and - (suggestions
welcome).

Allowing a numeric specifier to be followed by further letters feels
bogus: Especially when the numeric value is specified in hex, the input
can end up ambiguous (e.g. 0x1000a).

Allowing a numeric specifier of value 0 also causes an anomaly: While
generally we enforce + or - to come first, that detection is broken for
"0+" or "0-".
---
v2: New.

--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -896,6 +896,11 @@ obj_elf_parse_section_letters (char *str
 		}
 	    }
 	  break;
+	case 'd':
+	  if (gnu_attr == NULL)
+	    goto unrecognized;
+	  *gnu_attr |= SHF_GNU_MBIND;
+	  break;
 	case 'e':
 	  attr |= SHF_EXCLUDE;
 	  break;
@@ -908,33 +913,33 @@ obj_elf_parse_section_letters (char *str
 	case 'x':
 	  attr |= SHF_EXECINSTR;
 	  break;
+	case 'G':
+	  attr |= SHF_GROUP;
+	  break;
 	case 'M':
 	  attr |= SHF_MERGE;
 	  break;
+	case 'R':
+	  if (gnu_attr == NULL)
+	    goto unrecognized;
+	  *gnu_attr |= SHF_GNU_RETAIN;
+	  break;
 	case 'S':
 	  attr |= SHF_STRINGS;
 	  break;
-	case 'G':
-	  attr |= SHF_GROUP;
-	  break;
 	case 'T':
 	  attr |= SHF_TLS;
 	  break;
-	case 'd':
-	  *gnu_attr |= SHF_GNU_MBIND;
-	  break;
-	case 'R':
-	  *gnu_attr |= SHF_GNU_RETAIN;
-	  break;
 	case '?':
 	  *is_clone = true;
 	  break;
 	default:
+	unrecognized:
 	  {
-	    const char *bad_msg = _("unrecognized .section attribute:"
-				    " want a,e,o,w,x,M,S,G,T or number");
+	    const char *md_extra = "";
+
 #ifdef md_elf_section_letter
-	    bfd_vma md_attr = md_elf_section_letter (*str, &bad_msg);
+	    bfd_vma md_attr = md_elf_section_letter (*str, &md_extra);
 	    if (md_attr != (bfd_vma) -1)
 	      attr |= md_attr;
 	    else
@@ -942,21 +947,14 @@ obj_elf_parse_section_letters (char *str
 	      if (ISDIGIT (*str))
 		{
 		  char * end;
-		  const struct elf_backend_data *bed;
 		  bfd_vma numeric_flags = strtoul (str, &end, 0);
 
 		  attr |= numeric_flags;
 
-		  bed = get_elf_backend_data (stdoutput);
-
-		  if (bed->elf_osabi == ELFOSABI_NONE
-		      || bed->elf_osabi == ELFOSABI_GNU
-		      || bed->elf_osabi == ELFOSABI_FREEBSD)
+		  if (gnu_attr != NULL)
 		    {
 		      /* Add flags in the SHF_MASKOS range to gnu_attr for
 			 OSABIs that support those flags.
-			 Also adding the flags for ELFOSABI_NONE allows them
-			 to be validated later in obj_elf_section.
 			 We can't just always set these bits in gnu_attr for
 			 all OSABIs, since Binutils does not recognize all
 			 SHF_MASKOS bits for non-GNU OSABIs.  It's therefore
@@ -972,10 +970,18 @@ obj_elf_parse_section_letters (char *str
 		  len -= (end - str);
 		  str = end;
 		}
-	      else if (!attr && !*gnu_attr && (*str == '+' || *str == '-'))
+	      else if (!*inherit && !attr
+		       && (gnu_attr == NULL || !*gnu_attr)
+		       && (*str == '+' || *str == '-'))
 		*inherit = *str == '+' ? 1 : -1;
 	      else
-		as_fatal ("%s", bad_msg);
+		{
+		  as_bad (_("unrecognized .section attribute: want %s%s%s,? or number"),
+		    gnu_attr != NULL ? "a,d,e,o,w,x,G,M,R,S,T"
+				     : "a,e,o,w,x,G,M,S,T",
+		    md_extra != NULL ? "," : "", md_extra);
+		  return attr;
+		}
 	  }
 	  break;
 	}
@@ -1260,8 +1266,16 @@ obj_elf_section (int push)
 	      ignore_rest_of_line ();
 	      return;
 	    }
+
+	  const struct elf_backend_data *bed = get_elf_backend_data (stdoutput);
 	  attr = obj_elf_parse_section_letters (beg, strlen (beg), &is_clone,
-						&inherit, &gnu_attr);
+						&inherit,
+						bed->elf_osabi == ELFOSABI_NONE
+						|| (bed->elf_osabi
+						    == ELFOSABI_GNU)
+						|| (bed->elf_osabi
+						    == ELFOSABI_FREEBSD)
+						? &gnu_attr : NULL);
 
 	  if (inherit > 0)
 	    attr |= elf_section_flags (now_seg);
@@ -1571,28 +1585,17 @@ obj_elf_section (int push)
 
   if ((gnu_attr & (SHF_GNU_MBIND | SHF_GNU_RETAIN)) != 0)
     {
-      const struct elf_backend_data *bed;
       bool mbind_p = (gnu_attr & SHF_GNU_MBIND) != 0;
 
       if (mbind_p && (attr & SHF_ALLOC) == 0)
 	as_bad (_("SHF_ALLOC isn't set for GNU_MBIND section: %s"), name);
 
-      bed = get_elf_backend_data (stdoutput);
+      if (mbind_p)
+	elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_mbind;
+      if ((gnu_attr & SHF_GNU_RETAIN) != 0)
+	elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_retain;
 
-      if (bed->elf_osabi != ELFOSABI_GNU
-	  && bed->elf_osabi != ELFOSABI_FREEBSD
-	  && bed->elf_osabi != ELFOSABI_NONE)
-	as_bad (_("%s section is supported only by GNU and FreeBSD targets"),
-		mbind_p ? "GNU_MBIND" : "GNU_RETAIN");
-      else
-	{
-	  if (mbind_p)
-	    elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_mbind;
-	  if ((gnu_attr & SHF_GNU_RETAIN) != 0)
-	    elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_retain;
-
-	  attr |= gnu_attr;
-	}
+      attr |= gnu_attr;
     }
 
   change_section (name, type, attr, entsize, &match, linkonce, push,
--- a/gas/config/tc-alpha.c
+++ b/gas/config/tc-alpha.c
@@ -5306,12 +5306,12 @@ select_gp_value (void)
 /* Map 's' to SHF_ALPHA_GPREL.  */
 
 bfd_vma
-alpha_elf_section_letter (int letter, const char **ptr_msg)
+alpha_elf_section_letter (int letter, const char **extra)
 {
   if (letter == 's')
     return SHF_ALPHA_GPREL;
 
-  *ptr_msg = _("bad .section directive: want a,s,w,x,M,S,G,T in string");
+  *extra = "s";
   return -1;
 }
 
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -18669,17 +18669,15 @@ i386_solaris_fix_up_eh_frame (segT sec)
 /* For ELF on x86-64, add support for SHF_X86_64_LARGE.  */
 
 bfd_vma
-x86_64_section_letter (int letter, const char **ptr_msg)
+x86_64_section_letter (int letter, const char **extra)
 {
   if (flag_code == CODE_64BIT)
     {
       if (letter == 'l')
 	return SHF_X86_64_LARGE;
 
-      *ptr_msg = _("bad .section directive: want a,l,w,x,M,S,G,T in string");
+      *extra = "l";
     }
-  else
-    *ptr_msg = _("bad .section directive: want a,w,x,M,S,G,T in string");
   return -1;
 }
 
--- a/gas/config/tc-ia64.c
+++ b/gas/config/tc-ia64.c
@@ -853,20 +853,20 @@ set_section (char *name)
 /* Map 's' to SHF_IA_64_SHORT.  */
 
 bfd_vma
-ia64_elf_section_letter (int letter, const char **ptr_msg)
+ia64_elf_section_letter (int letter, const char **extra)
 {
   if (letter == 's')
     return SHF_IA_64_SHORT;
-  else if (letter == 'o')
-    return SHF_LINK_ORDER;
 #ifdef TE_VMS
   else if (letter == 'O')
     return SHF_IA_64_VMS_OVERLAID;
   else if (letter == 'g')
     return SHF_IA_64_VMS_GLOBAL;
+  *extra = "g,s,O";
+#else
+  *extra = "s";
 #endif
 
-  *ptr_msg = _("bad .section directive: want a,o,s,w,x,M,S,G,T in string");
   return -1;
 }
 
--- a/gas/config/tc-mep.c
+++ b/gas/config/tc-mep.c
@@ -2081,12 +2081,12 @@ mep_fix_adjustable (fixS *fixP)
 }
 
 bfd_vma
-mep_elf_section_letter (int letter, const char **ptrmsg)
+mep_elf_section_letter (int letter, const char **extra)
 {
   if (letter == 'v')
     return SHF_MEP_VLIW;
 
-  *ptrmsg = _("bad .section directive: want a,v,w,x,M,S in string");
+  *extra = "v";
   return -1;
 }
 
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -4171,12 +4171,12 @@ ppc_section_flags (flagword flags, bfd_v
 }
 
 bfd_vma
-ppc_elf_section_letter (int letter, const char **ptrmsg)
+ppc_elf_section_letter (int letter, const char **extra)
 {
   if (letter == 'v')
     return SHF_PPC_VLE;
 
-  *ptrmsg = _("bad .section directive: want a,e,v,w,x,M,S,G,T in string");
+  *extra = "v";
   return -1;
 }
 #endif /* OBJ_ELF */
--- a/gas/testsuite/gas/elf/bad-section-flag.err
+++ b/gas/testsuite/gas/elf/bad-section-flag.err
@@ -1,2 +1,2 @@
 .*: Assembler messages:
-.*:1: Fatal error: .*
+.*:1: Error: unrecognized [.]section attribute: .*



More information about the Binutils mailing list