[1/2] gas/ELF: allow "inheriting" section attributes and type

Message ID 61c83a56-fe09-1c86-32d0-25535dd7e96f@suse.com
State Accepted
Headers
Series gas/ELF: allow "inheriting" section attributes and type |

Checks

Context Check Description
snail/binutils-gdb-check success Github commit url

Commit Message

Jan Beulich Aug. 14, 2023, 1:48 p.m. UTC
  While --sectname-subst is nice, it isn't enough to e.g. mimic
-f{function,data}-sections in assembly code, when such use is to be
optional (e.g. dependent upon some configuration setting).

Assign meaning to '+' and '-' as section attribute letters, allowing
to inherit the prior section's attributes (and possibly type) along
with adding or removing some. Note that documenting the interaction
with '?' as undefined is a precautionary measure.

While touching the function invocation, stop using |= on the result of
obj_elf_parse_section_letters(): "attr" is firmly zero ahead of the
call.
---
The change ends up much simpler than I expected, and hence I fear it's
overly simplistic (i.e. I'm overlooking something that would break). In
any event the optional settings beyond the group are becoming hard to
handle: For SHF_GNU_MBIND it is not an error when no corresponding
number follows. So it may be necessary to simply document restrictions,
or to refuse to accept anything past the group. Of course it is also an
option to allow nothing past (e.g.) type when inheriting is used.

I didn't extend obj_elf_parse_section_letters()'es bad_msg: It's missing
a number of other characters already. And if doing so, a couple of
config/tc-*.c would also need adjustment. Perhaps this could do with an
overhaul anyway, having the target hook pass back merely the extra
letters it understands, with common code then synthesizing a message.

Initially I considered tying the functionality to --sectname-subst's,
which made me look at users of obj_elf_section_name(). How come
obj_elf_attach_to_group() and group name handling in obj_elf_section()
use that function? The names there are symbol names, not section ones,
aiui (in fact when using section names, the names are lost, as section
symbols are emitted without names), and at least in the former case it
also looks bogus to allow name substitution there (because of then
deriving the name from that of the section itself, rather than some
other one).
  

Patch

--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -6818,6 +6818,12 @@  section is a member of a section group
 section is used for thread-local-storage
 @item ?
 section is a member of the previously-current section's group, if any
+@item +
+section inherits attributes and (unless explicitly specified) type from the
+previously-current section, adding other attributes as specified
+@item -
+section inherits attributes and (unless explicitly specified) type from the
+previously-current section, removing other attributes as specified
 @item R
 retained section (apply SHF_GNU_RETAIN to prevent linker garbage
 collection, GNU ELF extension)
@@ -6839,6 +6845,12 @@  section may have the executable (@code{x
 @code{.attach_to_group} directive can be used to add a section to a group even
 if the section was not originally declared to be part of that group.
 
+Note further that @code{+} and @code{-} need to come first and can only take
+the effect described here unless overridden by a target.  The attributes
+inherited are those in effect at the time the directive is processed.
+Attributes added later (see above) will not be inherited.  Using either
+together with @code{?} is undefined at this point.
+
 The optional @var{type} argument may contain one of the following constants:
 
 @table @code
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -822,10 +822,12 @@  obj_elf_change_section (const char *name
 
 static bfd_vma
 obj_elf_parse_section_letters (char *str, size_t len,
-			       bool *is_clone, bfd_vma *gnu_attr)
+			       bool *is_clone, int *inherit, bfd_vma *gnu_attr)
 {
   bfd_vma attr = 0;
+
   *is_clone = false;
+  *inherit = 0;
 
   while (len > 0)
     {
@@ -923,6 +925,8 @@  obj_elf_parse_section_letters (char *str
 		  len -= (end - str);
 		  str = end;
 		}
+	      else if (!attr && !*gnu_attr && (*str == '+' || *str == '-'))
+		*inherit = *str == '+' ? 1 : -1;
 	      else
 		as_fatal ("%s", bad_msg);
 	  }
@@ -1171,6 +1175,7 @@  obj_elf_section (int push)
       if (*input_line_pointer == '"')
 	{
 	  bool is_clone;
+	  int inherit;
 
 	  beg = demand_copy_C_string (&dummy);
 	  if (beg == NULL)
@@ -1178,8 +1183,15 @@  obj_elf_section (int push)
 	      ignore_rest_of_line ();
 	      return;
 	    }
-	  attr |= obj_elf_parse_section_letters (beg, strlen (beg),
-						 &is_clone, &gnu_attr);
+	  attr = obj_elf_parse_section_letters (beg, strlen (beg), &is_clone,
+						&inherit, &gnu_attr);
+
+	  if (inherit > 0)
+	    attr |= elf_section_flags (now_seg);
+	  else if (inherit < 0)
+	    attr = elf_section_flags (now_seg) & ~attr;
+	  if (inherit)
+	    type = elf_section_type (now_seg);
 
 	  SKIP_WHITESPACE ();
 	  if (*input_line_pointer == ',')
@@ -1224,6 +1236,9 @@  obj_elf_section (int push)
 	    {
 	      ++input_line_pointer;
 	      SKIP_WHITESPACE ();
+	      if (inherit && *input_line_pointer == ','
+		  && (bfd_section_flags (now_seg) & SEC_MERGE) != 0)
+		goto fetch_entsize;
 	      entsize = get_absolute_expression ();
 	      SKIP_WHITESPACE ();
 	      if (entsize < 0)
@@ -1233,6 +1248,12 @@  obj_elf_section (int push)
 		  entsize = 0;
 		}
 	    }
+	  else if ((attr & SHF_MERGE) != 0 && inherit
+		    && (bfd_section_flags (now_seg) & SEC_MERGE) != 0)
+	    {
+	    fetch_entsize:
+	      entsize = now_seg->entsize;
+	    }
 	  else if ((attr & SHF_MERGE) != 0)
 	    {
 	      as_warn (_("entity size for SHF_MERGE not specified"));
@@ -1248,6 +1269,9 @@  obj_elf_section (int push)
 		{
 		  linked_to_section_index = strtoul (input_line_pointer, & input_line_pointer, 0);
 		}
+	      else if (inherit && *input_line_pointer == ','
+		       && (elf_section_flags (now_seg) & SHF_LINK_ORDER) != 0)
+		goto fetch_linked_to;
 	      else
 		{
 		  char c;
@@ -1260,6 +1284,17 @@  obj_elf_section (int push)
 		    match.linked_to_symbol_name = xmemdup0 (beg, length);
 		}
 	    }
+	  else if ((attr & SHF_LINK_ORDER) != 0 && inherit
+		   && (elf_section_flags (now_seg) & SHF_LINK_ORDER) != 0)
+	    {
+	    fetch_linked_to:
+	      if (now_seg->map_head.linked_to_symbol_name)
+		match.linked_to_symbol_name =
+		  now_seg->map_head.linked_to_symbol_name;
+	      else
+		linked_to_section_index =
+		  elf_section_data (now_seg)->this_hdr.sh_link;
+	    }
 
 	  if ((attr & SHF_GROUP) != 0 && is_clone)
 	    {
@@ -1270,6 +1305,10 @@  obj_elf_section (int push)
 	  if ((attr & SHF_GROUP) != 0 && *input_line_pointer == ',')
 	    {
 	      ++input_line_pointer;
+	      SKIP_WHITESPACE ();
+	      if (inherit && *input_line_pointer == ','
+		  && (elf_section_flags (now_seg) & SHF_GROUP) != 0)
+		goto fetch_group;
 	      match.group_name = obj_elf_section_name ();
 	      if (match.group_name == NULL)
 		attr &= ~SHF_GROUP;
@@ -1286,6 +1325,14 @@  obj_elf_section (int push)
 	      else if (startswith (name, ".gnu.linkonce"))
 		linkonce = 1;
 	    }
+	  else if ((attr & SHF_GROUP) != 0 && inherit
+		   && (elf_section_flags (now_seg) & SHF_GROUP) != 0)
+	    {
+	    fetch_group:
+	      match.group_name = elf_group_name (now_seg);
+	      linkonce =
+	        (bfd_section_flags (now_seg) & SEC_LINK_ONCE) != 0;
+	    }
 	  else if ((attr & SHF_GROUP) != 0)
 	    {
 	      as_warn (_("group name for SHF_GROUP not specified"));
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -279,6 +279,11 @@  if { [is_elf_format] } then {
     run_dump_test "section27"
     run_dump_test "section28"
     run_dump_test "section29"
+    if { ![istarget "rx-*-*"] } then {
+	run_dump_test "section30"
+    } else {
+	run_dump_test "section30" {{as -muse-conventional-section-names}}
+    }
     run_dump_test "sh-link-zero"
     run_dump_test "size"
     run_dump_test "dwarf2-1" $dump_opts
--- /dev/null
+++ b/gas/testsuite/gas/elf/section30.d
@@ -0,0 +1,28 @@ 
+#as: --sectname-subst
+#readelf: -SW
+#name: --sectname-subst plus section attr/type inherting
+# Targets setting NO_PSEUDO_DOT don't allow macros of certain names.
+#notarget: m681*-*-* m68hc1*-*-* s12z-*-* spu-*-* xgate-*-* z80-*-*
+
+#...
+  \[..\] \.group +GROUP +[0-9a-f]+ [0-9a-f]+ 0+c 04 +[1-9][0-9]* +[1-9][0-9]* +4
+  \[..\] \.text +PROGBITS +[0-9a-f]+ [0-9a-f]+ 0+0 00  AX  0   0 +[1-9][0-9]*
+  \[..\] \.data +PROGBITS +[0-9a-f]+ [0-9a-f]+ 0+0 00  WA  0   0 +[1-9][0-9]*
+  \[..\] \.bss +NOBITS +[0-9a-f]+ [0-9a-f]+ 0+0 00  WA  0   0 +[1-9][0-9]*
+#...
+  \[..\] \.text\.func1 +PROGBITS +[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  AX  0   0 +[1-9][0-9]*
+  \[..\] \.text\.func2 +PROGBITS +[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  AX  0   0 +[1-9][0-9]*
+  \[..\] \.data\.data1 +PROGBITS +[0-9a-f]+ [0-9a-f]+ 0+1 00  WA  0   0  1
+#...
+  \[..\] \.bss\.data2 +NOBITS +[0-9a-f]+ [0-9a-f]+ 0+2 00  WA  0   0  1
+  \[..\] \.rodata +PROGBITS +[0-9a-f]+ [0-9a-f]+ 0+0 00   A  0   0  1
+  \[..\] \.rodata\.data3 +PROGBITS +[0-9a-f]+ [0-9a-f]+ 0+3 00   A  0   0  1
+  \[..\] \.rodata\.str1\.1 +PROGBITS +[0-9a-f]+ [0-9a-f]+ 0+0 01 AMS  0   0  1
+  \[..\] \.rodata\.str1\.1\.str1 +PROGBITS +[0-9a-f]+ [0-9a-f]+ 0+8 01 AMS  0   0  1
+  \[..\] \.rodata\.2 +PROGBITS +[0-9a-f]+ [0-9a-f]+ 0+0 00  AL  [1-9]   0  1
+  \[..\] \.rodata\.2\.data4 +PROGBITS +[0-9a-f]+ [0-9a-f]+ 0+4 00  AL  [1-9]   0  1
+  \[..\] \.bss\.data5 +NOBITS +[0-9a-f]+ [0-9a-f]+ 0+5 00  WA  0   0  1
+  \[..\] \.rodata\.3 +PROGBITS +[0-9a-f]+ [0-9a-f]+ 0+0 00  AG  0   0  1
+  \[..\] \.rodata\.3\.data6 +PROGBITS +[0-9a-f]+ [0-9a-f]+ 0+6 00  AG  0   0  1
+  \[..\] \.bss\.data7 +NOBITS +[0-9a-f]+ [0-9a-f]+ 0+7 00  WA  0   0  1
+#pass
--- /dev/null
+++ b/gas/testsuite/gas/elf/section30.s
@@ -0,0 +1,67 @@ 
+	.macro func name:req
+	.pushsection %S.\name, "+"
+	.type \name, %function
+	.global \name
+	.hidden \name
+\name:
+	.endm
+
+	.macro data name:req
+	.pushsection %S.\name, "+"
+	.type \name, %object
+\name:
+	.endm
+
+	.macro end name:req
+	.size \name, . - \name
+	.popsection
+	.endm
+
+
+	.text
+	func func1
+	.nop
+	end func1
+
+	func func2
+	.nop
+	.nop
+	end func2
+
+	.data
+	data data1
+	.byte 1
+	end data1
+
+	.section .bss
+	data data2
+	.skip 2
+	end data2
+
+	.section .rodata, "a", %progbits
+	data data3
+	.byte 3, 3, 3
+	end data3
+
+	.section .rodata.str1.1, "aMS", %progbits, 1
+	data str1
+	.asciz "string1"
+	end str1
+
+	.section .rodata.2, "ao", %progbits, func1
+	data data4
+	.byte 4, 4, 4, 4
+	end data4
+	.pushsection .bss.data5, "-o", %nobits
+	.type data5, %object
+data5:	.fill 5
+	end data5
+
+	.section .rodata.3, "aG", %progbits, sig1, comdat
+	data data6
+	.byte 6, 6, 6, 6, 6, 6
+	end data6
+	.pushsection .bss.data7, "-G", %nobits
+	.type data7, %object
+data7:	.skip 7
+	end data7