public inbox for gnu-gabi@sourceware.org
 help / color / mirror / Atom feed
* [RFC] SHF_GNU_RETAIN ELF Section Flag
@ 2020-09-15 12:06 Jozef Lawrynowicz
  2020-09-15 12:09 ` Florian Weimer
  0 siblings, 1 reply; 20+ messages in thread
From: Jozef Lawrynowicz @ 2020-09-15 12:06 UTC (permalink / raw)
  To: gnu-gabi

[-- Attachment #1: Type: text/plain, Size: 4174 bytes --]

Hi,

I'd like to propose a new ELF section flag, SHF_GNU_RETAIN, for addition
to the GNU gABI.

This flag instructs the linker to "retain" the section in the output
file, even if garbage collection would remove it because it appears
unused.

The intention is to be able to apply the "retain" attribute to
declarations of functions and data in the source code, and have the
SHF_GNU_RETAIN flag be applied to the section containing the
declaration.

======================================================
Section Attribute Flags
+-------------------------------------+
| Name           | Value              |
+-------------------------------------+
| SHF_GNU_RETAIN | 0x200000 (1 << 21) |
+-------------------------------------+

SHF_GNU_RETAIN
  The section should not be garbage collected by the linker, even if it
  appears unused.

======================================================

----------
Motivation
----------
Linker garbage collection is a useful feature to help reduce the size of
linked output file, where sections are removed if they exclusively
contain definitions of functions or data that are never referenced by
other parts of the application.

Currently, the KEEP linker script directive can be used to save a
section from garbage collection. The new SHF_GNU_RETAIN flag has the
same effect as KEEP, but since it is an ELF section flag, it means that
this property can be propagated through the toolchain, from the
compiler, through the assembler, to the linker.

This enables a new "retain" attribute to be set on function and data
declarations in the source code, which communicates the need to set the
SHF_GNU_RETAIN flag on the containing section to downstream tools. In
some situations, this has benefits over applying the KEEP directive in
the linker script:

- The requirement for protection from garbage collection might be
  application-specific, so consolidating this requirement to be
  contained entirely within the source code improves portability.
- The user doesn't have to work out which section a function or data
  object declaration will be placed in, and then set the KEEP directive
  on that section. They can just set the attribute in the source code
  and leave the rest for the toolchain to handle.
- Generally avoiding linker script modifications can improve the user
  experience, especially when the user is inexperienced with the linker
  script format.  The boilerplate linker script code required for
  standard application operation can make modifications error-prone and
  have unintended side-effects.

--------------
Implementation
--------------
GCC supports a new "retain" attribute, which can be set on any
declaration of function or data which could have a section. This means
it can't be set on an automatic variable, for example.

GAS supports a new ".retain [section name]" directive, which is used to
apply SHF_GNU_RETAIN to the section named "section name". If "section
name" is ommitted, SHF_GNU_RETAIN is applied to the current section the
directive resides in.  Alternatively, the "R" flag is recognized by the
"flags" argument to the .section directive and will apply SHF_GNU_RETAIN
to that section.  It is intended that SHF_GNU_RETAIN does not interfere
with any validation when switching to a section. It can be used to
augment the section flags in a section which has already been created.

When garbage collection is enabled, LD marks sections which have the
SHF_GNU_RETAIN flag to save them from garbage collection. The underyling
behavior is the same as if the section had the KEEP linker script
directive applied.

The user can always override SHF_GNU_RETAIN by placing the section in
/DISCARD/.

For reference, I've attached GCC and Binutils patches which implement
the attribute. These are not "production ready", as there are some
further tweaks to make, and more testing is required, but the
functionality is working and the new tests are passing on msp430-elf,
arm-eabi and x86_64-pc-linux-gnu.

If this proposal is suitable for the GNU gABI, I will further improve
and test the implementation, and submit the patches upstream soon.

Thanks, and I look forward to hearing your thoughts.
Jozef

[-- Attachment #2: 0001-Add-support-for-retain-attribute.patch --]
[-- Type: text/plain, Size: 16153 bytes --]

From 308af5a66ad9c23b75804a43a7692e1884ce271b Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@mittosystems.com>
Date: Tue, 8 Sep 2020 20:41:03 +0100
Subject: [PATCH] Add support for "retain" attribute

---
 gcc/c-family/c-attribs.c                   | 33 +++++++++++++
 gcc/config/arm/arm.c                       |  2 +
 gcc/config/arm/unknown-elf.h               |  5 +-
 gcc/config/elfos.h                         | 16 +++++++
 gcc/config/i386/i386.c                     |  2 +
 gcc/config/msp430/msp430.c                 |  7 ++-
 gcc/defaults.h                             |  4 ++
 gcc/doc/extend.texi                        | 23 +++++++++
 gcc/testsuite/c-c++-common/attr-retain-1.c | 56 ++++++++++++++++++++++
 gcc/testsuite/c-c++-common/attr-retain-2.c | 26 ++++++++++
 gcc/testsuite/c-c++-common/attr-retain-3.c | 10 ++++
 gcc/varasm.c                               | 19 +++++++-
 gcc/varasm.h                               |  3 ++
 13 files changed, 203 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/attr-retain-1.c
 create mode 100644 gcc/testsuite/c-c++-common/attr-retain-2.c
 create mode 100644 gcc/testsuite/c-c++-common/attr-retain-3.c

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 37214831538..99839367e88 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -150,6 +150,7 @@ static tree handle_designated_init_attribute (tree *, tree, tree, int, bool *);
 static tree handle_patchable_function_entry_attribute (tree *, tree, tree,
 						       int, bool *);
 static tree handle_copy_attribute (tree *, tree, tree, int, bool *);
+static tree handle_retain_attribute (tree *, tree, tree, int, bool *);
 
 /* Helper to define attribute exclusions.  */
 #define ATTR_EXCL(name, function, type, variable)	\
@@ -484,6 +485,8 @@ const struct attribute_spec c_common_attribute_table[] =
 			      handle_noinit_attribute, attr_noinit_exclusions },
   { "access",		      1, 3, false, true, true, false,
 			      handle_access_attribute, NULL },
+  { "retain",		      0, 0, true, false, false, false,
+			      handle_retain_attribute, NULL },
   { NULL,                     0, 0, false, false, false, false, NULL, NULL }
 };
 
@@ -2420,6 +2423,36 @@ handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args,
 	       decl, is_alias ? "alias" : "ifunc");
     }
 
+  return NULL_TREE;
+}
+
+/* Handle a "retain" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_retain_attribute (tree * pnode,
+			 tree   name,
+			 tree   args ATTRIBUTE_UNUSED,
+			 int    flags ATTRIBUTE_UNUSED,
+			 bool *no_add_attrs)
+{
+  tree node = *pnode;
+
+  /* FIXME: Maybe it would be useful to allow the attribute to be set on types
+     as well... */
+  if (TREE_CODE (node) == FUNCTION_DECL
+      || (VAR_P (node) && TREE_STATIC (node)))
+    {
+      TREE_USED (node) = 1;
+      DECL_PRESERVE_P (node) = 1;
+      if (VAR_P (node))
+	DECL_READ_P (node) = 1;
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
 
   return NULL_TREE;
 }
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index dd78141519e..5e36644e4a7 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -21407,6 +21407,8 @@ arm_asm_declare_function_name (FILE *file, const char *name, tree decl)
 
   ARM_DECLARE_FUNCTION_NAME (file, name, decl);
   ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
+  if (lookup_attribute ("retain", DECL_ATTRIBUTES (decl)))
+    ASM_OUTPUT_RETAIN_DIRECTIVE (file, decl);
   ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
   ASM_OUTPUT_LABEL (file, name);
 
diff --git a/gcc/config/arm/unknown-elf.h b/gcc/config/arm/unknown-elf.h
index 9ad2947505f..d78d40cc00e 100644
--- a/gcc/config/arm/unknown-elf.h
+++ b/gcc/config/arm/unknown-elf.h
@@ -62,7 +62,7 @@
 	switch_to_section (get_named_section (DECL, NULL, 0));		\
       else								\
 	switch_to_section (bss_section);				\
-      									\
+									\
       ASM_OUTPUT_ALIGN (FILE, floor_log2 (ALIGN / BITS_PER_UNIT));	\
 									\
       last_assemble_variable_decl = DECL;				\
@@ -80,6 +80,9 @@
       else								\
 	switch_to_section (bss_section);				\
 									\
+      if (DECL && lookup_attribute ("retain", DECL_ATTRIBUTES (DECL)))	\
+	ASM_OUTPUT_RETAIN_DIRECTIVE (FILE, DECL);			\
+									\
       ASM_OUTPUT_ALIGN (FILE, floor_log2 (ALIGN / BITS_PER_UNIT));	\
       ASM_OUTPUT_LABEL (FILE, NAME);					\
       fprintf (FILE, "\t.space\t%d\n", SIZE ? (int) SIZE : 1);		\
diff --git a/gcc/config/elfos.h b/gcc/config/elfos.h
index 74a3eafda6b..9be1948c008 100644
--- a/gcc/config/elfos.h
+++ b/gcc/config/elfos.h
@@ -275,6 +275,15 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define ASM_DECLARE_RESULT(FILE, RESULT)
 #endif
 
+#ifndef ASM_OUTPUT_RETAIN_DIRECTIVE
+#define ASM_OUTPUT_RETAIN_DIRECTIVE(STREAM, DECL)	\
+  do							\
+    {							\
+	assemble_retain (STREAM, DECL);			\
+    }							\
+  while (0)
+#endif
+
 /* These macros generate the special .type and .size directives which
    are used to set the corresponding fields of the linker symbol table
    entries in an ELF object file under SVR4.  These macros also output
@@ -289,6 +298,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
   do								\
     {								\
       ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function");	\
+      if (lookup_attribute ("retain", DECL_ATTRIBUTES (DECL))) \
+	ASM_OUTPUT_RETAIN_DIRECTIVE (FILE, DECL);		\
       ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL));		\
       ASM_OUTPUT_FUNCTION_LABEL (FILE, NAME, DECL);		\
     }								\
@@ -305,6 +316,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
   do								\
     {								\
       ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function");	\
+      if (lookup_attribute ("retain", DECL_ATTRIBUTES (DECL))) \
+	ASM_OUTPUT_RETAIN_DIRECTIVE (FILE, DECL);		\
       ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL));		\
       ASM_OUTPUT_FUNCTION_LABEL (FILE, NAME, DECL);		\
     }								\
@@ -335,6 +348,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
       else								\
 	ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object");		\
 									\
+      if (lookup_attribute ("retain", DECL_ATTRIBUTES (DECL))) \
+	ASM_OUTPUT_RETAIN_DIRECTIVE (FILE, DECL);			\
+									\
       size_directive_output = 0;					\
       if (!flag_inhibit_size_directive					\
 	  && (DECL) && DECL_SIZE (DECL))				\
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index a15807d91da..062d68765d5 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -850,6 +850,8 @@ x86_elf_aligned_decl_common (FILE *file, tree decl,
   assemble_name (file, name);
   fprintf (file, "," HOST_WIDE_INT_PRINT_UNSIGNED ",%u\n",
 	   size, align / BITS_PER_UNIT);
+  if (lookup_attribute ("retain", DECL_ATTRIBUTES (decl)))
+    ASM_OUTPUT_RETAIN_DIRECTIVE (file, decl);
 }
 #endif
 
diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c
index a299ed7f9d1..dac3896e416 100644
--- a/gcc/config/msp430/msp430.c
+++ b/gcc/config/msp430/msp430.c
@@ -1746,6 +1746,8 @@ msp430_start_function (FILE *file, const char *name, tree decl)
 
   switch_to_section (function_section (decl));
   ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
+  if (lookup_attribute ("retain", DECL_ATTRIBUTES (decl)))
+    ASM_OUTPUT_RETAIN_DIRECTIVE (file, decl);
   ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
 }
 
@@ -2018,7 +2020,8 @@ msp430_output_aligned_decl_common (FILE *		  stream,
       && !has_attr (ATTR_LOWER, decl)
       && !has_attr (ATTR_UPPER, decl)
       && !has_attr (ATTR_PERSIST, decl)
-      && !has_attr (ATTR_NOINIT, decl))
+      && !has_attr (ATTR_NOINIT, decl)
+      && !has_attr ("retain", decl))
     {
       if (local)
 	{
@@ -2064,6 +2067,8 @@ msp430_output_aligned_decl_common (FILE *		  stream,
       ASM_OUTPUT_LABEL (stream, name);
       ASM_OUTPUT_SKIP (stream, size ? size : 1);
     }
+  if (decl && lookup_attribute ("retain", DECL_ATTRIBUTES (decl)))
+    ASM_OUTPUT_RETAIN_DIRECTIVE (stream, decl);
 }
 
 #undef TARGET_ASM_FILE_END
diff --git a/gcc/defaults.h b/gcc/defaults.h
index f1a38626624..9899d4abce2 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -260,6 +260,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #endif
 #endif
 
+#ifndef ASM_OUTPUT_RETAIN_DIRECTIVE
+#define ASM_OUTPUT_RETAIN_DIRECTIVE(STREAM, DECL) hook_void_void
+#endif
+
 /* This determines whether or not we support weak symbols.  SUPPORTS_WEAK
    must be a preprocessor constant.  */
 #ifndef SUPPORTS_WEAK
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 3b37aba5795..5342dd2801d 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -3578,6 +3578,17 @@ diagnosed.  Because a pure function cannot have any observable side
 effects it does not make sense for such a function to return @code{void}.
 Declaring such a function is diagnosed.
 
+@item retain
+@cindex @code{retain} function attribute
+The @code{retain} attribute, attached to a function, means that function must
+not be garbage collected by the linker, even if it appears unused.
+
+The section containing the function is marked with the SHF_GNU_RETAIN flag,
+which is a GNU extension to the ELF standard.
+
+This attribute implies, and has the same restrictions as, the @code{used}
+attribute.
+
 @item returns_nonnull
 @cindex @code{returns_nonnull} function attribute
 The @code{returns_nonnull} attribute specifies that the function
@@ -7168,6 +7179,18 @@ been fixed in GCC 4.4 but the change can lead to differences in the
 structure layout.  See the documentation of
 @option{-Wpacked-bitfield-compat} for more information.
 
+@item retain
+@cindex @code{retain} variable attribute
+The @code{retain} attribute, attached to a variable with static storage, means
+that variable must not be garbage collected by the linker, even if it appears
+unused.
+
+The section containing the variable is marked with the SHF_GNU_RETAIN flag,
+which is a GNU extension to the ELF standard.
+
+This attribute implies, and has the same restrictions as, the @code{used}
+attribute.
+
 @item section ("@var{section-name}")
 @cindex @code{section} variable attribute
 Normally, the compiler places the objects it generates in sections like
diff --git a/gcc/testsuite/c-c++-common/attr-retain-1.c b/gcc/testsuite/c-c++-common/attr-retain-1.c
new file mode 100644
index 00000000000..2ed6f9b220c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/attr-retain-1.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-final { scan-assembler "\\.retain\t\\.bss\\.a1" } } */
+/* { dg-final { scan-assembler "\\.retain\t\\.bss\\.b1" } } */
+/* { dg-final { scan-assembler "\\.retain\t\\.data\\.c1" } } */
+/* { dg-final { scan-assembler "\\.retain\t\\.bss\\.sa1" } } */
+/* { dg-final { scan-assembler "\\.retain\t\\.bss\\.sb1" } } */
+/* { dg-final { scan-assembler "\\.retain\t\\.data\\.sc1" } } */
+/* { dg-final { scan-assembler "\\.retain\t\\.text\\.foo1" } } */
+/* { dg-final { scan-assembler "\\.retain\t\\.bss\\.lsa" } } */
+/* { dg-final { scan-assembler "\\.retain\t\\.bss\\.lsb" } } */
+/* { dg-final { scan-assembler "\\.retain\t\\.data\\.lsc" } } */
+
+/* Test .retain directives are emitted for declarations using the "retain"
+   when they are each put in their own sections.  */
+
+#define RETAIN __attribute__((retain))
+#define SECTION(X) __attribute__((section(X)))
+
+/* This group of functions and data should be garbage collected by the
+   linker.  */
+int SECTION(".bss.a0") a0;
+int SECTION(".bss.b0") b0 = 0;
+int SECTION(".data.c0") c0 = 1;
+static int SECTION(".bss.sa0") sa0;
+static int SECTION(".bss.sb0") sb0 = 0;
+static int SECTION(".data.sc0") sc0 = 1;
+void SECTION(".text.foo0") foo0 (void) {}
+
+/* The "retain" attribute set on this group of functions and data should protect
+   them from linker garbage collection.  */
+int RETAIN SECTION(".bss.a1") a1;
+int RETAIN SECTION(".bss.b1") b1 = 0;
+int RETAIN SECTION(".data.c1") c1 = 1;
+static int RETAIN SECTION(".bss.sa1") sa1;
+static int RETAIN SECTION(".bss.sb1") sb1 = 0;
+static int RETAIN SECTION(".data.sc1") sc1 = 1;
+void RETAIN SECTION(".text.foo1") foo1 (void) {}
+
+/* .text.foo2 should be garbage collected, but the static variables defined
+   inside it have the retain attribute so should not be garbage collected.  */
+void SECTION(".text.foo2")
+foo2 (void)
+{
+  static int RETAIN SECTION(".bss.lsa") lsa;
+  static int RETAIN SECTION(".bss.lsb") lsb = 0;
+  static int RETAIN SECTION(".data.lsc") lsc = 1;
+  lsa++;
+  lsb++;
+  lsc++;
+}
+
+int main (void)
+{
+  while (1);
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/attr-retain-2.c b/gcc/testsuite/c-c++-common/attr-retain-2.c
new file mode 100644
index 00000000000..cd906246cbf
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/attr-retain-2.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-final { scan-assembler-times "\\.retain" 10 } } */
+
+/* Test .retain directives are emitted for declarations using the "retain"
+   attribute, even when symbols don't have an explicit section.  */
+
+#define RETAIN __attribute__((retain))
+
+int RETAIN a1;
+int RETAIN b1 = 0;
+int RETAIN c1 = 1;
+static int RETAIN sa1;
+static int RETAIN sb1 = 0;
+static int RETAIN sc1 = 1;
+void RETAIN foo1 (void) {}
+
+void
+foo2 (void)
+{
+  static int RETAIN lsa;
+  static int RETAIN lsb = 0;
+  static int RETAIN lsc = 1;
+  lsa++;
+  lsb++;
+  lsc++;
+}
diff --git a/gcc/testsuite/c-c++-common/attr-retain-3.c b/gcc/testsuite/c-c++-common/attr-retain-3.c
new file mode 100644
index 00000000000..a8c1917e38a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/attr-retain-3.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+
+typedef int int_retain __attribute__((retain)); /* { dg-warning "" "'retain' attribute ignored" } */
+
+void
+foo (void)
+{
+  int __attribute__((retain)) a; /* { dg-warning "" "'retain' attribute ignored" } */
+  while(a++);
+}
diff --git a/gcc/varasm.c b/gcc/varasm.c
index ea0b59cf44a..db67329fe74 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -483,11 +483,13 @@ resolve_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED,
    support is localized here.  */
 
 static void
-asm_output_aligned_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
+asm_output_aligned_bss (FILE *file, tree decl,
 			const char *name, unsigned HOST_WIDE_INT size,
 			int align)
 {
   switch_to_section (bss_section);
+  if (lookup_attribute ("retain", DECL_ATTRIBUTES (decl)))
+    ASM_OUTPUT_RETAIN_DIRECTIVE (file, decl);
   ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
 #ifdef ASM_DECLARE_OBJECT_NAME
   last_assemble_variable_decl = decl;
@@ -6225,6 +6227,21 @@ assemble_alias (tree decl, tree target)
     }
 }
 
+/* Emit a ".retain" assembler directive, which applies the SHF_GNU_RETAIN flag
+   to the specified section.  This indicates that the linker should not garbage
+   collect the section, even if it appears unused.  */
+void
+assemble_retain (FILE *stream, tree decl)
+{
+  if (DECL_SECTION_NAME (decl))
+    fprintf (stream, "\t.retain\t%s\n", DECL_SECTION_NAME (decl));
+  else
+    /* If the section name isn't readily available, just output the bare
+       ".retain" directive, which indicates the current section should be
+       retained.  */
+    fprintf (stream, "\t.retain\n");
+}
+
 /* Record and output a table of translations from original function
    to its transaction aware clone.  Note that tm_pure functions are
    considered to be their own clone.  */
diff --git a/gcc/varasm.h b/gcc/varasm.h
index 1b715ab1736..97001d8975f 100644
--- a/gcc/varasm.h
+++ b/gcc/varasm.h
@@ -51,6 +51,9 @@ extern void merge_weak (tree, tree);
 /* Make one symbol an alias for another.  */
 extern void assemble_alias (tree, tree);
 
+/* Emit the .retain directive.  */
+void assemble_retain (FILE *stream, tree decl);
+
 /* Return nonzero if VALUE is a valid constant-valued expression
    for use in initializing a static variable; one that can be an
    element of a "constant" initializer.
-- 
2.28.0


[-- Attachment #3: 0001-Support-SHF_GNU_RETAIN-ELF-section-flag.patch --]
[-- Type: text/plain, Size: 25376 bytes --]

From c3992c8f10a89a0133be0d0c0ca896b04d4f72fd Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@mittosystems.com>
Date: Wed, 9 Sep 2020 22:00:16 +0100
Subject: [PATCH] Support SHF_GNU_RETAIN ELF section flag

---
 bfd/elflink.c                     |   3 +-
 binutils/readelf.c                |   4 +
 gas/config/obj-elf.c              |  57 +++++++++++++
 gas/doc/as.texi                   |  17 ++++
 gas/testsuite/gas/elf/elf.exp     |   5 ++
 gas/testsuite/gas/elf/retain1.d   |  24 ++++++
 gas/testsuite/gas/elf/retain1.s   | 131 +++++++++++++++++++++++++++++
 gas/testsuite/gas/elf/retain2.d   |   2 +
 gas/testsuite/gas/elf/retain2.l   |   3 +
 gas/testsuite/gas/elf/retain2.s   |   7 ++
 gas/testsuite/gas/elf/retain3.d   |  24 ++++++
 gas/testsuite/gas/elf/retain3.s   | 121 +++++++++++++++++++++++++++
 gas/testsuite/gas/elf/section10.d |   4 +-
 include/elf/common.h              |   1 +
 ld/testsuite/ld-elf/elf.exp       |  14 ++++
 ld/testsuite/ld-elf/retain1.msg   |   8 ++
 ld/testsuite/ld-elf/retain1.s     | 134 ++++++++++++++++++++++++++++++
 ld/testsuite/ld-elf/retain2.d     |   5 ++
 ld/testsuite/ld-elf/retain2.ld    |   7 ++
 ld/testsuite/ld-elf/retain2.map   |  18 ++++
 ld/testsuite/ld-elf/retain3.msg   |   8 ++
 ld/testsuite/ld-elf/retain3.s     | 124 +++++++++++++++++++++++++++
 22 files changed, 718 insertions(+), 3 deletions(-)
 create mode 100644 gas/testsuite/gas/elf/retain1.d
 create mode 100644 gas/testsuite/gas/elf/retain1.s
 create mode 100644 gas/testsuite/gas/elf/retain2.d
 create mode 100644 gas/testsuite/gas/elf/retain2.l
 create mode 100644 gas/testsuite/gas/elf/retain2.s
 create mode 100644 gas/testsuite/gas/elf/retain3.d
 create mode 100644 gas/testsuite/gas/elf/retain3.s
 create mode 100644 ld/testsuite/ld-elf/retain1.msg
 create mode 100644 ld/testsuite/ld-elf/retain1.s
 create mode 100644 ld/testsuite/ld-elf/retain2.d
 create mode 100644 ld/testsuite/ld-elf/retain2.ld
 create mode 100644 ld/testsuite/ld-elf/retain2.map
 create mode 100644 ld/testsuite/ld-elf/retain3.msg
 create mode 100644 ld/testsuite/ld-elf/retain3.s

diff --git a/bfd/elflink.c b/bfd/elflink.c
index 0e339f3c1e..6d1a1c5105 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -13977,7 +13977,8 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
 			|| (elf_section_data (o)->this_hdr.sh_type
 			    == SHT_FINI_ARRAY)))
 		|| (elf_section_data (o)->this_hdr.sh_type == SHT_NOTE
-		    && elf_next_in_group (o) == NULL )))
+		    && elf_next_in_group (o) == NULL)
+		|| (elf_section_flags (o) & SHF_GNU_RETAIN)))
 	  {
 	    if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
 	      return FALSE;
diff --git a/binutils/readelf.c b/binutils/readelf.c
index cb4208f7b9..00502f7058 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -5977,6 +5977,8 @@ get_elf_section_flags (Filedata * filedata, bfd_vma sh_flags)
       /* 24 */ { STRING_COMMA_LEN ("GNU_MBIND") },
       /* VLE specific.  */
       /* 25 */ { STRING_COMMA_LEN ("VLE") },
+      /* GNU specific.  */
+      /* 26 */ { STRING_COMMA_LEN ("GNU_RETAIN") },
     };
 
   if (do_section_details)
@@ -6010,6 +6012,7 @@ get_elf_section_flags (Filedata * filedata, bfd_vma sh_flags)
 	    case SHF_EXCLUDE:		sindex = 18; break;
 	    case SHF_COMPRESSED:	sindex = 20; break;
 	    case SHF_GNU_MBIND:		sindex = 24; break;
+	    case SHF_GNU_RETAIN:	sindex = 26; break;
 
 	    default:
 	      sindex = -1;
@@ -6108,6 +6111,7 @@ get_elf_section_flags (Filedata * filedata, bfd_vma sh_flags)
 	    case SHF_EXCLUDE:		*p = 'E'; break;
 	    case SHF_COMPRESSED:	*p = 'C'; break;
 	    case SHF_GNU_MBIND:		*p = 'D'; break;
+	    case SHF_GNU_RETAIN:	*p = 'R'; break;
 
 	    default:
 	      if ((filedata->file_header.e_machine == EM_X86_64
diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index 9e39707801..0e8f3aa642 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -78,6 +78,7 @@ static void obj_elf_gnu_attribute (int);
 static void obj_elf_tls_common (int);
 static void obj_elf_lcomm (int);
 static void obj_elf_struct (int);
+static void obj_elf_retain (int);
 
 static const pseudo_typeS elf_pseudo_table[] =
 {
@@ -119,6 +120,9 @@ static const pseudo_typeS elf_pseudo_table[] =
   /* A GNU extension for object attributes.  */
   {"gnu_attribute", obj_elf_gnu_attribute, 0},
 
+  /* A GNU extension for preventing linker garbage collection of sections.  */
+  {"retain", obj_elf_retain, 0},
+
   /* These are used for dwarf.  */
   {"2byte", cons, 2},
   {"4byte", cons, 4},
@@ -857,6 +861,9 @@ obj_elf_parse_section_letters (char *str, size_t len,
 	case 'd':
 	  *gnu_attr |= SHF_GNU_MBIND;
 	  break;
+	case 'R':
+	  *gnu_attr |= SHF_GNU_RETAIN;
+	  break;
 	case '?':
 	  *is_clone = TRUE;
 	  break;
@@ -1986,6 +1993,56 @@ obj_elf_gnu_attribute (int ignored ATTRIBUTE_UNUSED)
   obj_elf_vendor_attribute (OBJ_ATTR_GNU);
 }
 
+/* Parse a .retain ["sectionname"] directive.
+   The SHF_GNU_RETAIN flag should be applied to "section name".
+   If section name is omitted, then the SHF_GNU_RETAIN flag should be
+   applied to the current section being assembled.  */
+static void
+obj_elf_retain (int ignored ATTRIBUTE_UNUSED)
+{
+  const char *name;
+  symbolS *secsym;
+  asection *bfdsec;
+
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer == '\n')
+    {
+      name = now_seg->name;
+      if (name == NULL)
+	{
+	  as_bad (_("\".retain\" directive not within a section"));
+	  ignore_rest_of_line ();
+	  return;
+	}
+    }
+  else
+    {
+      name = obj_elf_section_name ();
+      secsym = symbol_find (name);
+      if (secsym == NULL)
+	{
+	  as_bad (_("section '%s' has not been declared"), name);
+	  ignore_rest_of_line ();
+	  return;
+	}
+      else if (secsym != NULL
+	       && !symbol_section_p (secsym))
+	{
+	  as_bad (_("'%s' is not a section name, expected "
+		    "\".retain [section name]\""), name);
+	  ignore_rest_of_line ();
+	  return;
+	}
+    }
+  demand_empty_rest_of_line ();
+
+  bfdsec = bfd_get_section_by_name (stdoutput, name);
+  if (bfdsec != NULL)
+    elf_section_flags (bfdsec) |= SHF_GNU_RETAIN;
+  else
+    as_bad (_("Couldn't find BFD section for %s\n"), name);
+}
+
 void
 elf_obj_read_begin_hook (void)
 {
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index 112eaf810c..3ecbf88023 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -4468,6 +4468,7 @@ Some machine configurations provide additional directives.
 * Quad::                        @code{.quad @var{bignums}}
 * Reloc::			@code{.reloc @var{offset}, @var{reloc_name}[, @var{expression}]}
 * Rept::			@code{.rept @var{count}}
+* Retain::			@code{.retain ["@var{sectionname}"]}
 * Sbttl::                       @code{.sbttl "@var{subheading}"}
 @ifset COFF
 * Scl::                         @code{.scl @var{class}}
@@ -6468,6 +6469,22 @@ is equivalent to assembling
 A count of zero is allowed, but nothing is generated.  Negative counts are not
 allowed and if encountered will be treated as if they were zero.
 
+@ifset ELF
+@node Retain
+@section @code{.retain ["@var{sectionname}"]}
+
+@cindex @code{retain} directive
+@cindex SHF_GNU_RETAIN
+
+Apply the @var{SHF_GNU_RETAIN} flag to the section named @var{sectionname}, or
+the current section the directive resides in, if this argument is
+omitted.
+
+The SHF_GNU_RETAIN section flag indicates that the given section should not be
+garbage collected by the linker, even if it appears unused.
+
+@end ifset
+
 @node Sbttl
 @section @code{.sbttl "@var{subheading}"}
 
diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
index 8520421ba3..3a4879e348 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -307,6 +307,11 @@ if { [is_elf_format] } then {
 
     run_dump_test "strtab"
 
+    # Tests for the .retain directive/SHF_GNU_RETAIN.
+    run_dump_test "retain1"
+    run_dump_test "retain2"
+    run_dump_test "retain3"
+
     run_dump_test "bignums"
     run_dump_test "section-symbol-redef"
     
diff --git a/gas/testsuite/gas/elf/retain1.d b/gas/testsuite/gas/elf/retain1.d
new file mode 100644
index 0000000000..48c57f1241
--- /dev/null
+++ b/gas/testsuite/gas/elf/retain1.d
@@ -0,0 +1,24 @@
+#readelf: -S --wide
+#name: SHF_GNU_RETAIN 1
+
+#...
+  \[..\] .bss.a0[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+  \[..\] .bss.b0[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+  \[..\] .data.c0[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+  \[..\] .bss.sa0[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+  \[..\] .bss.sb0[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+  \[..\] .data.sc0[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+  \[..\] .text.foo0[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  AX.*
+  \[..\] .bss.a1[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .bss.b1[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .data.c1[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .bss.sa1[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .bss.sb1[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .data.sc1[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .text.foo1[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXR.*
+  \[..\] .text.foo2[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  AX.*
+#...
+  \[..\] .bss.lsa[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .bss.lsb[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .data.lsc[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#pass
diff --git a/gas/testsuite/gas/elf/retain1.s b/gas/testsuite/gas/elf/retain1.s
new file mode 100644
index 0000000000..2ea652ea35
--- /dev/null
+++ b/gas/testsuite/gas/elf/retain1.s
@@ -0,0 +1,131 @@
+.text
+	.global	a0
+	.section	.bss.a0,"aw"
+	.balign 2
+	.type	a0, STT_OBJECT
+	.size	a0, 2
+a0:
+	.zero	2
+	.global	b0
+	.section	.bss.b0,"aw"
+	.balign 2
+	.type	b0, STT_OBJECT
+	.size	b0, 2
+b0:
+	.zero	2
+	.global	c0
+	.section	.data.c0,"aw"
+	.balign 2
+	.type	c0, STT_OBJECT
+	.size	c0, 2
+c0:
+	.short	1
+	.section	.bss.sa0,"aw"
+	.balign 2
+	.type	sa0, STT_OBJECT
+	.size	sa0, 2
+sa0:
+	.zero	2
+	.section	.bss.sb0,"aw"
+	.balign 2
+	.type	sb0, STT_OBJECT
+	.size	sb0, 2
+sb0:
+	.zero	2
+	.section	.data.sc0,"aw"
+	.balign 2
+	.type	sc0, STT_OBJECT
+	.size	sc0, 2
+sc0:
+	.short	1
+	.section	.text.foo0,"ax"
+	.balign 2
+	.global	foo0
+	.type	foo0, STT_FUNC
+foo0:
+	.size	foo0, .-foo0
+	.global	a1
+	.section	.bss.a1,"aw"
+	.balign 2
+	.type	a1, STT_OBJECT
+	.retain	.bss.a1
+	.size	a1, 2
+a1:
+	.zero	2
+	.global	b1
+	.section	.bss.b1,"aw"
+	.balign 2
+	.type	b1, STT_OBJECT
+	.retain	.bss.b1
+	.size	b1, 2
+b1:
+	.zero	2
+	.global	c1
+	.section	.data.c1,"aw"
+	.balign 2
+	.type	c1, STT_OBJECT
+	.retain	.data.c1
+	.size	c1, 2
+c1:
+	.short	1
+	.section	.bss.sa1,"aw"
+	.balign 2
+	.type	sa1, STT_OBJECT
+	.retain	.bss.sa1
+	.size	sa1, 2
+sa1:
+	.zero	2
+	.section	.bss.sb1,"aw"
+	.balign 2
+	.type	sb1, STT_OBJECT
+	.retain	.bss.sb1
+	.size	sb1, 2
+sb1:
+	.zero	2
+	.section	.data.sc1,"aw"
+	.balign 2
+	.type	sc1, STT_OBJECT
+	.retain	.data.sc1
+	.size	sc1, 2
+sc1:
+	.short	1
+	.section	.text.foo1,"ax"
+	.balign 2
+	.global	foo1
+	.type	foo1, STT_FUNC
+	.retain	.text.foo1
+foo1:
+	.size	foo1, .-foo1
+	.section	.text.foo2,"ax"
+	.balign 2
+	.global	foo2
+	.type	foo2, STT_FUNC
+foo2:
+	.size	foo2, .-foo2
+	.section	.bss.lsa,"aw"
+	.balign 2
+	.type	lsa.2, STT_OBJECT
+	.retain	.bss.lsa
+	.size	lsa.2, 2
+lsa.2:
+	.zero	2
+	.section	.bss.lsb,"aw"
+	.balign 2
+	.type	lsb.1, STT_OBJECT
+	.retain	.bss.lsb
+	.size	lsb.1, 2
+lsb.1:
+	.zero	2
+	.section	.data.lsc,"aw"
+	.balign 2
+	.type	lsc.0, STT_OBJECT
+	.retain	.data.lsc
+	.size	lsc.0, 2
+lsc.0:
+	.short	1
+.text
+	.balign 2
+	.global	main
+	.type	main, STT_FUNC
+main:
+	.size	main, .-main
diff --git a/gas/testsuite/gas/elf/retain2.d b/gas/testsuite/gas/elf/retain2.d
new file mode 100644
index 0000000000..55bcb87ab3
--- /dev/null
+++ b/gas/testsuite/gas/elf/retain2.d
@@ -0,0 +1,2 @@
+#name: SHF_GNU_RETAIN 2
+#error_output: retain2.l
diff --git a/gas/testsuite/gas/elf/retain2.l b/gas/testsuite/gas/elf/retain2.l
new file mode 100644
index 0000000000..3cf31b3e25
--- /dev/null
+++ b/gas/testsuite/gas/elf/retain2.l
@@ -0,0 +1,3 @@
+[^:]*: Assembler messages:
+[^:]*:1: Error: section '.data.foo' has not been declared
+[^:]*:7: Error: 'myvar' is not a section name, expected ".retain \[section name\]"
diff --git a/gas/testsuite/gas/elf/retain2.s b/gas/testsuite/gas/elf/retain2.s
new file mode 100644
index 0000000000..3522546886
--- /dev/null
+++ b/gas/testsuite/gas/elf/retain2.s
@@ -0,0 +1,7 @@
+.retain ".data.foo"
+.data
+.global myvar
+.type myvar, STT_OBJECT
+myvar:
+	.byte 2
+.retain "myvar"
diff --git a/gas/testsuite/gas/elf/retain3.d b/gas/testsuite/gas/elf/retain3.d
new file mode 100644
index 0000000000..78a7c26c47
--- /dev/null
+++ b/gas/testsuite/gas/elf/retain3.d
@@ -0,0 +1,24 @@
+#readelf: -S --wide
+#name: SHF_GNU_RETAIN 3 (use flags set on .section directive)
+
+#...
+  \[..\] .bss.a0[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+  \[..\] .bss.b0[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+  \[..\] .data.c0[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+  \[..\] .bss.sa0[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+  \[..\] .bss.sb0[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+  \[..\] .data.sc0[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+  \[..\] .text.foo0[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  AX.*
+  \[..\] .bss.a1[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .bss.b1[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .data.c1[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .bss.sa1[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .bss.sb1[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .data.sc1[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .text.foo1[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXR.*
+  \[..\] .text.foo2[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  AX.*
+#...
+  \[..\] .bss.lsa[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .bss.lsb[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+  \[..\] .data.lsc[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#pass
diff --git a/gas/testsuite/gas/elf/retain3.s b/gas/testsuite/gas/elf/retain3.s
new file mode 100644
index 0000000000..a7f050a8f5
--- /dev/null
+++ b/gas/testsuite/gas/elf/retain3.s
@@ -0,0 +1,121 @@
+.text
+	.global	a0
+	.section	.bss.a0,"aw"
+	.balign 2
+	.type	a0, STT_OBJECT
+	.size	a0, 2
+a0:
+	.zero	2
+	.global	b0
+	.section	.bss.b0,"aw"
+	.balign 2
+	.type	b0, STT_OBJECT
+	.size	b0, 2
+b0:
+	.zero	2
+	.global	c0
+	.section	.data.c0,"aw"
+	.balign 2
+	.type	c0, STT_OBJECT
+	.size	c0, 2
+c0:
+	.short	1
+	.section	.bss.sa0,"aw"
+	.balign 2
+	.type	sa0, STT_OBJECT
+	.size	sa0, 2
+sa0:
+	.zero	2
+	.section	.bss.sb0,"aw"
+	.balign 2
+	.type	sb0, STT_OBJECT
+	.size	sb0, 2
+sb0:
+	.zero	2
+	.section	.data.sc0,"aw"
+	.balign 2
+	.type	sc0, STT_OBJECT
+	.size	sc0, 2
+sc0:
+	.short	1
+	.section	.text.foo0,"ax"
+	.balign 2
+	.global	foo0
+	.type	foo0, STT_FUNC
+foo0:
+	.size	foo0, .-foo0
+	.global	a1
+	.section	.bss.a1,"awR"
+	.balign 2
+	.type	a1, STT_OBJECT
+	.size	a1, 2
+a1:
+	.zero	2
+	.global	b1
+	.section	.bss.b1,"awR"
+	.balign 2
+	.type	b1, STT_OBJECT
+	.size	b1, 2
+b1:
+	.zero	2
+	.global	c1
+	.section	.data.c1,"awR"
+	.balign 2
+	.type	c1, STT_OBJECT
+	.size	c1, 2
+c1:
+	.short	1
+	.section	.bss.sa1,"awR"
+	.balign 2
+	.type	sa1, STT_OBJECT
+	.size	sa1, 2
+sa1:
+	.zero	2
+	.section	.bss.sb1,"awR"
+	.balign 2
+	.type	sb1, STT_OBJECT
+	.size	sb1, 2
+sb1:
+	.zero	2
+	.section	.data.sc1,"awR"
+	.balign 2
+	.type	sc1, STT_OBJECT
+	.size	sc1, 2
+sc1:
+	.short	1
+	.section	.text.foo1,"axR"
+	.balign 2
+	.global	foo1
+	.type	foo1, STT_FUNC
+foo1:
+	.size	foo1, .-foo1
+	.section	.text.foo2,"ax"
+	.balign 2
+	.global	foo2
+	.type	foo2, STT_FUNC
+foo2:
+	.size	foo2, .-foo2
+	.section	.bss.lsa,"awR"
+	.balign 2
+	.type	lsa.2, STT_OBJECT
+	.size	lsa.2, 2
+lsa.2:
+	.zero	2
+	.section	.bss.lsb,"awR"
+	.balign 2
+	.type	lsb.1, STT_OBJECT
+	.size	lsb.1, 2
+lsb.1:
+	.zero	2
+	.section	.data.lsc,"awR"
+	.balign 2
+	.type	lsc.0, STT_OBJECT
+	.size	lsc.0, 2
+lsc.0:
+	.short	1
+.text
+	.balign 2
+	.global	main
+	.type	main, STT_FUNC
+main:
+	.size	main, .-main
diff --git a/gas/testsuite/gas/elf/section10.d b/gas/testsuite/gas/elf/section10.d
index 554a791f1d..ef91d7d086 100644
--- a/gas/testsuite/gas/elf/section10.d
+++ b/gas/testsuite/gas/elf/section10.d
@@ -18,7 +18,7 @@
 #...
 [ 	]*\[.*\][ 	]+sec3
 [ 	]*PROGBITS.*
-[ 	]*\[.*fefff030\]: MERGE, STRINGS,.* EXCLUDE, OS \(.*ef00000\), PROC \(.*[3467]0000000\), UNKNOWN \(0+0ff000\)
+[ 	]*\[.*fefff030\]: MERGE, STRINGS,.* EXCLUDE, OS \(.*ed00000\), PROC \(.*[3467]0000000\), UNKNOWN \(0+0ff000\)
 #...
 [ 	]*\[.*\][ 	]+sec4
 [ 	]*LOOS\+0x11[ 	].*
@@ -26,7 +26,7 @@
 #...
 [ 	]*\[.*\][ 	]+sec5
 [ 	]*LOUSER\+0x9[ 	].*
-[ 	]*\[.*feff0000\]:.* EXCLUDE, OS \(.*ef00000\), PROC \(.*[3467]0000000\), UNKNOWN \(.*f0000\)
+[ 	]*\[.*feff0000\]:.* EXCLUDE, OS \(.*ed00000\), PROC \(.*[3467]0000000\), UNKNOWN \(.*f0000\)
 [ 	]*\[.*\][ 	]+.data.foo
 [ 	]*LOUSER\+0x7f000000[ 	].*
 [ 	]*\[0+003\]: WRITE, ALLOC
diff --git a/include/elf/common.h b/include/elf/common.h
index 805058146a..364c58a7de 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -554,6 +554,7 @@
 /* #define SHF_MASKOS	0x0F000000    *//* OS-specific semantics */
 #define SHF_MASKOS	0x0FF00000	/* New value, Oct 4, 1999 Draft */
 #define SHF_GNU_BUILD_NOTE    (1 << 20)	/* Section contains GNU BUILD ATTRIBUTE notes.  */
+#define SHF_GNU_RETAIN	      (1 << 21)	/* Section should not be garbage collected by the linker.  */
 #define SHF_MASKPROC	0xF0000000	/* Processor-specific semantics */
 
 /* This used to be implemented as a processor specific section flag.
diff --git a/ld/testsuite/ld-elf/elf.exp b/ld/testsuite/ld-elf/elf.exp
index c0d67d80d2..04027fcbed 100644
--- a/ld/testsuite/ld-elf/elf.exp
+++ b/ld/testsuite/ld-elf/elf.exp
@@ -225,6 +225,20 @@ if [check_gc_sections_available] {
 	    {pr25490-6.s} \
 	    [list [list "readelf" {-SW} $pr25490_6_exp]] \
 	    "pr25490-6.exe"] \
+	[list "SHF_GNU_RETAIN 1" \
+	    "--gc-sections -e main --print-gc-sections" \
+	    "" \
+	    "" \
+	    {retain1.s} \
+	    {{ ld retain1.msg }} \
+	    "retain1.exe"] \
+	[list "SHF_GNU_RETAIN 3 (use flags set on .section directive)" \
+	    "--gc-sections -e main --print-gc-sections" \
+	    "" \
+	    "" \
+	    {retain3.s} \
+	    {{ ld retain3.msg }} \
+	    "retain3.exe"] \
 	]
 }
 
diff --git a/ld/testsuite/ld-elf/retain1.msg b/ld/testsuite/ld-elf/retain1.msg
new file mode 100644
index 0000000000..0e0f24ff10
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1.msg
@@ -0,0 +1,8 @@
+.*: removing unused section '.bss.a0' in file.*
+.*: removing unused section '.bss.b0' in file.*
+.*: removing unused section '.data.c0' in file.*
+.*: removing unused section '.bss.sa0' in file.*
+.*: removing unused section '.bss.sb0' in file.*
+.*: removing unused section '.data.sc0' in file.*
+.*: removing unused section '.text.foo0' in file.*
+.*: removing unused section '.text.foo2' in file.*
diff --git a/ld/testsuite/ld-elf/retain1.s b/ld/testsuite/ld-elf/retain1.s
new file mode 100644
index 0000000000..05b739ba64
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1.s
@@ -0,0 +1,134 @@
+.text
+	.global	a0
+	.section	.bss.a0,"aw"
+	.balign 2
+	.type	a0, STT_OBJECT
+	.size	a0, 2
+a0:
+	.zero	2
+	.global	b0
+	.section	.bss.b0,"aw"
+	.balign 2
+	.type	b0, STT_OBJECT
+	.size	b0, 2
+b0:
+	.zero	2
+	.global	c0
+	.section	.data.c0,"aw"
+	.balign 2
+	.type	c0, STT_OBJECT
+	.size	c0, 2
+c0:
+	.short	1
+	.section	.bss.sa0,"aw"
+	.balign 2
+	.type	sa0, STT_OBJECT
+	.size	sa0, 2
+sa0:
+	.zero	2
+	.section	.bss.sb0,"aw"
+	.balign 2
+	.type	sb0, STT_OBJECT
+	.size	sb0, 2
+sb0:
+	.zero	2
+	.section	.data.sc0,"aw"
+	.balign 2
+	.type	sc0, STT_OBJECT
+	.size	sc0, 2
+sc0:
+	.short	1
+	.section	.text.foo0,"ax"
+	.balign 2
+	.global	foo0
+	.type	foo0, STT_FUNC
+foo0:
+	.word 0
+	.size	foo0, .-foo0
+	.global	a1
+	.section	.bss.a1,"aw"
+	.balign 2
+	.type	a1, STT_OBJECT
+	.retain	.bss.a1
+	.size	a1, 2
+a1:
+	.zero	2
+	.global	b1
+	.section	.bss.b1,"aw"
+	.balign 2
+	.type	b1, STT_OBJECT
+	.retain	.bss.b1
+	.size	b1, 2
+b1:
+	.zero	2
+	.global	c1
+	.section	.data.c1,"aw"
+	.balign 2
+	.type	c1, STT_OBJECT
+	.retain	.data.c1
+	.size	c1, 2
+c1:
+	.short	1
+	.section	.bss.sa1,"aw"
+	.balign 2
+	.type	sa1, STT_OBJECT
+	.retain	.bss.sa1
+	.size	sa1, 2
+sa1:
+	.zero	2
+	.section	.bss.sb1,"aw"
+	.balign 2
+	.type	sb1, STT_OBJECT
+	.retain	.bss.sb1
+	.size	sb1, 2
+sb1:
+	.zero	2
+	.section	.data.sc1,"aw"
+	.balign 2
+	.type	sc1, STT_OBJECT
+	.retain	.data.sc1
+	.size	sc1, 2
+sc1:
+	.short	1
+	.section	.text.foo1,"ax"
+	.balign 2
+	.global	foo1
+	.type	foo1, STT_FUNC
+	.retain	.text.foo1
+foo1:
+	.word 0
+	.size	foo1, .-foo1
+	.section	.text.foo2,"ax"
+	.balign 2
+	.global	foo2
+	.type	foo2, STT_FUNC
+foo2:
+	.word 0
+	.size	foo2, .-foo2
+	.section	.bss.lsa,"aw"
+	.balign 2
+	.type	lsa.2, STT_OBJECT
+	.retain	.bss.lsa
+	.size	lsa.2, 2
+lsa.2:
+	.zero	2
+	.section	.bss.lsb,"aw"
+	.balign 2
+	.type	lsb.1, STT_OBJECT
+	.retain	.bss.lsb
+	.size	lsb.1, 2
+lsb.1:
+	.zero	2
+	.section	.data.lsc,"aw"
+	.balign 2
+	.type	lsc.0, STT_OBJECT
+	.retain	.data.lsc
+	.size	lsc.0, 2
+lsc.0:
+	.short	1
+.text
+	.balign 2
+	.global	main
+	.type	main, STT_FUNC
+main:
+	.size	main, .-main
diff --git a/ld/testsuite/ld-elf/retain2.d b/ld/testsuite/ld-elf/retain2.d
new file mode 100644
index 0000000000..207227928e
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.d
@@ -0,0 +1,5 @@
+# source: retain1.s
+# ld: -e main -Map=retain2.map --gc-sections --script=retain2.ld
+# map: retain2.map
+
+#pass
diff --git a/ld/testsuite/ld-elf/retain2.ld b/ld/testsuite/ld-elf/retain2.ld
new file mode 100644
index 0000000000..b8c9e6dfd1
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.ld
@@ -0,0 +1,7 @@
+SECTIONS
+{
+  /DISCARD/ :
+  {
+    *(".text.foo1")
+  }
+}
diff --git a/ld/testsuite/ld-elf/retain2.map b/ld/testsuite/ld-elf/retain2.map
new file mode 100644
index 0000000000..65b61f7488
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.map
@@ -0,0 +1,18 @@
+# Test that .text.foo1, which has the SHF_GNU_RETAIN flag, can still be
+# explicitly discarded from the output file.
+
+#...
+Discarded input sections
+
+ .data.*
+ .bss.*
+ .bss.a0.*
+ .bss.b0.*
+ .data.c0.*
+ .bss.sa0.*
+ .bss.sb0.*
+ .data.sc0.*
+ .text.foo0.*
+ .text.foo1.*
+ .text.foo2.*
+#pass
diff --git a/ld/testsuite/ld-elf/retain3.msg b/ld/testsuite/ld-elf/retain3.msg
new file mode 100644
index 0000000000..0e0f24ff10
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain3.msg
@@ -0,0 +1,8 @@
+.*: removing unused section '.bss.a0' in file.*
+.*: removing unused section '.bss.b0' in file.*
+.*: removing unused section '.data.c0' in file.*
+.*: removing unused section '.bss.sa0' in file.*
+.*: removing unused section '.bss.sb0' in file.*
+.*: removing unused section '.data.sc0' in file.*
+.*: removing unused section '.text.foo0' in file.*
+.*: removing unused section '.text.foo2' in file.*
diff --git a/ld/testsuite/ld-elf/retain3.s b/ld/testsuite/ld-elf/retain3.s
new file mode 100644
index 0000000000..f1ade91c87
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain3.s
@@ -0,0 +1,124 @@
+.text
+	.global	a0
+	.section	.bss.a0,"aw"
+	.balign 2
+	.type	a0, STT_OBJECT
+	.size	a0, 2
+a0:
+	.zero	2
+	.global	b0
+	.section	.bss.b0,"aw"
+	.balign 2
+	.type	b0, STT_OBJECT
+	.size	b0, 2
+b0:
+	.zero	2
+	.global	c0
+	.section	.data.c0,"aw"
+	.balign 2
+	.type	c0, STT_OBJECT
+	.size	c0, 2
+c0:
+	.short	1
+	.section	.bss.sa0,"aw"
+	.balign 2
+	.type	sa0, STT_OBJECT
+	.size	sa0, 2
+sa0:
+	.zero	2
+	.section	.bss.sb0,"aw"
+	.balign 2
+	.type	sb0, STT_OBJECT
+	.size	sb0, 2
+sb0:
+	.zero	2
+	.section	.data.sc0,"aw"
+	.balign 2
+	.type	sc0, STT_OBJECT
+	.size	sc0, 2
+sc0:
+	.short	1
+	.section	.text.foo0,"ax"
+	.balign 2
+	.global	foo0
+	.type	foo0, STT_FUNC
+foo0:
+	.word 0
+	.size	foo0, .-foo0
+	.global	a1
+	.section	.bss.a1,"awR"
+	.balign 2
+	.type	a1, STT_OBJECT
+	.size	a1, 2
+a1:
+	.zero	2
+	.global	b1
+	.section	.bss.b1,"awR"
+	.balign 2
+	.type	b1, STT_OBJECT
+	.size	b1, 2
+b1:
+	.zero	2
+	.global	c1
+	.section	.data.c1,"awR"
+	.balign 2
+	.type	c1, STT_OBJECT
+	.size	c1, 2
+c1:
+	.short	1
+	.section	.bss.sa1,"awR"
+	.balign 2
+	.type	sa1, STT_OBJECT
+	.size	sa1, 2
+sa1:
+	.zero	2
+	.section	.bss.sb1,"awR"
+	.balign 2
+	.type	sb1, STT_OBJECT
+	.size	sb1, 2
+sb1:
+	.zero	2
+	.section	.data.sc1,"awR"
+	.balign 2
+	.type	sc1, STT_OBJECT
+	.size	sc1, 2
+sc1:
+	.short	1
+	.section	.text.foo1,"axR"
+	.balign 2
+	.global	foo1
+	.type	foo1, STT_FUNC
+foo1:
+	.word 0
+	.size	foo1, .-foo1
+	.section	.text.foo2,"ax"
+	.balign 2
+	.global	foo2
+	.type	foo2, STT_FUNC
+foo2:
+	.word 0
+	.size	foo2, .-foo2
+	.section	.bss.lsa,"awR"
+	.balign 2
+	.type	lsa.2, STT_OBJECT
+	.size	lsa.2, 2
+lsa.2:
+	.zero	2
+	.section	.bss.lsb,"awR"
+	.balign 2
+	.type	lsb.1, STT_OBJECT
+	.size	lsb.1, 2
+lsb.1:
+	.zero	2
+	.section	.data.lsc,"awR"
+	.balign 2
+	.type	lsc.0, STT_OBJECT
+	.size	lsc.0, 2
+lsc.0:
+	.short	1
+.text
+	.balign 2
+	.global	main
+	.type	main, STT_FUNC
+main:
+	.size	main, .-main
-- 
2.28.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-15 12:06 [RFC] SHF_GNU_RETAIN ELF Section Flag Jozef Lawrynowicz
@ 2020-09-15 12:09 ` Florian Weimer
  2020-09-15 12:31   ` Jozef Lawrynowicz
  0 siblings, 1 reply; 20+ messages in thread
From: Florian Weimer @ 2020-09-15 12:09 UTC (permalink / raw)
  To: Jozef Lawrynowicz; +Cc: gnu-gabi

* Jozef Lawrynowicz:

> I'd like to propose a new ELF section flag, SHF_GNU_RETAIN, for addition
> to the GNU gABI.
>
> This flag instructs the linker to "retain" the section in the output
> file, even if garbage collection would remove it because it appears
> unused.

How does this flag interaction with libraries (.a files)?

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-15 12:09 ` Florian Weimer
@ 2020-09-15 12:31   ` Jozef Lawrynowicz
  2020-09-15 12:37     ` Florian Weimer
  0 siblings, 1 reply; 20+ messages in thread
