[PATCH] bfd: xtensa: keep property tables without linker script KEEP

Alexey Lapshin <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
Property sections are unreferenced, so linker scripts kept them alive
with KEEP(). That does keep the tables, but it also keeps dead code:
gas puts .xt.prop/.xt.lit for a COMDAT function into that function's
group, and _bfd_elf_gc_mark marks every member of a group when one
member is marked. KEEP() on the property section therefore retains the
code, literals, rodata and exception tables of unused C++ template
instantiations and inline functions, bloating the final image. Dropping
KEEP() instead loses the property tables of live code, because
non-COMDAT objects share one .xt.prop that nothing references.

Mark property tables from the gc_mark_extra_sections hook, once the
sections they describe have been marked, using the existing
xtensa_get_property_section lookup. Set gc_mark directly rather than
calling _bfd_elf_gc_mark, so a property section that belongs to a COMDAT
group does not drag in the rest of the group. Linker scripts no longer
need KEEP() for .xt.prop/.xt.lit. Warn once if KEEP is still used for a
property section base name.

bfd/
	* elf32-xtensa.c (elf_xtensa_gc_mark_extra_sections): New
	function. Warn if KEEP is used for a property section.
	(elf_backend_gc_mark_extra_sections): Define.
	(elf_xtensa_gc_mark_hook): Update comment.

include/
	* elf/xtensa.h (XTENSA_PROPERTY_SEC_NAMES): New macro.

ld/
	* testsuite/ld-xtensa/gc-prop.d: New test.
	* testsuite/ld-xtensa/gc-prop.map: New test map check.
	* testsuite/ld-xtensa/gc-prop.s: New test source.
	* testsuite/ld-xtensa/gc-prop.t: New test script.
	* testsuite/ld-xtensa/xtensa.exp: Run it.
---
 bfd/elf32-xtensa.c                 | 76 ++++++++++++++++++++++++++----
 include/elf/xtensa.h               |  3 ++
 ld/testsuite/ld-xtensa/gc-prop.d   |  7 +++
 ld/testsuite/ld-xtensa/gc-prop.map |  9 ++++
 ld/testsuite/ld-xtensa/gc-prop.s   |  9 ++++
 ld/testsuite/ld-xtensa/gc-prop.t   |  7 +++
 ld/testsuite/ld-xtensa/xtensa.exp  |  1 +
 7 files changed, 102 insertions(+), 10 deletions(-)
 create mode 100644 ld/testsuite/ld-xtensa/gc-prop.d
 create mode 100644 ld/testsuite/ld-xtensa/gc-prop.map
 create mode 100644 ld/testsuite/ld-xtensa/gc-prop.s
 create mode 100644 ld/testsuite/ld-xtensa/gc-prop.t

