[PATCH] ELF: Support the section flag 'o' in .section directive

Fangrui Song i@maskray.me
Mon Feb 3 06:26:00 GMT 2020


On 2020-02-02, H.J. Lu wrote:
>As shown in
>
>https://sourceware.org/bugzilla/show_bug.cgi?id=25490
>
>--gc-sections will silently remove __patchable_function_entries section
>and generate corrupt result.  This patch adds the section flag 'o' to
>.section directive:
>
>.section __patchable_function_entries,"awo",@progbits,foo
>.section __patchable_function_entries,"awoG",@progbits,foo,foo,comdat
>.section __patchable_function_entries,"awo",@progbits,bar,unique,4
>.section __patchable_function_entries,"awoG",@progbits,foo,foo,comdat,unique,1
>
>which specifies the symbol name which the section references.  Assmebler
>will set its elf_linked_to_section to a local section where the symbol
>is defined.
>
>Linker is updated to set gc_mark if gc_mark of its linked-to section is
>set after all sections, including backend specific ones, have been
>garbage collected.  To make it to work, _bfd_elf_gc_mark_extra_sections
>must be called after elf_backend_gc_mark_extra_sections.
>
>bfd/
>
>	PR gas/25381
>	* bfd-in2.h: Regenerated.
>	* elf32-arm.c (elf32_arm_gc_mark_extra_sections): Call
>	_bfd_elf_gc_mark_extra_sections last.
>	* elf32-csky.c (_bfd_elf_gc_mark_extra_sections): Likewise.
>	* elf32-tic6x.c (elf32_tic6x_gc_mark_extra_sections): Likewise.
>	* elfxx-mips.c (_bfd_mips_elf_gc_mark_extra_sections): Likewise.
>	* elflink.c (_bfd_elf_gc_mark_extra_sections): Set gc_mark if
>	gc_mark of its linked-to section is set.
>	* section.c (asection): Add linked_to_symbol_name to map_head
>	union.
>
>gas/
>
>	PR gas/25381
>	* config/obj-elf.c (get_section): Also check
>	linked_to_symbol_name.
>	(obj_elf_change_section): Also set map_head.linked_to_symbol_name.
>	(obj_elf_parse_section_letters): Handle the 'o' flag.
>	(build_group_lists): Renamed to ...
>	(build_additional_section_info): This.  Set elf_linked_to_section
>	from map_head.linked_to_symbol_name.
>	(elf_adjust_symtab): Updated.
>	* config/obj-elf.h (elf_section_match): Add linked_to_symbol_name.
>	* doc/as.texi: Document the 'o' flag.
>	* testsuite/gas/elf/elf.exp: Run PR gas/25381 tests.
>	* testsuite/gas/elf/section18.d: New file.
>	* testsuite/gas/elf/section18.s: Likewise.
>	* testsuite/gas/elf/section19.d: Likewise.
>	* testsuite/gas/elf/section19.s: Likewise.
>	* testsuite/gas/elf/section20.d: Likewise.
>	* testsuite/gas/elf/section20.s: Likewise.
>	* testsuite/gas/elf/section21.d: Likewise.
>	* testsuite/gas/elf/section21.l: Likewise.
>	* testsuite/gas/elf/section21.s: Likewise.
>
>ld/
>
>	PR gas/25381
>	* testsuite/ld-elf/elf.exp: Run PR gas/25381 tests.
>	* testsuite/ld-elf/pr25490-2-32.rd: New file.
>	* testsuite/ld-elf/pr25490-2-64.rd: Likewise.
>	* testsuite/ld-elf/pr25490-2.s: Likewise.
>	* testsuite/ld-elf/pr25490-3-32.rd: Likewise.
>	* testsuite/ld-elf/pr25490-3-64.rd: Likewise.
>	* testsuite/ld-elf/pr25490-3.s: Likewise.
>	* testsuite/ld-elf/pr25490-4-32.rd: Likewise.
>	* testsuite/ld-elf/pr25490-4-64.rd: Likewise.
>	* testsuite/ld-elf/pr25490-4.s: Likewise.
>	* testsuite/ld-elf/pr25490-5-32.rd: Likewise.
>	* testsuite/ld-elf/pr25490-5-64.rd: Likewise.
>	* testsuite/ld-elf/pr25490-5.s: Likewise.
>	* testsuite/ld-elf/pr25490-6-32.rd: Likewise.
>	* testsuite/ld-elf/pr25490-6-64.rd: Likewise.
>	* testsuite/ld-elf/pr25490-6.s: Likewise.
>---
> bfd/bfd-in2.h                       |  4 ++-
> bfd/elf32-arm.c                     |  4 +--
> bfd/elf32-csky.c                    |  4 +--
> bfd/elf32-tic6x.c                   |  4 +--
> bfd/elflink.c                       | 13 +++++++-
> bfd/elfxx-mips.c                    |  4 +--
> bfd/section.c                       |  4 ++-
> gas/config/obj-elf.c                | 52 ++++++++++++++++++++++++++---
> gas/config/obj-elf.h                |  1 +
> gas/doc/as.texi                     | 27 +++++++++++++++
> gas/testsuite/gas/elf/elf.exp       |  4 +++
> gas/testsuite/gas/elf/section18.d   |  8 +++++
> gas/testsuite/gas/elf/section18.s   | 13 ++++++++
> gas/testsuite/gas/elf/section19.d   |  8 +++++
> gas/testsuite/gas/elf/section19.s   | 13 ++++++++
> gas/testsuite/gas/elf/section20.d   | 17 ++++++++++
> gas/testsuite/gas/elf/section20.s   | 13 ++++++++
> gas/testsuite/gas/elf/section21.d   |  2 ++
> gas/testsuite/gas/elf/section21.l   |  4 +++
> gas/testsuite/gas/elf/section21.s   | 15 +++++++++
> ld/testsuite/ld-elf/elf.exp         | 50 +++++++++++++++++++++++++++
> ld/testsuite/ld-elf/pr25490-2-32.rd |  7 ++++
> ld/testsuite/ld-elf/pr25490-2-64.rd |  7 ++++
> ld/testsuite/ld-elf/pr25490-2.s     |  9 +++++
> ld/testsuite/ld-elf/pr25490-3-32.rd |  7 ++++
> ld/testsuite/ld-elf/pr25490-3-64.rd |  7 ++++
> ld/testsuite/ld-elf/pr25490-3.s     | 18 ++++++++++
> ld/testsuite/ld-elf/pr25490-4-32.rd |  7 ++++
> ld/testsuite/ld-elf/pr25490-4-64.rd |  7 ++++
> ld/testsuite/ld-elf/pr25490-4.s     | 18 ++++++++++
> ld/testsuite/ld-elf/pr25490-5-32.rd |  7 ++++
> ld/testsuite/ld-elf/pr25490-5-64.rd |  7 ++++
> ld/testsuite/ld-elf/pr25490-5.s     | 17 ++++++++++
> ld/testsuite/ld-elf/pr25490-6-32.rd |  7 ++++
> ld/testsuite/ld-elf/pr25490-6-64.rd |  7 ++++
> ld/testsuite/ld-elf/pr25490-6.s     | 28 ++++++++++++++++
> 36 files changed, 408 insertions(+), 16 deletions(-)
> create mode 100644 gas/testsuite/gas/elf/section18.d
> create mode 100644 gas/testsuite/gas/elf/section18.s
> create mode 100644 gas/testsuite/gas/elf/section19.d
> create mode 100644 gas/testsuite/gas/elf/section19.s
> create mode 100644 gas/testsuite/gas/elf/section20.d
> create mode 100644 gas/testsuite/gas/elf/section20.s
> create mode 100644 gas/testsuite/gas/elf/section21.d
> create mode 100644 gas/testsuite/gas/elf/section21.l
> create mode 100644 gas/testsuite/gas/elf/section21.s
> create mode 100644 ld/testsuite/ld-elf/pr25490-2-32.rd
> create mode 100644 ld/testsuite/ld-elf/pr25490-2-64.rd
> create mode 100644 ld/testsuite/ld-elf/pr25490-2.s
> create mode 100644 ld/testsuite/ld-elf/pr25490-3-32.rd
> create mode 100644 ld/testsuite/ld-elf/pr25490-3-64.rd
> create mode 100644 ld/testsuite/ld-elf/pr25490-3.s
> create mode 100644 ld/testsuite/ld-elf/pr25490-4-32.rd
> create mode 100644 ld/testsuite/ld-elf/pr25490-4-64.rd
> create mode 100644 ld/testsuite/ld-elf/pr25490-4.s
> create mode 100644 ld/testsuite/ld-elf/pr25490-5-32.rd
> create mode 100644 ld/testsuite/ld-elf/pr25490-5-64.rd
> create mode 100644 ld/testsuite/ld-elf/pr25490-5.s
> create mode 100644 ld/testsuite/ld-elf/pr25490-6-32.rd
> create mode 100644 ld/testsuite/ld-elf/pr25490-6-64.rd
> create mode 100644 ld/testsuite/ld-elf/pr25490-6.s
>
>diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
>index 09a5a39ff5e..2d26b81db38 100644
>--- a/bfd/bfd-in2.h
>+++ b/bfd/bfd-in2.h
>@@ -1185,10 +1185,12 @@ typedef struct bfd_section
>   /* Early in the link process, map_head and map_tail are used to build
>      a list of input sections attached to an output section.  Later,
>      output sections use these fields for a list of bfd_link_order
>-     structs.  */
>+     structs.  The linked_to_symbol_name field is for ELF assembler
>+     internal use.  */
>   union {
>     struct bfd_link_order *link_order;
>     struct bfd_section *s;
>+    const char *linked_to_symbol_name;
>   } map_head, map_tail;
> } asection;
>
>diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
>index faf8376f200..a6df8f331ce 100644
>--- a/bfd/elf32-arm.c
>+++ b/bfd/elf32-arm.c
>@@ -15939,8 +15939,6 @@ elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
>   bfd_boolean debug_sec_need_to_be_marked = FALSE;
>   asection *isec;
>
>-  _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
>-
>   out_attr = elf_known_obj_attributes_proc (info->output_bfd);
>   is_v8m = out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
> 	   && out_attr[Tag_CPU_arch_profile].i == 'M';
>@@ -16024,6 +16022,8 @@ elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
>       first_bfd_browse = FALSE;
>     }
>
>+  _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
>+
>   return TRUE;
> }
>
>diff --git a/bfd/elf32-csky.c b/bfd/elf32-csky.c
>index 04214f28ea5..3c5fcc82f5a 100644
>--- a/bfd/elf32-csky.c
>+++ b/bfd/elf32-csky.c
>@@ -3032,8 +3032,6 @@ elf32_csky_gc_mark_extra_sections (struct bfd_link_info *info,
> {
>   bfd *sub;
>
>-  _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
>-
>   for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
>     {
>       asection *o;
>@@ -3043,6 +3041,8 @@ elf32_csky_gc_mark_extra_sections (struct bfd_link_info *info,
> 	  o->gc_mark = 1;
>     }
>
>+  _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
>+
>   return TRUE;
> }
>
>diff --git a/bfd/elf32-tic6x.c b/bfd/elf32-tic6x.c
>index 39ca6992007..6308eded0b4 100644
>--- a/bfd/elf32-tic6x.c
>+++ b/bfd/elf32-tic6x.c
>@@ -1935,8 +1935,6 @@ elf32_tic6x_gc_mark_extra_sections (struct bfd_link_info *info,
>   Elf_Internal_Shdr **elf_shdrp;
>   bfd_boolean again;
>
>-  _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
>-
>   /* Marking EH data may cause additional code sections to be marked,
>      requiring multiple passes.  */
>   again = TRUE;
>@@ -1970,6 +1968,8 @@ elf32_tic6x_gc_mark_extra_sections (struct bfd_link_info *info,
> 	}
>     }
>
>+  _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
>+
>   return TRUE;
> }
>
>diff --git a/bfd/elflink.c b/bfd/elflink.c
>index e4d92952aaf..8ad13b8b55f 100644
>--- a/bfd/elflink.c
>+++ b/bfd/elflink.c
>@@ -13312,7 +13312,9 @@ _bfd_elf_gc_mark_debug_special_section_group (asection *grp)
>     }
> }
>
>-/* Keep debug and special sections.  */
>+/* Keep debug and special sections.  NB: This function must be called
>+   after elf_backend_gc_mark_extra_sections so that linked-to section
>+   can be checkd properly.  */
>
> bfd_boolean
> _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
>@@ -13345,6 +13347,15 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
> 		   && (isec->flags & SEC_ALLOC) != 0
> 		   && elf_section_type (isec) != SHT_NOTE)
> 	    some_kept = TRUE;
>+	  else
>+	    {
>+	      /* Since all sections, including backend specific ones,
>+		 have been garbage collected, mark this section if its
>+		 linked-to section is marked.  */
>+	      asection *linked_to_sec = elf_linked_to_section (isec);
>+	      if (linked_to_sec && linked_to_sec->gc_mark)
>+		isec->gc_mark = 1;
>+	    }
>
> 	  if (!debug_frag_seen
> 	      && (isec->flags & SEC_DEBUGGING)
>diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
>index d7e3aed3b67..a2d6ace3236 100644
>--- a/bfd/elfxx-mips.c
>+++ b/bfd/elfxx-mips.c
>@@ -12845,8 +12845,6 @@ _bfd_mips_elf_gc_mark_extra_sections (struct bfd_link_info *info,
> {
>   bfd *sub;
>
>-  _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
>-
>   for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
>     {
>       asection *o;
>@@ -12863,6 +12861,8 @@ _bfd_mips_elf_gc_mark_extra_sections (struct bfd_link_info *info,
> 	  }
>     }
>
>+  _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
>+
>   return TRUE;
> }
> 
>diff --git a/bfd/section.c b/bfd/section.c
>index 0c15a0d646f..7de0a2d7a85 100644
>--- a/bfd/section.c
>+++ b/bfd/section.c
>@@ -544,10 +544,12 @@ CODE_FRAGMENT
> .  {* Early in the link process, map_head and map_tail are used to build
> .     a list of input sections attached to an output section.  Later,
> .     output sections use these fields for a list of bfd_link_order
>-.     structs.  *}
>+.     structs.  The linked_to_symbol_name field is for ELF assembler
>+.     internal use.  *}
> .  union {
> .    struct bfd_link_order *link_order;
> .    struct bfd_section *s;
>+.    const char *linked_to_symbol_name;
> .  } map_head, map_tail;
> .} asection;
> .
>diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
>index 2958490c323..d7a07fec6bf 100644
>--- a/gas/config/obj-elf.c
>+++ b/gas/config/obj-elf.c
>@@ -524,6 +524,8 @@ get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
>   struct elf_section_match *match = (struct elf_section_match *) inf;
>   const char *gname = match->group_name;
>   const char *group_name = elf_group_name (sec);
>+  const char *linked_to_symbol_name
>+    = sec->map_head.linked_to_symbol_name;
>   unsigned int info = elf_section_data (sec)->this_hdr.sh_info;
>
>   return (info == match->info
>@@ -533,7 +535,12 @@ get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
> 	  && (group_name == gname
> 	      || (group_name != NULL
> 		  && gname != NULL
>-		  && strcmp (group_name, gname) == 0)));
>+		  && strcmp (group_name, gname) == 0))
>+	  && (linked_to_symbol_name == match->linked_to_symbol_name
>+	      || (linked_to_symbol_name != NULL
>+		  && match->linked_to_symbol_name != NULL
>+		  && strcmp (linked_to_symbol_name,
>+			     match->linked_to_symbol_name) == 0)));
> }
>
> /* Handle the .section pseudo-op.  This code supports two different
>@@ -740,6 +747,10 @@ obj_elf_change_section (const char *name,
>       sec->section_id = match_p->section_id;
>       flags |= match_p->flags;
>
>+      /* Set the linked-to symbol name.  */
>+      sec->map_head.linked_to_symbol_name
>+	= match_p->linked_to_symbol_name;
>+
>       bfd_set_section_flags (sec, flags);
>       if (flags & SEC_MERGE)
> 	sec->entsize = entsize;
>@@ -801,6 +812,9 @@ obj_elf_parse_section_letters (char *str, size_t len,
> 	case 'e':
> 	  attr |= SHF_EXCLUDE;
> 	  break;
>+	case 'o':
>+	  attr |= SHF_LINK_ORDER;
>+	  break;
> 	case 'w':
> 	  attr |= SHF_WRITE;
> 	  break;
>@@ -841,7 +855,7 @@ obj_elf_parse_section_letters (char *str, size_t len,
> 	default:
> 	  {
> 	    const char *bad_msg = _("unrecognized .section attribute:"
>-				    " want a,e,w,x,M,S,G,T or number");
>+				    " want a,e,o,w,x,M,S,G,T or number");
> #ifdef md_elf_section_letter
> 	    bfd_vma md_attr = md_elf_section_letter (*str, &bad_msg);
> 	    if (md_attr != (bfd_vma) -1)
>@@ -1154,6 +1168,19 @@ obj_elf_section (int push)
> 	      attr &= ~SHF_MERGE;
> 	    }
>
>+	  if ((attr & SHF_LINK_ORDER) != 0 && *input_line_pointer == ',')
>+	    {
>+	      char c;
>+	      unsigned int length;
>+	      ++input_line_pointer;
>+	      SKIP_WHITESPACE ();
>+	      c = get_symbol_name (& beg);
>+	      (void) restore_line_pointer (c);
>+	      length = input_line_pointer - beg;
>+	      if (length)
>+		match.linked_to_symbol_name = xmemdup0 (beg, length);
>+	    }
>+
> 	  if ((attr & SHF_GROUP) != 0 && is_clone)
> 	    {
> 	      as_warn (_("? section flag ignored with G present"));
>@@ -2476,10 +2503,12 @@ static struct group_list groups;
> /* Called via bfd_map_over_sections.  If SEC is a member of a group,
>    add it to a list of sections belonging to the group.  INF is a
>    pointer to a struct group_list, which is where we store the head of
>-   each list.  */
>+   each list.  If its link_to_symbol_name isn't NULL, set up its
>+   linked-to section.  */
>
> static void
>-build_group_lists (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
>+build_additional_section_info (bfd *abfd ATTRIBUTE_UNUSED,
>+				  asection *sec, void *inf)
> {
>   struct group_list *list = (struct group_list *) inf;
>   const char *group_name = elf_group_name (sec);
>@@ -2487,6 +2516,18 @@ build_group_lists (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
>   unsigned int *elem_idx;
>   unsigned int *idx_ptr;
>
>+  if (sec->map_head.linked_to_symbol_name)
>+    {
>+      symbolS *linked_to_sym;
>+      linked_to_sym = symbol_find (sec->map_head.linked_to_symbol_name);
>+      if (!linked_to_sym || !S_IS_DEFINED (linked_to_sym))
>+	as_bad (_("undefined linked-to symbol `%s' on section `%s'"),
>+		sec->map_head.linked_to_symbol_name,
>+		bfd_section_name (sec));
>+      else
>+	elf_linked_to_section (sec) = S_GET_SEGMENT (linked_to_sym);
>+    }
>+
>   if (group_name == NULL)
>     return;
>
>@@ -2533,7 +2574,8 @@ elf_adjust_symtab (void)
>   groups.num_group = 0;
>   groups.head = NULL;
>   groups.indexes = hash_new ();
>-  bfd_map_over_sections (stdoutput, build_group_lists, &groups);
>+  bfd_map_over_sections (stdoutput, build_additional_section_info,
>+			 &groups);
>
>   /* Make the SHT_GROUP sections that describe each section group.  We
>      can't set up the section contents here yet, because elf section
>diff --git a/gas/config/obj-elf.h b/gas/config/obj-elf.h
>index 7cfcc254823..54af9ebc0e2 100644
>--- a/gas/config/obj-elf.h
>+++ b/gas/config/obj-elf.h
>@@ -82,6 +82,7 @@ struct elf_obj_sy
> struct elf_section_match
> {
>   const char *group_name;
>+  const char *linked_to_symbol_name;
>   unsigned int info;
>   unsigned int section_id;
>   flagword flags;
>diff --git a/gas/doc/as.texi b/gas/doc/as.texi
>index 152bbfdd009..1554c51ad2f 100644
>--- a/gas/doc/as.texi
>+++ b/gas/doc/as.texi
>@@ -6599,6 +6599,9 @@ section is allocatable
> section is a GNU_MBIND section
> @item e
> section is excluded from executable and shared library.
>+@item o
>+section references a symbol defined in another section (the linked-to
>+section) in the same file.
> @item w
> section is writable
> @item x
>@@ -6678,6 +6681,23 @@ which is a suffix of a larger string is considered a duplicate.  Thus
> @code{"def"} will be merged with @code{"abcdef"};  A reference to the first
> @code{"def"} will be changed to a reference to @code{"abcdef"+3}.
>
>+If @var{flags} contains the @code{o} flag, then the @var{type} argument
>+must be present along with an additional field like this:
>+
>+@smallexample
>+.section @var{name},"@var{flags}"o,@@@var{type},@var{SymbolName}
>+@end smallexample
>+
>+The @var{SymbolName} field specifies the symbol name which the section
>+references.
>+
>+Note: If both the @var{M} and @var{o} flags are present, then the fields
>+for the Merge flag should come first, like this:
>+
>+@smallexample
>+.section @var{name},"@var{flags}"Mo,@@@var{type},@var{entsize},@var{SymbolName}
>+@end smallexample
>+
> If @var{flags} contains the @code{G} symbol then the @var{type} argument must
> be present along with an additional field like this:
>
>@@ -6702,6 +6722,13 @@ the Merge flag should come first, like this:
> .section @var{name} , "@var{flags}"MG, @@@var{type}, @var{entsize}, @var{GroupName}[, @var{linkage}]
> @end smallexample
>
>+If both @code{o} flag and @code{G} flag are present, then the
>+@var{SymbolName} field for @code{o} comes first, like this:
>+
>+@smallexample
>+.section @var{name},"@var{flags}"oG,@@@var{type},@var{SymbolName},@var{GroupName}[,@var{linkage}]
>+@end smallexample
>+
> If @var{flags} contains the @code{?} symbol then it may not also contain the
> @code{G} symbol and the @var{GroupName} or @var{linkage} fields should not be
> present.  Instead, @code{?} says to consider the section that's current before
>diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
>index 08c6830e0db..0f9b2672c4c 100644
>--- a/gas/testsuite/gas/elf/elf.exp
>+++ b/gas/testsuite/gas/elf/elf.exp
>@@ -249,6 +249,10 @@ if { [is_elf_format] } then {
>     run_dump_test "section16a"
>     run_dump_test "section16b"
>     run_dump_test "section17"
>+    run_dump_test "section18"
>+    run_dump_test "section19"
>+    run_dump_test "section20"
>+    run_dump_test "section21"
>     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/section18.d b/gas/testsuite/gas/elf/section18.d
>new file mode 100644
>index 00000000000..a00b4a65f95
>--- /dev/null
>+++ b/gas/testsuite/gas/elf/section18.d
>@@ -0,0 +1,8 @@
>+#readelf: -SW
>+#name: linked-to section 1
>+
>+#...
>+ +\[ *[0-9]+\] +__patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[48] +00 +WAL +.*
>+#...
>+ +\[ *[0-9]+\] +__patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[48] +00 +WAL +.*
>+#pass
>diff --git a/gas/testsuite/gas/elf/section18.s b/gas/testsuite/gas/elf/section18.s
>new file mode 100644
>index 00000000000..d51eb681318
>--- /dev/null
>+++ b/gas/testsuite/gas/elf/section18.s
>@@ -0,0 +1,13 @@
>+	.text
>+foo:
>+	.section __patchable_function_entries,"awo",%progbits,foo
>+	.dc.a	.LPFE1
>+	.text
>+.LPFE1:
>+	.byte 0
>+	.section __patchable_function_entries,"awo",%progbits,bar
>+	.dc.a	.LPFE2
>+	.text
>+bar:
>+.LPFE2:
>+	.byte 0
>diff --git a/gas/testsuite/gas/elf/section19.d b/gas/testsuite/gas/elf/section19.d
>new file mode 100644
>index 00000000000..4e500ad3bd2
>--- /dev/null
>+++ b/gas/testsuite/gas/elf/section19.d
>@@ -0,0 +1,8 @@
>+#readelf: -SW
>+#name: linked-to section 2
>+
>+#...
>+ +\[ *[0-9]+\] +__patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[48] +00 +WAL +.*
>+#...
>+ +\[ *[0-9]+\] +__patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[48] +00 +WAL +.*
>+#pass
>diff --git a/gas/testsuite/gas/elf/section19.s b/gas/testsuite/gas/elf/section19.s
>new file mode 100644
>index 00000000000..7d30ea1ff9c
>--- /dev/null
>+++ b/gas/testsuite/gas/elf/section19.s
>@@ -0,0 +1,13 @@
>+	.section .text,"ax",%progbits,unique,20
>+foo:
>+	.section __patchable_function_entries,"awo",%progbits,foo,unique,2
>+	.dc.a	.LPFE1
>+	.section .text,"ax",%progbits,unique,20
>+.LPFE1:
>+	.byte 0
>+	.section __patchable_function_entries,"awo",%progbits,bar,unique,102
>+	.dc.a	.LPFE2
>+	.section .text,"ax",%progbits,unique,2
>+bar:
>+.LPFE2:
>+	.byte 0
>diff --git a/gas/testsuite/gas/elf/section20.d b/gas/testsuite/gas/elf/section20.d
>new file mode 100644
>index 00000000000..3e0b023f7ac
>--- /dev/null
>+++ b/gas/testsuite/gas/elf/section20.d
>@@ -0,0 +1,17 @@
>+#readelf: -SWg
>+#name: linked-to section 3
>+
>+#...
>+ +\[ *[0-9]+\] +__patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[48] +00 +WALG +.*
>+#...
>+ +\[ *[0-9]+\] +__patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+[48] +00 +WALG +.*
>+#...
>+COMDAT group section \[[ 0-9]+\] `.group' \[foo\] contains [0-9]+ sections:
>+   \[Index\]    Name
>+#...
>+   \[[ 0-9]+\]   __patchable_function_entries
>+#...
>+COMDAT group section \[[ 0-9]+\] `.group' \[bar\] contains [0-9]+ sections:
>+#...
>+   \[[ 0-9]+\]   __patchable_function_entries
>+#pass
>diff --git a/gas/testsuite/gas/elf/section20.s b/gas/testsuite/gas/elf/section20.s
>new file mode 100644
>index 00000000000..1e9639ef4a7
>--- /dev/null
>+++ b/gas/testsuite/gas/elf/section20.s
>@@ -0,0 +1,13 @@
>+	.section .text,"axG",%progbits,foo,comdat
>+foo:
>+	.section __patchable_function_entries,"awoG",%progbits,foo,foo,comdat
>+	.dc.a	.LPFE1
>+	.section .text,"axG",%progbits,foo,comdat
>+.LPFE1:
>+	.byte 0
>+	.section __patchable_function_entries,"awoG",%progbits,bar,bar,comdat,unique,4
>+	.dc.a	.LPFE2
>+	.section .text,"axG",%progbits,bar,comdat,unique,24
>+bar:
>+.LPFE2:
>+	.byte 0
>diff --git a/gas/testsuite/gas/elf/section21.d b/gas/testsuite/gas/elf/section21.d
>new file mode 100644
>index 00000000000..54fa9d419bc
>--- /dev/null
>+++ b/gas/testsuite/gas/elf/section21.d
>@@ -0,0 +1,2 @@
>+#name: incorrect linked-to symbols
>+#error_output: section21.l
>diff --git a/gas/testsuite/gas/elf/section21.l b/gas/testsuite/gas/elf/section21.l
>new file mode 100644
>index 00000000000..8b9af6118a9
>--- /dev/null
>+++ b/gas/testsuite/gas/elf/section21.l
>@@ -0,0 +1,4 @@
>+[^:]*: Assembler messages:
>+[^:]*:11: Error: junk@end of line, first unrecognized character is `1'
>+[^:]*: Error: undefined linked-to symbol `bar' on section `__patchable_function_entries'
>+[^:]*: Error: undefined linked-to symbol `foo' on section `__patchable_function_entries'
>diff --git a/gas/testsuite/gas/elf/section21.s b/gas/testsuite/gas/elf/section21.s
>new file mode 100644
>index 00000000000..ae5f848b299
>--- /dev/null
>+++ b/gas/testsuite/gas/elf/section21.s
>@@ -0,0 +1,15 @@
>+	.section __patchable_function_entries,"awo",%progbits,bar
>+	.dc.a	.LPFE1
>+	.text
>+.LPFE1:
>+	.byte 0
>+	.section __patchable_function_entries,"awo",%progbits,foo
>+	.dc.a	.LPFE2
>+	.text
>+.LPFE2:
>+	.dc.a foo
>+	.section __patchable_function_entries,"awo",%progbits,1foo
>+	.dc.a	.LPFE3
>+	.text
>+.LPFE3:
>+	.byte 0
>diff --git a/ld/testsuite/ld-elf/elf.exp b/ld/testsuite/ld-elf/elf.exp
>index 989fb50d4ae..ea8cd884056 100644
>--- a/ld/testsuite/ld-elf/elf.exp
>+++ b/ld/testsuite/ld-elf/elf.exp
>@@ -76,9 +76,19 @@ run_ld_link_tests [list \
> if [is_elf64 tmpdir/symbol3w.a] {
>     set ASFLAGS "$ASFLAGS --defsym ALIGN=3"
>     set pr23900_1_exp "pr23900-1-64.rd"
>+    set pr25490_2_exp "pr25490-2-64.rd"
>+    set pr25490_3_exp "pr25490-3-64.rd"
>+    set pr25490_4_exp "pr25490-4-64.rd"
>+    set pr25490_5_exp "pr25490-5-64.rd"
>+    set pr25490_6_exp "pr25490-6-64.rd"
> } else {
>     set ASFLAGS "$ASFLAGS --defsym ALIGN=2"
>     set pr23900_1_exp "pr23900-1-32.rd"
>+    set pr25490_2_exp "pr25490-2-32.rd"
>+    set pr25490_3_exp "pr25490-3-32.rd"
>+    set pr25490_4_exp "pr25490-4-32.rd"
>+    set pr25490_5_exp "pr25490-5-32.rd"
>+    set pr25490_6_exp "pr25490-6-32.rd"
> }
>
>
>@@ -172,6 +182,46 @@ if { [istarget *-*-*linux*]
> 	]
> }
>
>+if [check_gc_sections_available] {
>+    run_ld_link_tests [list \
>+	[list "__patchable_function_entries section 2" \
>+	    "--gc-sections -e _start" \
>+	    "" \
>+	    "" \
>+	    {pr25490-2.s} \
>+	    [list [list "readelf" {-SW} $pr25490_2_exp]] \
>+	    "pr25490-2.exe"] \
>+	[list "__patchable_function_entries section 3" \
>+	    "--gc-sections -e _start" \
>+	    "" \
>+	    "" \
>+	    {pr25490-3.s} \
>+	    [list [list "readelf" {-SW} $pr25490_3_exp]] \
>+	    "pr25490-3.exe"] \
>+	[list "__patchable_function_entries section 4" \
>+	    "--gc-sections -e _start" \
>+	    "" \
>+	    "" \
>+	    {pr25490-4.s} \
>+	    [list [list "readelf" {-SW} $pr25490_4_exp]] \
>+	    "pr25490-4.exe"] \
>+	[list "__patchable_function_entries section 5" \
>+	    "--gc-sections -e _start" \
>+	    "" \
>+	    "" \
>+	    {pr25490-5.s} \
>+	    [list [list "readelf" {-SW} $pr25490_5_exp]] \
>+	    "pr25490-5.exe"] \
>+	[list "__patchable_function_entries section 6" \
>+	    "--gc-sections -e _start" \
>+	    "" \
>+	    "" \
>+	    {pr25490-6.s} \
>+	    [list [list "readelf" {-SW} $pr25490_6_exp]] \
>+	    "pr25490-6.exe"] \
>+	]
>+}
>+
> set LDFLAGS $old_ldflags
> set ASFLAGS $old_asflags
>
>diff --git a/ld/testsuite/ld-elf/pr25490-2-32.rd b/ld/testsuite/ld-elf/pr25490-2-32.rd
>new file mode 100644
>index 00000000000..99ee4dbb5d7
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-2-32.rd
>@@ -0,0 +1,7 @@
>+#source: pr25490-2.s
>+#ld: --gc-sections
>+#readelf: -SW
>+
>+#...
>+ +\[ *[0-9]+\] __patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+4 +00 +WAL +[0-9] +0 +1
>+#pass
>diff --git a/ld/testsuite/ld-elf/pr25490-2-64.rd b/ld/testsuite/ld-elf/pr25490-2-64.rd
>new file mode 100644
>index 00000000000..db086d5aafc
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-2-64.rd
>@@ -0,0 +1,7 @@
>+#source: pr25490-2.s
>+#ld: --gc-sections
>+#readelf: -SW
>+
>+#...
>+ +\[ *[0-9]+\] __patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+8 +00 +WAL +[0-9] +0 +1
>+#pass
>diff --git a/ld/testsuite/ld-elf/pr25490-2.s b/ld/testsuite/ld-elf/pr25490-2.s
>new file mode 100644
>index 00000000000..856bb5fe9d3
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-2.s
>@@ -0,0 +1,9 @@
>+	.text
>+	.globl	_start
>+	.type	_start, %function
>+_start:
>+	.section __patchable_function_entries,"awo",%progbits,_start
>+	.dc.a	.LPFE1
>+	.text
>+.LPFE1:
>+	.byte 0
>diff --git a/ld/testsuite/ld-elf/pr25490-3-32.rd b/ld/testsuite/ld-elf/pr25490-3-32.rd
>new file mode 100644
>index 00000000000..d2765f84c7f
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-3-32.rd
>@@ -0,0 +1,7 @@
>+#source: pr25490-3.s
>+#ld: --gc-sections
>+#readelf: -SW
>+
>+#...
>+ +\[ *[0-9]+\] __patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+4 +00 +WAL +[0-9] +0 +1
>+#pass
>diff --git a/ld/testsuite/ld-elf/pr25490-3-64.rd b/ld/testsuite/ld-elf/pr25490-3-64.rd
>new file mode 100644
>index 00000000000..5faeebe65d8
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-3-64.rd
>@@ -0,0 +1,7 @@
>+#source: pr25490-3.s
>+#ld: --gc-sections
>+#readelf: -SW
>+
>+#...
>+ +\[ *[0-9]+\] __patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+8 +00 +WAL +[0-9] +0 +1
>+#pass
>diff --git a/ld/testsuite/ld-elf/pr25490-3.s b/ld/testsuite/ld-elf/pr25490-3.s
>new file mode 100644
>index 00000000000..427ad69b535
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-3.s
>@@ -0,0 +1,18 @@
>+	.section	.text.bar,"ax",%progbits
>+	.globl	bar
>+	.type	bar, %function
>+bar:
>+	.section __patchable_function_entries,"awo",%progbits,bar
>+	.dc.a	.LPFE1
>+	.section	.text.bar,"ax",%progbits
>+.LPFE1:
>+	.byte 0
>+	.section	.text._start,"ax",%progbits
>+	.globl	_start
>+	.type	_start, %function
>+_start:
>+	.section __patchable_function_entries,"awo",%progbits,_start
>+	.dc.a	.LPFE2
>+	.section	.text._start,"ax",%progbits
>+.LPFE2:
>+	.byte 0
>diff --git a/ld/testsuite/ld-elf/pr25490-4-32.rd b/ld/testsuite/ld-elf/pr25490-4-32.rd
>new file mode 100644
>index 00000000000..5667f40836b
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-4-32.rd
>@@ -0,0 +1,7 @@
>+#source: pr25490-4.s
>+#ld: --gc-sections
>+#readelf: -SW
>+
>+#...
>+ +\[ *[0-9]+\] __patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+8 +00 +WAL +[0-9] +0 +1
>+#pass
>diff --git a/ld/testsuite/ld-elf/pr25490-4-64.rd b/ld/testsuite/ld-elf/pr25490-4-64.rd
>new file mode 100644
>index 00000000000..5a3b34dcd56
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-4-64.rd
>@@ -0,0 +1,7 @@
>+#source: pr25490-4.s
>+#ld: --gc-sections
>+#readelf: -SW
>+
>+#...
>+ +\[ *[0-9]+\] __patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+10 +00 +WAL +[0-9] +0 +1
>+#pass
>diff --git a/ld/testsuite/ld-elf/pr25490-4.s b/ld/testsuite/ld-elf/pr25490-4.s
>new file mode 100644
>index 00000000000..9b3ffcad04d
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-4.s
>@@ -0,0 +1,18 @@
>+	.section	.text.bar,"ax",%progbits
>+	.globl	bar
>+	.type	bar, %function
>+bar:
>+	.section __patchable_function_entries,"awo",%progbits,bar
>+	.dc.a	.LPFE1
>+	.section	.text.bar,"ax",%progbits
>+.LPFE1:
>+	.byte 0
>+	.section	.text._start,"ax",%progbits
>+	.globl	_start
>+	.type	_start, %function
>+_start:
>+	.section __patchable_function_entries,"awo",%progbits,_start
>+	.dc.a	.LPFE2
>+	.section	.text._start,"ax",%progbits
>+.LPFE2:
>+	.dc.a	bar
>diff --git a/ld/testsuite/ld-elf/pr25490-5-32.rd b/ld/testsuite/ld-elf/pr25490-5-32.rd
>new file mode 100644
>index 00000000000..32e19b8b5c8
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-5-32.rd
>@@ -0,0 +1,7 @@
>+#source: pr25490-5.s
>+#ld: --gc-sections
>+#readelf: -SW
>+
>+#...
>+ +\[ *[0-9]+\] __patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+8 +00 +WAL +[0-9] +0 +1
>+#pass
>diff --git a/ld/testsuite/ld-elf/pr25490-5-64.rd b/ld/testsuite/ld-elf/pr25490-5-64.rd
>new file mode 100644
>index 00000000000..17358d5feda
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-5-64.rd
>@@ -0,0 +1,7 @@
>+#source: pr25490-5.s
>+#ld: --gc-sections
>+#readelf: -SW
>+
>+#...
>+ +\[ *[0-9]+\] __patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+10 +00 +WAL +[0-9] +0 +1
>+#pass
>diff --git a/ld/testsuite/ld-elf/pr25490-5.s b/ld/testsuite/ld-elf/pr25490-5.s
>new file mode 100644
>index 00000000000..f9d46b8e0b0
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-5.s
>@@ -0,0 +1,17 @@
>+	.text
>+	.type	bar, %function
>+bar:
>+	.section __patchable_function_entries,"awo",%progbits,bar
>+	.dc.a	.LPFE1
>+	.text
>+.LPFE1:
>+	.byte 0
>+	.text
>+	.globl	_start
>+	.type	_start, %function
>+_start:
>+	.section __patchable_function_entries,"awo",%progbits,_start
>+	.dc.a	.LPFE2
>+	.text
>+.LPFE2:
>+	.byte	0
>diff --git a/ld/testsuite/ld-elf/pr25490-6-32.rd b/ld/testsuite/ld-elf/pr25490-6-32.rd
>new file mode 100644
>index 00000000000..807e83159a8
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-6-32.rd
>@@ -0,0 +1,7 @@
>+#source: pr25490-6.s
>+#ld: --gc-sections
>+#readelf: -SW
>+
>+#...
>+ +\[ *[0-9]+\] __patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+c +00 +WAL +[0-9] +0 +1
>+#pass
>diff --git a/ld/testsuite/ld-elf/pr25490-6-64.rd b/ld/testsuite/ld-elf/pr25490-6-64.rd
>new file mode 100644
>index 00000000000..668eaa45601
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-6-64.rd
>@@ -0,0 +1,7 @@
>+#source: pr25490-6.s
>+#ld: --gc-sections
>+#readelf: -SW
>+
>+#...
>+ +\[ *[0-9]+\] __patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0+18 +00 +WAL +[0-9] +0 +1
>+#pass
>diff --git a/ld/testsuite/ld-elf/pr25490-6.s b/ld/testsuite/ld-elf/pr25490-6.s
>new file mode 100644
>index 00000000000..5f5a348d4d0
>--- /dev/null
>+++ b/ld/testsuite/ld-elf/pr25490-6.s
>@@ -0,0 +1,28 @@
>+	.section .text,"axG",%progbits,bar,comdat
>+	.globl	bar
>+	.type	bar, %function
>+bar:
>+	.section __patchable_function_entries,"awo",%progbits,bar
>+	.dc.a	.LPFE1
>+	.section .text,"axG",%progbits,bar,comdat
>+.LPFE1:
>+	.byte 0
>+	.section .text,"axG",%progbits,foo,comdat
>+	.globl	foo
>+	.type	foo, %function
>+foo:
>+	.section __patchable_function_entries,"awo",%progbits,foo,unique,0
>+	.dc.a	.LPFE2
>+	.section .text,"axG",%progbits,foo,comdat
>+.LPFE2:
>+	.byte 0
>+	.section .text,"axG",%progbits,_start,comdat,unique,1
>+	.globl	_start
>+	.type	_start, %function
>+_start:
>+	.section __patchable_function_entries,"awoG",%progbits,_start,_start,comdat,unique,3
>+	.dc.a	.LPFE3
>+	.section .text,"axG",%progbits,_start,comdat,unique,1
>+.LPFE3:
>+	.dc.a	foo
>+	.dc.a	bar
>-- 
>2.24.1

Does .pushsection directive support the section flag "o" as well?

   .section __patchable_function_entries,"awoG",%progbits,_start,_start,comdat,unique,3
   .pushsection __patchable_function_entries,"awoG",%progbits,_start,_start,comdat,unique,3

How many feature requests from https://sourceware.org/ml/binutils/2019-11/msg00266.html are implemented in this patch?

   Generalize GC support for SHF_LINK_ORDER
   https://sourceware.org/bugzilla/show_bug.cgi?id=24526
   
   Garbage collecting non-alloc SHF_LINK_ORDER sections
   https://sourceware.org/bugzilla/show_bug.cgi?id=25021
   
   Make /DISCARD/ discard SHF_LINK_ORDER sections
   https://sourceware.org/bugzilla/show_bug.cgi?id=25022


If possible, separating the section flag "o" change from ld --gc-sections semantics may be clearer.

--gc-sections is a bit tricky. Its implementation may require more scrutiny.

The desired semantics:

For SHF_ALLOC sections, GC roots consist of
SHT_INIT_ARRAY / SHT_FINI_ARRAY / SHT_PREINIT_ARRAY / (SHT_NOTE not in a section group).
GNU ld may have rules for other GC roots. I haven't check that.

For a non-SHF_ALLOC section, it is a GC root only if all the following
conditions are satisfied:

* it is not a SHT_REL[A] (used by -r --gc-sections and --emit-relocs)
* it is not in a section group with at least one SHF_ALLOC section.
   If it belongs to such a section group, we expect a
   SHF_ALLOC section in the section group responsible for making the whole group
   alive. This semantic is at least expected by
   https://fedoraproject.org/wiki/Toolchain/Watermark

   If it belongs to a section group with no SHF_ALLOC sections => A real
   world example: clang/gcc -fdebug-type-sections places .debug_types and
   .rela.debug_types in a section group. We should consider .debug_types a GC root.
   (see https://reviews.llvm.org/D70146 + https://reviews.llvm.org/D71157)

   GNU ld's current implementation only special cases SEC_DEBUGGING. It'd
   be nice to generalize it.
* it does not have the SHF_LINK_ORDER flag. We expect the linked-to
   section responsible for making it alive.



More information about the Binutils mailing list