From: Jozef Lawrynowicz @ 2020-09-15 12:31 UTC (permalink / raw)
  To: Florian Weimer; +Cc: gnu-gabi

On Tue, Sep 15, 2020 at 02:09:22PM +0200, Florian Weimer wrote:
> * Jozef Lawrynowicz:
> 
> > I'd like to propose a new ELF section flag, SHF_GNU_RETAIN, for addition
> > to the GNU gABI.
> >
> > This flag instructs the linker to "retain" the section in the output
> > file, even if garbage collection would remove it because it appears
> > unused.
> 
> How does this flag interaction with libraries (.a files)?

If a section in a library has SHF_GNU_RETAIN set, and that library gets
searched by the linker for some undefined symbol, then the
SHF_GNU_RETAIN section will also be pulled into the program, and
retained in the linked output file.

Thanks,
Jozef

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-15 12:31   ` Jozef Lawrynowicz
@ 2020-09-15 12:37     ` Florian Weimer
  2020-09-15 12:50       ` Carlos O'Donell
  0 siblings, 1 reply; 20+ messages in thread
From: Florian Weimer @ 2020-09-15 12:37 UTC (permalink / raw)
  To: Jozef Lawrynowicz; +Cc: gnu-gabi

* Jozef Lawrynowicz:

> On Tue, Sep 15, 2020 at 02:09:22PM +0200, Florian Weimer wrote:
>> * Jozef Lawrynowicz:
>> 
>> > I'd like to propose a new ELF section flag, SHF_GNU_RETAIN, for addition
>> > to the GNU gABI.
>> >
>> > This flag instructs the linker to "retain" the section in the output
>> > file, even if garbage collection would remove it because it appears
>> > unused.
>> 
>> How does this flag interaction with libraries (.a files)?
>
> If a section in a library has SHF_GNU_RETAIN set, and that library gets
> searched by the linker for some undefined symbol, then the
> SHF_GNU_RETAIN section will also be pulled into the program, and
> retained in the linked output file.

Sorry, that's not quite what I meant.  What happens if the .o file with
SHF_GNU_RETAIN in an .a library is not otherwise referenced and thus
never loaded by the link editor?  How would the link editor realize that
it is even there?

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-15 12:37     ` Florian Weimer
@ 2020-09-15 12:50       ` Carlos O'Donell
  2020-09-15 12:55         ` Florian Weimer
  0 siblings, 1 reply; 20+ messages in thread