diff --git a/bfd/elf32-xtensa.c b/bfd/elf32-xtensa.c
index eb7fef9331e..2eaaee409b2 100644
--- a/bfd/elf32-xtensa.c
+++ b/bfd/elf32-xtensa.c
@@ -1328,16 +1328,12 @@ elf_xtensa_gc_mark_hook (asection *sec,
 			 struct elf_link_hash_entry *h,
 			 Elf_Internal_Sym *sym)
 {
-  /* Property sections are marked "KEEP" in the linker scripts, but they
-     should not cause other sections to be marked.  (This approach relies
-     on elf_xtensa_discard_info to remove property table entries that
-     describe discarded sections.  Alternatively, it might be more
-     efficient to avoid using "KEEP" in the linker scripts and instead use
-     the gc_mark_extra_sections hook to mark only the property sections
-     that describe marked sections.  That alternative does not work well
-     with the current property table sections, which do not correspond
-     one-to-one with the sections they describe, but that should be fixed
-     someday.) */
+  /* Nothing refers to a property section, so it is kept alive by
+     elf_xtensa_gc_mark_extra_sections instead, and its relocations must
+     not cause other sections to be marked.  (This relies on
+     elf_xtensa_discard_info to remove property table entries that
+     describe discarded sections, which is needed anyway because a
+     property section may describe more than one section.)  */
   if (xtensa_is_property_section (sec))
     return NULL;
 
@@ -1353,6 +1349,65 @@ elf_xtensa_gc_mark_hook (asection *sec,
 }
 
 
+/* Property sections are not referenced by anything, so this pass marks
+   the ones describing sections that have been marked.  */
+
+static bool
+elf_xtensa_gc_mark_extra_sections (struct bfd_link_info *info,
+				   elf_gc_mark_hook_fn gc_mark_hook)
+{
+  static const char *const prop_names[] = XTENSA_PROPERTY_SEC_NAMES;
+  bfd *sub;
+  bool warned = false;
+
+  _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
+
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
+    {
+      asection *sec;
+
+      if (!is_xtensa_elf (sub))
+	continue;
+
+      for (sec = sub->sections; sec != NULL; sec = sec->next)
+	{
+	  size_t i;
+
+	  if (!sec->gc_mark
+	      || (sec->flags & SEC_ALLOC) == 0
+	      || xtensa_is_property_section (sec))
+	    continue;
+
+	  for (i = 0; i < sizeof (prop_names) / sizeof (prop_names[0]); i++)
+	    {
+	      asection *prop_sec =
+		xtensa_get_property_section (sec, prop_names[i]);
+
+	      /* Set "gc_mark" directly rather than calling _bfd_elf_gc_mark:
+	         a property section can be a member of the COMDAT group of
+	         the section it describes, and marking a group member retains
+	         the entire group.  Nothing else needs to be marked because
+	         elf_xtensa_gc_mark_hook ignores relocations in property
+	         sections.  */
+	      if (prop_sec != NULL)
+		{
+		  if (!warned && (prop_sec->flags & SEC_KEEP) != 0)
+		    {
+		      info->callbacks->einfo
+			(_("%P: warning: KEEP should not be used for Xtensa "
+			   "property section %s\n"), prop_names[i]);
+		      warned = true;
+		    }
+		  prop_sec->gc_mark = 1;
+		}
+	    }
+	}
+    }
+
+  return true;
+}
+
+
 /* Create all the dynamic sections.  */
 
 static bool
@@ -11505,6 +11560,7 @@ static const struct bfd_elf_special_section elf_xtensa_special_sections[] =
 #define elf_backend_finish_dynamic_sections  elf_xtensa_finish_dynamic_sections
 #define elf_backend_finish_dynamic_symbol    elf_xtensa_finish_dynamic_symbol
 #define elf_backend_gc_mark_hook	     elf_xtensa_gc_mark_hook
+#define elf_backend_gc_mark_extra_sections   elf_xtensa_gc_mark_extra_sections
 #define elf_backend_grok_prstatus	     elf_xtensa_grok_prstatus
 #define elf_backend_grok_psinfo		     elf_xtensa_grok_psinfo
 #define elf_backend_hide_symbol		     elf_xtensa_hide_symbol
diff --git a/include/elf/xtensa.h b/include/elf/xtensa.h
index 523855e7e81..5fb8485638f 100644
--- a/include/elf/xtensa.h
+++ b/include/elf/xtensa.h
@@ -131,6 +131,9 @@ END_RELOC_NUMBERS (R_XTENSA_max)
 #define XTENSA_LIT_SEC_NAME  ".xt.lit"
 #define XTENSA_PROP_SEC_NAME ".xt.prop"
 
+#define XTENSA_PROPERTY_SEC_NAMES \
+  { XTENSA_INSN_SEC_NAME, XTENSA_LIT_SEC_NAME, XTENSA_PROP_SEC_NAME }
+
 typedef struct property_table_entry_t
 {
   bfd_vma address;
diff --git a/ld/testsuite/ld-xtensa/gc-prop.d b/ld/testsuite/ld-xtensa/gc-prop.d
new file mode 100644
index 00000000000..3e8d3a07186
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/gc-prop.d
@@ -0,0 +1,7 @@
+#source: gc-prop.s
+#ld: -T gc-prop.t --gc-sections
+#map: gc-prop.map
+#readelf: -SW
+#...
+ +\[ *[0-9]+\] \.xt\.prop +PROGBITS +[0-9a-f]+ +[0-9a-f]+ +0*[1-9a-f][0-9a-f]* .*
+#pass
diff --git a/ld/testsuite/ld-xtensa/gc-prop.map b/ld/testsuite/ld-xtensa/gc-prop.map
new file mode 100644
index 00000000000..85ffa79dff0
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/gc-prop.map
@@ -0,0 +1,9 @@
+#...
+Discarded input sections
+#...
+ \.text\.dead +0x[0-9a-f]+ +0x[0-9a-f]+ .*
+#...
+ \.xt\.prop\.dead +0x[0-9a-f]+ +0x[0-9a-f]+ .*
+#...
+\.xt\.prop +0x[0-9a-f]+ +0x0*[1-9a-f][0-9a-f]*
+#pass
diff --git a/ld/testsuite/ld-xtensa/gc-prop.s b/ld/testsuite/ld-xtensa/gc-prop.s
new file mode 100644
index 00000000000..56396206018
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/gc-prop.s
@@ -0,0 +1,9 @@
+	.section	.text.dead,"axG",@progbits,dead,comdat
+	.global	dead
+dead:
+	ret
+
+	.text
+	.global	_start
+_start:
+	ret
diff --git a/ld/testsuite/ld-xtensa/gc-prop.t b/ld/testsuite/ld-xtensa/gc-prop.t
new file mode 100644
index 00000000000..d493873cfce
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/gc-prop.t
@@ -0,0 +1,7 @@
+ENTRY(_start)
+SECTIONS
+{
+  .text 0x1000 : { *(.literal .literal.* .text .text.*) }
+  .xt.prop 0 : { *(.xt.prop .xt.prop.* .gnu.linkonce.prop.*) }
+  .xt.lit 0 : { *(.xt.lit .xt.lit.* .gnu.linkonce.p.*) }
+}
diff --git a/ld/testsuite/ld-xtensa/xtensa.exp b/ld/testsuite/ld-xtensa/xtensa.exp
index 06349571d4f..8517f3437fd 100644
--- a/ld/testsuite/ld-xtensa/xtensa.exp
+++ b/ld/testsuite/ld-xtensa/xtensa.exp
@@ -26,6 +26,7 @@ if { !([istarget "xtensa*-*-*"]) } {
 run_dump_test "call_overflow"
 run_dump_test "coalesce"
 run_dump_test "diff_overflow"
+run_dump_test "gc-prop"
 run_dump_test "lcall"
 run_dump_test "relax-diff1"
 run_dump_test "relax-loc"
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.