From: Carlos O'Donell @ 2020-09-15 12:50 UTC (permalink / raw)
  To: Florian Weimer, Jozef Lawrynowicz; +Cc: gnu-gabi

On 9/15/20 8:37 AM, Florian Weimer via Gnu-gabi wrote:
> * Jozef Lawrynowicz:
> 
>> On Tue, Sep 15, 2020 at 02:09:22PM +0200, Florian Weimer wrote:
>>> * Jozef Lawrynowicz:
>>>
>>>> I'd like to propose a new ELF section flag, SHF_GNU_RETAIN, for addition
>>>> to the GNU gABI.
>>>>
>>>> This flag instructs the linker to "retain" the section in the output
>>>> file, even if garbage collection would remove it because it appears
>>>> unused.
>>>
>>> How does this flag interaction with libraries (.a files)?
>>
>> If a section in a library has SHF_GNU_RETAIN set, and that library gets
>> searched by the linker for some undefined symbol, then the
>> SHF_GNU_RETAIN section will also be pulled into the program, and
>> retained in the linked output file.
> 
> Sorry, that's not quite what I meant.  What happens if the .o file with
> SHF_GNU_RETAIN in an .a library is not otherwise referenced and thus
> never loaded by the link editor?  How would the link editor realize that
> it is even there?

Why would it be loaded?

Why does the link editor need to detect the presence of such a file?

There is certainly a semantic layering here that needs to be teased apart
and explained in more detail.

The archive operates on whole object files.

Therefore the rules say that the whole object file is included when a
dependency would require it to be included.

While SHF_GNU_RETAIN operates on sections. So when the linker is doing
garbage collection of the included section it would keep the section.

Thus the definition of SHF_GNU_RETAIN might be:

SHF_GNU_RETAIN

  When an object file containing such a marked section is included in
  the link, the section should not be garbage collected by the linker,
  even if it appears unused.

This would do away with the archive ambiguity.

Unless we want to argue what we mean by "included in the link?"

-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-15 12:50       ` Carlos O'Donell
@ 2020-09-15 12:55         ` Florian Weimer
  2020-09-15 13:29           ` Jozef Lawrynowicz
  0 siblings, 1 reply; 20+ messages in thread
From: Florian Weimer @ 2020-09-15 12:55 UTC (permalink / raw)
  To: Carlos O'Donell; +Cc: Jozef Lawrynowicz, gnu-gabi

* Carlos O'Donell:

> On 9/15/20 8:37 AM, Florian Weimer via Gnu-gabi wrote:
>> * Jozef Lawrynowicz:
>> 
>>> On Tue, Sep 15, 2020 at 02:09:22PM +0200, Florian Weimer wrote:
>>>> * Jozef Lawrynowicz:
>>>>
>>>>> I'd like to propose a new ELF section flag, SHF_GNU_RETAIN, for addition
>>>>> to the GNU gABI.
>>>>>
>>>>> This flag instructs the linker to "retain" the section in the output
>>>>> file, even if garbage collection would remove it because it appears
>>>>> unused.
>>>>
>>>> How does this flag interaction with libraries (.a files)?
>>>
>>> If a section in a library has SHF_GNU_RETAIN set, and that library gets
>>> searched by the linker for some undefined symbol, then the
>>> SHF_GNU_RETAIN section will also be pulled into the program, and
>>> retained in the linked output file.
>> 
>> Sorry, that's not quite what I meant.  What happens if the .o file with
>> SHF_GNU_RETAIN in an .a library is not otherwise referenced and thus
>> never loaded by the link editor?  How would the link editor realize that
>> it is even there?
>
> Why would it be loaded?

Hypothetically: Because the ranlib section tells the link editor to load
it (so more specification updates are needed).

> Why does the link editor need to detect the presence of such a file?

To make SHF_GNU_RETAIN work with libraries.

I think without that, the same effect can be had today with
SHF_GROUP/SHT_GROUP, perhaps with an assembler-only change to implement
the .retain pseudo.

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-15 12:55         ` Florian Weimer
@ 2020-09-15 13:29           ` Jozef Lawrynowicz
  2020-09-15 14:11             ` Carlos O'Donell
  0 siblings, 1 reply; 20+ messages in thread
From: Jozef Lawrynowicz @ 2020-09-15 13:29 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Carlos O'Donell, gnu-gabi

On Tue, Sep 15, 2020 at 02:55:05PM +0200, Florian Weimer wrote:
> * Carlos O'Donell:
> 
> > On 9/15/20 8:37 AM, Florian Weimer via Gnu-gabi wrote:
> >> * Jozef Lawrynowicz:
> >> 
> >>> On Tue, Sep 15, 2020 at 02:09:22PM +0200, Florian Weimer wrote:
> >>>> * Jozef Lawrynowicz:
> >>>>
> >>>>> I'd like to propose a new ELF section flag, SHF_GNU_RETAIN, for addition
> >>>>> to the GNU gABI.
> >>>>>
> >>>>> This flag instructs the linker to "retain" the section in the output
> >>>>> file, even if garbage collection would remove it because it appears
> >>>>> unused.
> >>>>
> >>>> How does this flag interaction with libraries (.a files)?
> >>>
> >>> If a section in a library has SHF_GNU_RETAIN set, and that library gets
> >>> searched by the linker for some undefined symbol, then the
> >>> SHF_GNU_RETAIN section will also be pulled into the program, and
> >>> retained in the linked output file.
> >> 
> >> Sorry, that's not quite what I meant.  What happens if the .o file with
> >> SHF_GNU_RETAIN in an .a library is not otherwise referenced and thus
> >> never loaded by the link editor?  How would the link editor realize that
> >> it is even there?
> >
> > Why would it be loaded?
> 
> Hypothetically: Because the ranlib section tells the link editor to load
> it (so more specification updates are needed).
> 

An SHF_GNU_RETAIN section would only be kept if it's containing object
was loaded in the first place, and the section was therefore considered for
garbage collection. So no, SHF_GNU_RETAIN is not intended to be used to
force inclusion of sections which the linker would not have otherwise
seen.
SHF_GNU_RETAIN can be thought of to essentially "turn off" garbage
collection for that section, rather than change the fundamental linking
behavior for that section or containing object.

Carlos' ammendment to the definition is accurate:

> SHF_GNU_RETAIN
>   When an object file containing such a marked section is included in
>   the link, the section should not be garbage collected by the linker,
>   even if it appears unused.

> > Why does the link editor need to detect the presence of such a file?
> 
> To make SHF_GNU_RETAIN work with libraries.
> 
> I think without that, the same effect can be had today with
> SHF_GROUP/SHT_GROUP, perhaps with an assembler-only change to implement
> the .retain pseudo.
> 

Perhaps, but without making any further extensions, wouldn't the
assembler need to know of a section which will definitiley be kept in
the output file? Only the linker can truly know this, by looking at the
entry point (when there is one).

A new bit in GRP_MASKOS could define that sections in a group with this
flag must always be kept, but that seems like a more round about way of
using a new section flag.

Thanks,
Jozef

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-15 13:29           ` Jozef Lawrynowicz
@ 2020-09-15 14:11             ` Carlos O'Donell
  2020-09-15 16:52               ` Jozef Lawrynowicz
  0 siblings, 1 reply; 20+ messages in thread
From: Carlos O'Donell @ 2020-09-15 14:11 UTC (permalink / raw)
  To: Jozef Lawrynowicz, Florian Weimer; +Cc: gnu-gabi

On 9/15/20 9:29 AM, Jozef Lawrynowicz wrote:
> On Tue, Sep 15, 2020 at 02:55:05PM +0200, Florian Weimer wrote:
>> * Carlos O'Donell:
>>
>>> On 9/15/20 8:37 AM, Florian Weimer via Gnu-gabi wrote:
>>>> * Jozef Lawrynowicz:
>>>>
>>>>> On Tue, Sep 15, 2020 at 02:09:22PM +0200, Florian Weimer wrote:
>>>>>> * Jozef Lawrynowicz:
>>>>>>
>>>>>>> I'd like to propose a new ELF section flag, SHF_GNU_RETAIN, for addition
>>>>>>> to the GNU gABI.
>>>>>>>
>>>>>>> This flag instructs the linker to "retain" the section in the output
>>>>>>> file, even if garbage collection would remove it because it appears
>>>>>>> unused.
>>>>>>
>>>>>> How does this flag interaction with libraries (.a files)?
>>>>>
>>>>> If a section in a library has SHF_GNU_RETAIN set, and that library gets
>>>>> searched by the linker for some undefined symbol, then the
>>>>> SHF_GNU_RETAIN section will also be pulled into the program, and
>>>>> retained in the linked output file.
>>>>
>>>> Sorry, that's not quite what I meant.  What happens if the .o file with
>>>> SHF_GNU_RETAIN in an .a library is not otherwise referenced and thus
>>>> never loaded by the link editor?  How would the link editor realize that
>>>> it is even there?
>>>
>>> Why would it be loaded?
>>
>> Hypothetically: Because the ranlib section tells the link editor to load
>> it (so more specification updates are needed).
>>
> 
> An SHF_GNU_RETAIN section would only be kept if it's containing object
> was loaded in the first place, and the section was therefore considered for
> garbage collection. So no, SHF_GNU_RETAIN is not intended to be used to
> force inclusion of sections which the linker would not have otherwise
> seen.
> SHF_GNU_RETAIN can be thought of to essentially "turn off" garbage
> collection for that section, rather than change the fundamental linking
> behavior for that section or containing object.
> 
> Carlos' ammendment to the definition is accurate:
> 
>> SHF_GNU_RETAIN
>>   When an object file containing such a marked section is included in
>>   the link, the section should not be garbage collected by the linker,
>>   even if it appears unused.
> 
>>> Why does the link editor need to detect the presence of such a file?
>>
>> To make SHF_GNU_RETAIN work with libraries.
>>
>> I think without that, the same effect can be had today with
>> SHF_GROUP/SHT_GROUP, perhaps with an assembler-only change to implement
>> the .retain pseudo.
>>
> 
> Perhaps, but without making any further extensions, wouldn't the
> assembler need to know of a section which will definitiley be kept in
> the output file? Only the linker can truly know this, by looking at the
> entry point (when there is one).
> 
> A new bit in GRP_MASKOS could define that sections in a group with this
> flag must always be kept, but that seems like a more round about way of
> using a new section flag.

Florian's point here, and let me reiterate it to see if I understood it,
is that SHF_GROUP / SHT_GROUP is the right mechanic here because:

(a) *Something* needs the section that would otherwise have been garbage
    collected.

(b) Expressing the "depends on" relationship could be achieved with
    a SHF_GROUP / SHT_GROUP and a new bit GRP_DEPENDS to indicate that
    a group of sections depend upon eachother (k-connected dependency).

Then the linker during garbage collection must either be able to discard
all sections in the group or none of them.

The underlying idea here is that SHF_GNU_RETAIN is really an expression
of "depended upon by something" with no further information about the
dependee or other related dependents.

How would "depends on" (GRP_DEPENDS) be expressed to the developer?

They would have to put code, and data, and other things into the this
new group to make a collection of things that depend upon eachother
in some non-"symbol dependency" way.

In the end you have to define the collection of things that would go
into the section group.

-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-15 14:11             ` Carlos O'Donell
@ 2020-09-15 16:52               ` Jozef Lawrynowicz
  2020-09-16 12:58                 ` Carlos O'Donell
  2020-09-16 13:11                 ` Florian Weimer
  0 siblings, 2 replies; 20+ messages in thread
From: Jozef Lawrynowicz @ 2020-09-15 16:52 UTC (permalink / raw)
  To: Carlos O'Donell; +Cc: Florian Weimer, gnu-gabi

On Tue, Sep 15, 2020 at 10:11:30AM -0400, Carlos O'Donell wrote:
> On 9/15/20 9:29 AM, Jozef Lawrynowicz wrote:
> > On Tue, Sep 15, 2020 at 02:55:05PM +0200, Florian Weimer wrote:
> >> * Carlos O'Donell:
> >>
> >>> On 9/15/20 8:37 AM, Florian Weimer via Gnu-gabi wrote:
> >>>> * Jozef Lawrynowicz:
> >>>>
> >>>>> On Tue, Sep 15, 2020 at 02:09:22PM +0200, Florian Weimer wrote:
> >>>>>> * Jozef Lawrynowicz:
> >>>>>>
> >>>>>>> I'd like to propose a new ELF section flag, SHF_GNU_RETAIN, for addition
> >>>>>>> to the GNU gABI.
> >>>>>>>
> >>>>>>> This flag instructs the linker to "retain" the section in the output
> >>>>>>> file, even if garbage collection would remove it because it appears
> >>>>>>> unused.
> >>>>>>
> >>>>>> How does this flag interaction with libraries (.a files)?
> >>>>>
> >>>>> If a section in a library has SHF_GNU_RETAIN set, and that library gets
> >>>>> searched by the linker for some undefined symbol, then the
> >>>>> SHF_GNU_RETAIN section will also be pulled into the program, and
> >>>>> retained in the linked output file.
> >>>>
> >>>> Sorry, that's not quite what I meant.  What happens if the .o file with
> >>>> SHF_GNU_RETAIN in an .a library is not otherwise referenced and thus
> >>>> never loaded by the link editor?  How would the link editor realize that
> >>>> it is even there?
> >>>
> >>> Why would it be loaded?
> >>
> >> Hypothetically: Because the ranlib section tells the link editor to load
> >> it (so more specification updates are needed).
> >>
> > 
> > An SHF_GNU_RETAIN section would only be kept if it's containing object
> > was loaded in the first place, and the section was therefore considered for
> > garbage collection. So no, SHF_GNU_RETAIN is not intended to be used to
> > force inclusion of sections which the linker would not have otherwise
> > seen.
> > SHF_GNU_RETAIN can be thought of to essentially "turn off" garbage
> > collection for that section, rather than change the fundamental linking
> > behavior for that section or containing object.
> > 
> > Carlos' ammendment to the definition is accurate:
> > 
> >> SHF_GNU_RETAIN
> >>   When an object file containing such a marked section is included in
> >>   the link, the section should not be garbage collected by the linker,
> >>   even if it appears unused.
> > 
> >>> Why does the link editor need to detect the presence of such a file?
> >>
> >> To make SHF_GNU_RETAIN work with libraries.
> >>
> >> I think without that, the same effect can be had today with
> >> SHF_GROUP/SHT_GROUP, perhaps with an assembler-only change to implement
> >> the .retain pseudo.
> >>
> > 
> > Perhaps, but without making any further extensions, wouldn't the
> > assembler need to know of a section which will definitiley be kept in
> > the output file? Only the linker can truly know this, by looking at the
> > entry point (when there is one).
> > 
> > A new bit in GRP_MASKOS could define that sections in a group with this
> > flag must always be kept, but that seems like a more round about way of
> > using a new section flag.
> 
> Florian's point here, and let me reiterate it to see if I understood it,
> is that SHF_GROUP / SHT_GROUP is the right mechanic here because:
> 
> (a) *Something* needs the section that would otherwise have been garbage
>     collected.
> 
> (b) Expressing the "depends on" relationship could be achieved with
>     a SHF_GROUP / SHT_GROUP and a new bit GRP_DEPENDS to indicate that
>     a group of sections depend upon eachother (k-connected dependency).
> 
> Then the linker during garbage collection must either be able to discard
> all sections in the group or none of them.
> 
> The underlying idea here is that SHF_GNU_RETAIN is really an expression
> of "depended upon by something" with no further information about the
> dependee or other related dependents.

I suppose the most compelling use cases for SHF_GNU_RETAIN are when the
dependency cannot be expressed with references to ELF sections. You
can't use SHF_GROUP because there is nothing to group the section with.

Consider when it is in fact the hardware that depends on the
SHF_GNU_RETAIN section:
- Interrupt vector table
- Bootloader code
- Memory mapped registers

These use cases perhaps make more sense when paired another flag I was
going to propose, which enables the setting of a section's VMA from the
source code.

So a user could set the value of a memory mapped register directly from
the source code, without any help from the linker script.

I realize these use cases are focussed towards embedded
microcontrollers, but there are many different processors, following
different processor-specific ABIs which fall under this category.
Maybe I should just work towards getting this functionality added for
ARM, and then whatever other targets want to use it can just piggyback
off that...

Thanks,
Jozef
> 
> How would "depends on" (GRP_DEPENDS) be expressed to the developer?
> 
> They would have to put code, and data, and other things into the this
> new group to make a collection of things that depend upon eachother
> in some non-"symbol dependency" way.
> 
> In the end you have to define the collection of things that would go
> into the section group.
> 
> -- 
> Cheers,
> Carlos.
> 

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-15 16:52               ` Jozef Lawrynowicz
@ 2020-09-16 12:58                 ` Carlos O'Donell
  2020-09-16 13:11                 ` Florian Weimer
  1 sibling, 0 replies; 20+ messages in thread
From: Carlos O'Donell @ 2020-09-16 12:58 UTC (permalink / raw)
  To: Jozef Lawrynowicz; +Cc: Florian Weimer, gnu-gabi

On 9/15/20 12:52 PM, Jozef Lawrynowicz wrote:
> I suppose the most compelling use cases for SHF_GNU_RETAIN are when the
> dependency cannot be expressed with references to ELF sections. You
> can't use SHF_GROUP because there is nothing to group the section with.

GRP_KEEP - Group of sections to always keep. Never discarded if included
           in the link.

The benefit is you can give them a logical group name e.g. "cpu_features"
and have more than one of them for accounting/documentation purposes.

You can implement a "KEEP" source markup based on gas' .section directive?

-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-15 16:52               ` Jozef Lawrynowicz
  2020-09-16 12:58                 ` Carlos O'Donell
@ 2020-09-16 13:11                 ` Florian Weimer
  2020-09-16 13:46                   ` Michael Matz
  2020-09-16 14:13                   ` Jozef Lawrynowicz
  1 sibling, 2 replies; 20+ messages in thread
From: Florian Weimer @ 2020-09-16 13:11 UTC (permalink / raw)
  To: Jozef Lawrynowicz; +Cc: Carlos O'Donell, gnu-gabi

* Jozef Lawrynowicz:

> I suppose the most compelling use cases for SHF_GNU_RETAIN are when the
> dependency cannot be expressed with references to ELF sections. You
> can't use SHF_GROUP because there is nothing to group the section with.

But if there is nothing to group the section with, why would the link
editor load the object?

That's the part I don't understand.

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-16 13:11                 ` Florian Weimer
@ 2020-09-16 13:46                   ` Michael Matz
  2020-09-18 12:07                     ` Florian Weimer
  2020-09-16 14:13                   ` Jozef Lawrynowicz
  1 sibling, 1 reply; 20+ messages in thread
From: Michael Matz @ 2020-09-16 13:46 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Jozef Lawrynowicz, gnu-gabi

Hello,

On Wed, 16 Sep 2020, Florian Weimer via Gnu-gabi wrote:

> * Jozef Lawrynowicz:
> 
> > I suppose the most compelling use cases for SHF_GNU_RETAIN are when the
> > dependency cannot be expressed with references to ELF sections. You
> > can't use SHF_GROUP because there is nothing to group the section with.
> 
> But if there is nothing to group the section with, why would the link
> editor load the object?
> 
> That's the part I don't understand.

Hmm?  By putting it on the command line:

% ld --gc-sections needed.o

should retain the RETAIN sections from needed.o, even if otherwise not 
seemingly referenced.

(I'm not sure if doing this via a group flag, or via a section flag would 
be better here.  In a way I find the section flag more appealing, it's the 
less complicated way to state "don't GC this section").


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-16 13:11                 ` Florian Weimer
  2020-09-16 13:46                   ` Michael Matz
@ 2020-09-16 14:13                   ` Jozef Lawrynowicz
  2020-09-18 10:00                     ` Jozef Lawrynowicz
  1 sibling, 1 reply; 20+ messages in thread
From: Jozef Lawrynowicz @ 2020-09-16 14:13 UTC (permalink / raw)
  To: Carlos O'Donell, Florian Weimer; +Cc: gnu-gabi

On Wed, Sep 16, 2020 at 08:58:41AM -0400, Carlos O'Donell wrote:
> On 9/15/20 12:52 PM, Jozef Lawrynowicz wrote:
> > I suppose the most compelling use cases for SHF_GNU_RETAIN are when the
> > dependency cannot be expressed with references to ELF sections. You
> > can't use SHF_GROUP because there is nothing to group the section with.
> 
> GRP_KEEP - Group of sections to always keep. Never discarded if included
>            in the link.
> 
> The benefit is you can give them a logical group name e.g. "cpu_features"
> and have more than one of them for accounting/documentation purposes.
> 
> You can implement a "KEEP" source markup based on gas' .section directive?

This is an interesting idea, but my initial thoughts are that it adds
some complexity that I don't think is required. There is already a lot
of information that can be gleaned from the section header, and the
symbols within that section.
Presumably the developer would have named the ISR/memory mapped
register symbol sensibly.

It doesn't seem very standard to make use of ELF constructs for
documenting why something has been done a certain way. You would just
use the construct to make something happen and have the "why" documented
elsewhere.

On Wed, Sep 16, 2020 at 03:11:20PM +0200, Florian Weimer wrote:
> * Jozef Lawrynowicz:
> 
> > I suppose the most compelling use cases for SHF_GNU_RETAIN are when the
> > dependency cannot be expressed with references to ELF sections. You
> > can't use SHF_GROUP because there is nothing to group the section with.
> 
> But if there is nothing to group the section with, why would the link
> editor load the object?
> 
> That's the part I don't understand.

Well this is intended for use by application code rather than libraries.
So all the objects that are part of the specific application and
explicitly passed to the link editor are going to be loaded.

(Please forgive any technical misuse of "application" above, but I hope
it is clear what I mean ;))

If a developer wants to use it in a library they'll have to take
precautions that it behaves as expected, by considering the object file
that the SHF_GNU_RETAIN section would reside in.

Thanks,
Jozef

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-16 14:13                   ` Jozef Lawrynowicz
@ 2020-09-18 10:00                     ` Jozef Lawrynowicz
  2020-09-18 18:11                       ` Florian Weimer
  0 siblings, 1 reply; 20+ messages in thread
From: Jozef Lawrynowicz @ 2020-09-18 10:00 UTC (permalink / raw)
  To: Carlos O'Donell, Florian Weimer; +Cc: gnu-gabi

Hi,

Where do we stand on this proposal?

Unless we are trying to be protective of the remaining operating
system-specific section flag bits, I don't really see any downside to
going the route of SHF_GNU_RETAIN. It is very simple, the linker
implementation requires only one additional line of code, and the
definition precisely describes how the section should be treated.

SHF_GNU_RETAIN
  The link editor should not garbage collect the section if it is
  unused.

I don't think the extra detail about whether the link editor sees the
section or not (in the case of libraries) is actually needed.

The definition explicitly states exactly what the linker should do - do
not garbage collect the section. It does not say "the linker should keep
the section if it is unused". Garbage collection implies the linker
"had" the section to begin with.

Perhaps the ambiguity in this area comes from the word "retain" in the
flag name, but again this has a precise definition. You cannot retain
something you don't have. To use the word "encounters" which is used
throughout the ELF spec:

If the linker doesn't encounter a section, it can't retain it. The
linker doesn't encounter any sections from libraries until it loads
an object file needed to resolve a symbol reference, so this behavior is
also precisely defined by the above definition.

If we really need to, we could add emphasize the "garbage collection"
aspect further:

SHF_GNU_RETAIN
  When performing garbage collection of unused sections, the link editor
  should not discard the section, even if it appears unused.

Are there any other objections to adding this to the GNU gABI?

Thanks,
Jozef

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-16 13:46                   ` Michael Matz
@ 2020-09-18 12:07                     ` Florian Weimer
  2020-09-18 12:22                       ` Jozef Lawrynowicz
  0 siblings, 1 reply; 20+ messages in thread
From: Florian Weimer @ 2020-09-18 12:07 UTC (permalink / raw)
  To: Michael Matz; +Cc: Jozef Lawrynowicz, gnu-gabi

* Michael Matz:

> Hello,
>
> On Wed, 16 Sep 2020, Florian Weimer via Gnu-gabi wrote:
>
>> * Jozef Lawrynowicz:
>> 
>> > I suppose the most compelling use cases for SHF_GNU_RETAIN are when the
>> > dependency cannot be expressed with references to ELF sections. You
>> > can't use SHF_GROUP because there is nothing to group the section with.
>> 
>> But if there is nothing to group the section with, why would the link
>> editor load the object?
>> 
>> That's the part I don't understand.
>
> Hmm?  By putting it on the command line:
>
> % ld --gc-sections needed.o
>
> should retain the RETAIN sections from needed.o, even if otherwise not 
> seemingly referenced.

But this use case already works today with an implicit linker script, I
think:

$ cat needed-impl.S
	.section .data.need-to-be-kept
symbol_to_be_retained:
	.long 0
$ cat needed.o
/* GNU ld script */
INPUT (needed-impl.o)
SECTIONS {
  .data : {
    KEEP (*(.data.need-to-be-kept))
  }
}
$ gcc -c needed-impl.S
$ gcc -shared -Wl,--gc-sections needed.o
$ $ readelf -s a.out | grep symbol_to_be_retained
    35: 0000000000004020     0 NOTYPE  LOCAL  DEFAULT   20 symbol_to_be_retained

(Some polishing by a linker expert is certainly needed, but I hope you
get the idea.)

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-18 12:07                     ` Florian Weimer
@ 2020-09-18 12:22                       ` Jozef Lawrynowicz
  2020-09-18 18:09                         ` Florian Weimer
  0 siblings, 1 reply; 20+ messages in thread
From: Jozef Lawrynowicz @ 2020-09-18 12:22 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Michael Matz, gnu-gabi

On Fri, Sep 18, 2020 at 02:07:42PM +0200, Florian Weimer wrote:
> * Michael Matz:
> 
> > Hello,
> >
> > On Wed, 16 Sep 2020, Florian Weimer via Gnu-gabi wrote:
> >
> >> * Jozef Lawrynowicz:
> >> 
> >> > I suppose the most compelling use cases for SHF_GNU_RETAIN are when the
> >> > dependency cannot be expressed with references to ELF sections. You
> >> > can't use SHF_GROUP because there is nothing to group the section with.
> >> 
> >> But if there is nothing to group the section with, why would the link
> >> editor load the object?
> >> 
> >> That's the part I don't understand.
> >
> > Hmm?  By putting it on the command line:
> >
> > % ld --gc-sections needed.o
> >
> > should retain the RETAIN sections from needed.o, even if otherwise not 
> > seemingly referenced.
> 
> But this use case already works today with an implicit linker script, I
> think:
> 
> $ cat needed-impl.S
> 	.section .data.need-to-be-kept
> symbol_to_be_retained:
> 	.long 0
> $ cat needed.o
> /* GNU ld script */
> INPUT (needed-impl.o)
> SECTIONS {
>   .data : {
>     KEEP (*(.data.need-to-be-kept))
>   }
> }
> $ gcc -c needed-impl.S
> $ gcc -shared -Wl,--gc-sections needed.o
> $ $ readelf -s a.out | grep symbol_to_be_retained
>     35: 0000000000004020     0 NOTYPE  LOCAL  DEFAULT   20 symbol_to_be_retained
> 
> (Some polishing by a linker expert is certainly needed, but I hope you
> get the idea.)

Yes, the use of the KEEP linker script directive is the current way to
protect a section from garbage collection, but in my original proposal
I outlined the benefits of using an attribute to save a section from
garbage collection. For the attribute to work, you need a section flag
to propagate the information to the linker.

On Tue, Sep 15, 2020 at 01:06:32PM +0100, Jozef Lawrynowicz wrote:

> ----------
> Motivation
> ----------
>
> ...snip...
>
> Currently, the KEEP linker script directive can be used to save a
> section from garbage collection. The new SHF_GNU_RETAIN flag has the
> same effect as KEEP, but since it is an ELF section flag, it means that
> this property can be propagated through the toolchain, from the
> compiler, through the assembler, to the linker.
>
> This enables a new "retain" attribute to be set on function and data
> declarations in the source code, which communicates the need to set the
> SHF_GNU_RETAIN flag on the containing section to downstream tools. In
> some situations, this has benefits over applying the KEEP directive in
> the linker script:
>
> - The requirement for protection from garbage collection might be
>   application-specific, so consolidating this requirement to be
>   contained entirely within the source code improves portability.
> - The user doesn't have to work out which section a function or data
>   object declaration will be placed in, and then set the KEEP directive
>   on that section. They can just set the attribute in the source code
>   and leave the rest for the toolchain to handle.
> - Generally avoiding linker script modifications can improve the user
>   experience, especially when the user is inexperienced with the linker
>   script format.  The boilerplate linker script code required for
>   standard application operation can make modifications error-prone and
>   have unintended side-effects.

So this new flag is not implementing a feature which is not currently
possible to do in any other way, but it opens up new ways to modify the
behavior of linker garbage collection, which can be used by developers
and writers of libraries/SDKs.

Thanks,
Jozef

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-18 12:22                       ` Jozef Lawrynowicz
@ 2020-09-18 18:09                         ` Florian Weimer
  0 siblings, 0 replies; 20+ messages in thread
From: Florian Weimer @ 2020-09-18 18:09 UTC (permalink / raw)
  To: Jozef Lawrynowicz; +Cc: Michael Matz, gnu-gabi

* Jozef Lawrynowicz:

> Yes, the use of the KEEP linker script directive is the current way to
> protect a section from garbage collection, but in my original proposal
> I outlined the benefits of using an attribute to save a section from
> garbage collection. For the attribute to work, you need a section flag
> to propagate the information to the linker.

I think you meant to write “an attribute to save a *symbol* from”.
I agree that this is a compelling case for a single-object-file
solution.

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-18 10:00                     ` Jozef Lawrynowicz
@ 2020-09-18 18:11                       ` Florian Weimer
  2020-09-21 12:42                         ` Michael Matz
  0 siblings, 1 reply; 20+ messages in thread
From: Florian Weimer @ 2020-09-18 18:11 UTC (permalink / raw)
  To: Jozef Lawrynowicz; +Cc: Carlos O'Donell, gnu-gabi

* Jozef Lawrynowicz:

> Unless we are trying to be protective of the remaining operating
> system-specific section flag bits, I don't really see any downside to
> going the route of SHF_GNU_RETAIN. It is very simple, the linker
> implementation requires only one additional line of code, and the
> definition precisely describes how the section should be treated.
>
> SHF_GNU_RETAIN
>   The link editor should not garbage collect the section if it is
>   unused.

I don't have any objections to this wording.

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-18 18:11                       ` Florian Weimer
@ 2020-09-21 12:42                         ` Michael Matz
  2020-09-21 18:53                           ` Jozef Lawrynowicz
  0 siblings, 1 reply; 20+ messages in thread
From: Michael Matz @ 2020-09-21 12:42 UTC (permalink / raw)
  To: Jozef Lawrynowicz; +Cc: gnu-gabi

Hello,

On Fri, 18 Sep 2020, Florian Weimer via Gnu-gabi wrote:

> * Jozef Lawrynowicz:
> 
> > Unless we are trying to be protective of the remaining operating
> > system-specific section flag bits, I don't really see any downside to
> > going the route of SHF_GNU_RETAIN. It is very simple, the linker
> > implementation requires only one additional line of code, and the
> > definition precisely describes how the section should be treated.
> >
> > SHF_GNU_RETAIN
> >   The link editor should not garbage collect the section if it is
> >   unused.
> 
> I don't have any objections to this wording.

Me neither.


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [RFC] SHF_GNU_RETAIN ELF Section Flag
  2020-09-21 12:42                         ` Michael Matz
@ 2020-09-21 18:53                           ` Jozef Lawrynowicz
  0 siblings, 0 replies; 20+ messages in thread
From: Jozef Lawrynowicz @ 2020-09-21 18:53 UTC (permalink / raw)
  To: Michael Matz, fweimer; +Cc: gnu-gabi

On Mon, Sep 21, 2020 at 12:42:55PM +0000, Michael Matz wrote:
> Hello,
> 
> On Fri, 18 Sep 2020, Florian Weimer via Gnu-gabi wrote:
> 
> > * Jozef Lawrynowicz:
> > 
> > > Unless we are trying to be protective of the remaining operating
> > > system-specific section flag bits, I don't really see any downside to
> > > going the route of SHF_GNU_RETAIN. It is very simple, the linker
> > > implementation requires only one additional line of code, and the
> > > definition precisely describes how the section should be treated.
> > >
> > > SHF_GNU_RETAIN
> > >   The link editor should not garbage collect the section if it is
> > >   unused.
> > 
> > I don't have any objections to this wording.
> 
> Me neither.

Thanks everyone for the feedback.

I'm finalizing the patch so the tests work for all Binutils ELF targets,
and will be posting to the Binutils ML soon, with the GCC patch to
follow once that is applied.

Regards,
Jozef

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2020-09-21 18:53 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-15 12:06 [RFC] SHF_GNU_RETAIN ELF Section Flag Jozef Lawrynowicz
2020-09-15 12:09 ` Florian Weimer
2020-09-15 12:31   ` Jozef Lawrynowicz
2020-09-15 12:37     ` Florian Weimer
2020-09-15 12:50       ` Carlos O'Donell
2020-09-15 12:55         ` Florian Weimer
2020-09-15 13:29           ` Jozef Lawrynowicz
2020-09-15 14:11             ` Carlos O'Donell
2020-09-15 16:52               ` Jozef Lawrynowicz
2020-09-16 12:58                 ` Carlos O'Donell
2020-09-16 13:11                 ` Florian Weimer
2020-09-16 13:46                   ` Michael Matz
2020-09-18 12:07                     ` Florian Weimer
2020-09-18 12:22                       ` Jozef Lawrynowicz
2020-09-18 18:09                         ` Florian Weimer
2020-09-16 14:13                   ` Jozef Lawrynowicz
2020-09-18 10:00                     ` Jozef Lawrynowicz
2020-09-18 18:11                       ` Florian Weimer
2020-09-21 12:42                         ` Michael Matz
2020-09-21 18:53                           ` Jozef Lawrynowicz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).