public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
@ 2020-09-28 13:26 Jozef Lawrynowicz
  2020-09-29  4:43 ` Fangrui Song
  2020-09-30 22:13 ` H.J. Lu
  0 siblings, 2 replies; 22+ messages in thread
From: Jozef Lawrynowicz @ 2020-09-28 13:26 UTC (permalink / raw)
  To: binutils

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

The attached patch is version 2 of the SHF_GNU_RETAIN patch that was
previously discussed here:
https://sourceware.org/pipermail/binutils/2020-September/113406.html

The following changes have been made:
- Removed the .retain directive
- The assembler will create different input sections for sections with
  the same name but SHF_GNU_RETAIN set/unset (thanks to H.J. for that).
  This means the linker will be able to do a better job garbage
  collecting input sections, as the "retain" attribute applied to a
  symbol declaration in the source code will not cause other parts of
  the program that are not required, but are in the same section, to be
  unnecessarily retained.
- Added GNU OSABI handling (also thanks to H.J.).

I've successfully regtested the patch for the Binutils, GAS and LD
testsuites for the following targets:

aarch64-elf arc-elf arm-eabi arm-elf avr-elf bfin-elf cr16-elf cris-elf
crx-elf csky-elf d10v-elf d30v-elf dlx-elf epiphany-elf fr30-elf frv-elf
ft32-elf h8300-elf hppa-elf i386-elf ip2k-elf iq2000-elf lm32-elf
m32c-elf m32r-elf m68hc11-elf m68hc12-elf m68k-elf mcore-elf mep-elf
metag-elf microblaze-elf mips-elf moxie-elf msp430-elf mt-elf nios2-elf
or1k-elf pj-elf ppc-elf pru-elf riscv-elf rl78-elf rx-elf s12z-elf
score-elf sh-elf sparc-elf spu-elf tic6x-elf tilegx-elf tilepro-elf
v850-elf visium-elf wasm32-elf xgate-elf xstormy16-elf xtensa-elf
z80-elf.

The new tests only run for the targets that use the GNU OSABI. From the
above list, arm-elf, hppa-elf, msp430-elf, visium-elf do not use the GNU
OSABI, so do not support SHF_GNU_RETAIN.

Ok to apply?

Thanks,
Jozef

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

From 137b4f3fa377d2eac520d6b9541512293992e200 Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@mittosystems.com>
Date: Tue, 22 Sep 2020 21:00:35 +0100
Subject: [PATCH] Support SHF_GNU_RETAIN ELF section flag

The GNU-specific SHF_GNU_RETAIN ELF section flag is defined as follows:

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

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

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

Note that there is not a direct mapping of SHF_GNU_RETAIN to the BFD
section flag SEC_KEEP. This would prevent the user being able to
explicitly remove an SHF_GNU_RETAIN section by placing it in /DISCARD/.

bfd/ChangeLog:

2020-09-28  H.J. Lu  <hongjiu.lu@intel.com>
	Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* elf-bfd.h (enum elf_gnu_osabi): Add elf_gnu_osabi_retain.
	(struct elf_obj_tdata): Increase has_gnu_osabi to 4 bits.
	* elf.c (_bfd_elf_make_section_from_shdr): Set elf_gnu_osabi_retain
	for SHF_GNU_RETAIN.
	* elflink.c (bfd_elf_gc_sections): gc_mark the section if
	SHF_GNU_RETAIN is set.

binutils/ChangeLog:

2020-09-28  Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* NEWS: Announce SHF_GNU_RETAIN.
	* readelf.c (get_elf_section_flags): Handle SHF_GNU_RETAIN.
	* testsuite/binutils-all/readelf.exp: Run new test.
	Don't run run_dump_test when there isn't an assembler available.
	* testsuite/lib/binutils-common.exp (supports_gnu_osabi): Adjust
	comment.
	* testsuite/binutils-all/retain1.d: New test.
	* testsuite/binutils-all/retain1.s: New test.

gas/ChangeLog:

2020-09-28  H.J. Lu  <hongjiu.lu@intel.com>
	Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* NEWS: Announce SHF_GNU_RETAIN.
	* config/obj-elf.c (SEC_ASSEMBLER_SHF_MASK): New.
	(get_section): Use SEC_ASSEMBLER_SHF_MASK.
	(obj_elf_change_section): Update struct member name.
	(obj_elf_parse_section_letters): Handle 'R' flag.
	(obj_elf_section): Set elf_gnu_osabi_retain
	for SHF_GNU_RETAIN.
	* config/obj-elf.h (struct elf_section_match): Adjust "info" member
	name to "sh_info".  Add "sh_flags" member.
	* doc/as.texi (Section): Document 'R' flag.
	* testsuite/gas/elf/elf.exp: Run new tests.
	* testsuite/gas/elf/section10.d: Adjust test.
	* testsuite/gas/elf/section22.d: New test.
	* testsuite/gas/elf/section22.s: New test.

include/ChangeLog:

2020-09-28  Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* elf/common.h (SHF_GNU_RETAIN): Define.

ld/ChangeLog:

2020-09-28  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
	H.J. Lu  <hongjiu.lu@intel.com>

	* NEWS: Announce SHF_GNU_RETAIN.
	* ld.texi (garbage collection): Document SHF_GNU_RETAIN.
	(Output Section Discarding): Likewise.
	* testsuite/ld-elf/elf.exp: Run new tests.
	* testsuite/ld-elf/retain1.msg: New test.
	* testsuite/ld-elf/retain1.s: New test.
	* testsuite/ld-elf/retain2.d: New test.
	* testsuite/ld-elf/retain2.ld: New test.
	* testsuite/ld-elf/retain2.map: New test.
	* testsuite/ld-elf/retain3.s: New test.
	* testsuite/ld-elf/retain4.s: New test.
	* testsuite/ld-elf/retain5lib.s: New test.
	* testsuite/ld-elf/retain5main.s: New test.
	* testsuite/ld-elf/retain6.msg: New test.
	* testsuite/ld-elf/retain6lib.s: New test.
	* testsuite/ld-elf/retain6main.s: New test.
	* testsuite/ld-elf/retain7.s: New test.
	* testsuite/ld-elf/retain7a.d: New test.
	* testsuite/ld-elf/retain7b.d: New test.
---
 bfd/elf-bfd.h                               |   9 +-
 bfd/elf.c                                   |   5 +-
 bfd/elflink.c                               |   3 +-
 binutils/NEWS                               |   4 +
 binutils/readelf.c                          |   4 +
 binutils/testsuite/binutils-all/readelf.exp |   6 +-
 binutils/testsuite/binutils-all/retain1.d   |  18 ++++
 binutils/testsuite/binutils-all/retain1.s   | 104 ++++++++++++++++++++
 binutils/testsuite/lib/binutils-common.exp  |   5 +-
 gas/NEWS                                    |   6 ++
 gas/config/obj-elf.c                        |  39 +++++---
 gas/config/obj-elf.h                        |   3 +-
 gas/doc/as.texi                             |   3 +
 gas/testsuite/gas/elf/elf.exp               |   1 +
 gas/testsuite/gas/elf/section10.d           |   4 +-
 gas/testsuite/gas/elf/section22.d           |  19 ++++
 gas/testsuite/gas/elf/section22.s           |  34 +++++++
 include/elf/common.h                        |   1 +
 ld/NEWS                                     |   4 +
 ld/ld.texi                                  |   8 ++
 ld/testsuite/ld-elf/elf.exp                 |  34 +++++++
 ld/testsuite/ld-elf/retain1.msg             |   9 ++
 ld/testsuite/ld-elf/retain1.s               | 104 ++++++++++++++++++++
 ld/testsuite/ld-elf/retain2.d               |   7 ++
 ld/testsuite/ld-elf/retain2.ld              |   7 ++
 ld/testsuite/ld-elf/retain2.map             |  32 ++++++
 ld/testsuite/ld-elf/retain3.s               |  19 ++++
 ld/testsuite/ld-elf/retain4.s               |  13 +++
 ld/testsuite/ld-elf/retain5lib.s            |   6 ++
 ld/testsuite/ld-elf/retain5main.s           |   5 +
 ld/testsuite/ld-elf/retain6.msg             |   1 +
 ld/testsuite/ld-elf/retain6lib.s            |  17 ++++
 ld/testsuite/ld-elf/retain6main.s           |  13 +++
 ld/testsuite/ld-elf/retain7.s               | 104 ++++++++++++++++++++
 ld/testsuite/ld-elf/retain7a.d              |  27 +++++
 ld/testsuite/ld-elf/retain7b.d              |  10 ++
 36 files changed, 666 insertions(+), 22 deletions(-)
 create mode 100644 binutils/testsuite/binutils-all/retain1.d
 create mode 100644 binutils/testsuite/binutils-all/retain1.s
 create mode 100644 gas/testsuite/gas/elf/section22.d
 create mode 100644 gas/testsuite/gas/elf/section22.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.s
 create mode 100644 ld/testsuite/ld-elf/retain4.s
 create mode 100644 ld/testsuite/ld-elf/retain5lib.s
 create mode 100644 ld/testsuite/ld-elf/retain5main.s
 create mode 100644 ld/testsuite/ld-elf/retain6.msg
 create mode 100644 ld/testsuite/ld-elf/retain6lib.s
 create mode 100644 ld/testsuite/ld-elf/retain6main.s
 create mode 100644 ld/testsuite/ld-elf/retain7.s
 create mode 100644 ld/testsuite/ld-elf/retain7a.d
 create mode 100644 ld/testsuite/ld-elf/retain7b.d

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 140a98594d..ffb75f7919 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1897,14 +1897,15 @@ struct output_elf_obj_tdata
   bfd_boolean flags_init;
 };
 
-/* Indicate if the bfd contains SHF_GNU_MBIND sections or symbols that
-   have the STT_GNU_IFUNC symbol type or STB_GNU_UNIQUE binding.  Used
-   to set the osabi field in the ELF header structure.  */
+/* Indicate if the bfd contains SHF_GNU_MBIND/SHF_GNU_RETAIN sections or
+   symbols that have the STT_GNU_IFUNC symbol type or STB_GNU_UNIQUE
+   binding.  Used to set the osabi field in the ELF header structure.  */
 enum elf_gnu_osabi
 {
   elf_gnu_osabi_mbind = 1 << 0,
   elf_gnu_osabi_ifunc = 1 << 1,
   elf_gnu_osabi_unique = 1 << 2,
+  elf_gnu_osabi_retain = 1 << 3,
 };
 
 typedef struct elf_section_list
@@ -2034,7 +2035,7 @@ struct elf_obj_tdata
   ENUM_BITFIELD (dynamic_lib_link_class) dyn_lib_class : 4;
 
   /* Whether the bfd uses OS specific bits that require ELFOSABI_GNU.  */
-  ENUM_BITFIELD (elf_gnu_osabi) has_gnu_osabi : 3;
+  ENUM_BITFIELD (elf_gnu_osabi) has_gnu_osabi : 4;
 
   /* Whether if the bfd contains the GNU_PROPERTY_NO_COPY_ON_PROTECTED
      property.  */
diff --git a/bfd/elf.c b/bfd/elf.c
index 00594020c9..85a889a97f 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1068,9 +1068,12 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
       /* FIXME: We should not recognize SHF_GNU_MBIND for ELFOSABI_NONE,
 	 but binutils as of 2019-07-23 did not set the EI_OSABI header
 	 byte.  */
-    case ELFOSABI_NONE:
     case ELFOSABI_GNU:
     case ELFOSABI_FREEBSD:
+      if ((hdr->sh_flags & SHF_GNU_RETAIN) != 0)
+	elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_retain;
+      /* Fall through */
+    case ELFOSABI_NONE:
       if ((hdr->sh_flags & SHF_GNU_MBIND) != 0)
 	elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_mbind;
       break;
diff --git a/bfd/elflink.c b/bfd/elflink.c
index b6937293e8..65b2d6b8aa 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -14102,7 +14102,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/NEWS b/binutils/NEWS
index c0dc73d7d8..6c7d3f3953 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -4,6 +4,10 @@
   symbol names.  In addition the --demangle=<style>, --no-demangle,
   --recurse-limit and --no-recurse-limit options are also now availale.
 
+* Add support for the SHF_GNU_RETAIN ELF section flag.
+  This flag specifies that the section should not be garbage collected by the
+  linker if it is unused.
+
 Changes in 2.35:
 
 * Changed readelf's display of symbol names when wide mode is not enabled.
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 9ba4e29a65..d136b750ed 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/binutils/testsuite/binutils-all/readelf.exp b/binutils/testsuite/binutils-all/readelf.exp
index 1fb36ae5c4..6dea09e305 100644
--- a/binutils/testsuite/binutils-all/readelf.exp
+++ b/binutils/testsuite/binutils-all/readelf.exp
@@ -364,8 +364,12 @@ readelf_wi_test
 readelf_compressed_wa_test
 
 readelf_dump_test
-run_dump_test "pr25543"
 
+# These dump tests require an assembler.
+if {[which $AS] != 0} then {
+    run_dump_test "pr25543"
+    run_dump_test "retain1"
+}
 
 # PR 13482 - Check for off-by-one errors when dumping .note sections.
 if {![binutils_assemble $srcdir/$subdir/version.s tmpdir/version.o]} then {
diff --git a/binutils/testsuite/binutils-all/retain1.d b/binutils/testsuite/binutils-all/retain1.d
new file mode 100644
index 0000000000..01cd32a475
--- /dev/null
+++ b/binutils/testsuite/binutils-all/retain1.d
@@ -0,0 +1,18 @@
+#source: retain1.s
+#readelf: -S --wide
+#name: readelf SHF_GNU_RETAIN
+#notarget: ![supports_gnu_osabi]
+
+#...
+  \[[ 0-9]+\] .bss.retain0.*WAR.*
+  \[[ 0-9]+\] .bss.retain1.*WAR.*
+  \[[ 0-9]+\] .data.retain2.*WAR.*
+  \[[ 0-9]+\] .bss.sretain0.*WAR.*
+  \[[ 0-9]+\] .bss.sretain1.*WAR.*
+  \[[ 0-9]+\] .data.sretain2.*WAR.*
+  \[[ 0-9]+\] .text.fnretain1.*AXR.*
+#...
+  \[[ 0-9]+\] .bss.lsretain0.*WAR.*
+  \[[ 0-9]+\] .bss.lsretain1.*WAR.*
+  \[[ 0-9]+\] .data.lsretain2.*WAR.*
+#pass
diff --git a/binutils/testsuite/binutils-all/retain1.s b/binutils/testsuite/binutils-all/retain1.s
new file mode 100644
index 0000000000..f7716faabe
--- /dev/null
+++ b/binutils/testsuite/binutils-all/retain1.s
@@ -0,0 +1,104 @@
+	.global	discard0
+	.section	.bss.discard0,"aw"
+	.type	discard0, %object
+discard0:
+	.zero	2
+
+	.global	discard1
+	.section	.bss.discard1,"aw"
+	.type	discard1, %object
+discard1:
+	.zero	2
+
+	.global	discard2
+	.section	.data.discard2,"aw"
+	.type	discard2, %object
+discard2:
+	.word	1
+
+	.section	.bss.sdiscard0,"aw"
+	.type	sdiscard0, %object
+sdiscard0:
+	.zero	2
+
+	.section	.bss.sdiscard1,"aw"
+	.type	sdiscard1, %object
+sdiscard1:
+	.zero	2
+
+	.section	.data.sdiscard2,"aw"
+	.type	sdiscard2, %object
+sdiscard2:
+	.word	1
+
+	.section	.text.fndiscard0,"ax"
+	.global	fndiscard0
+	.type	fndiscard0, %function
+fndiscard0:
+	.word 0
+
+	.global	retain0
+	.section	.bss.retain0,"awR"
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.global	retain1
+	.section	.bss.retain1,"awR"
+	.type	retain1, %object
+retain1:
+	.zero	2
+
+	.global	retain2
+	.section	.data.retain2,"awR"
+	.type	retain2, %object
+retain2:
+	.word	1
+
+	.section	.bss.sretain0,"awR"
+	.type	sretain0, %object
+sretain0:
+	.zero	2
+
+	.section	.bss.sretain1,"awR"
+	.type	sretain1, %object
+sretain1:
+	.zero	2
+
+	.section	.data.sretain2,"aRw"
+	.type	sretain2, %object
+sretain2:
+	.word	1
+
+	.section	.text.fnretain1,"Rax"
+	.global	fnretain1
+	.type	fnretain1, %function
+fnretain1:
+	.word	0
+
+	.section	.text.fndiscard2,"ax"
+	.global	fndiscard2
+	.type	fndiscard2, %function
+fndiscard2:
+	.word	0
+
+	.section	.bss.lsretain0,"awR"
+	.type	lsretain0.2, %object
+lsretain0.2:
+	.zero	2
+
+	.section	.bss.lsretain1,"aRw"
+	.type	lsretain1.1, %object
+lsretain1.1:
+	.zero	2
+
+	.section	.data.lsretain2,"aRw"
+	.type	lsretain2.0, %object
+lsretain2.0:
+	.word	1
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/binutils/testsuite/lib/binutils-common.exp b/binutils/testsuite/lib/binutils-common.exp
index b9a1e6e4bc..a43639bafb 100644
--- a/binutils/testsuite/lib/binutils-common.exp
+++ b/binutils/testsuite/lib/binutils-common.exp
@@ -195,13 +195,15 @@ proc match_target { target } {
 
 # True if the ELF target supports setting the ELF header OSABI field
 # to ELFOSABI_GNU or ELFOSABI_FREEBSD, a requirement for STT_GNU_IFUNC
-# symbol and SHF_GNU_MBIND section support.
+# symbol and SHF_GNU_MBIND or SHF_GNU_RETAIN section support.
 #
 # This generally depends on the target OS only, however there are a
 # number of exceptions for bare metal targets as follows.  The MSP430
 # and Visium targets set OSABI to ELFOSABI_STANDALONE.  Likewise
 # non-EABI ARM targets set OSABI to ELFOSABI_ARM
 #
+# Non-Linux HPPA defaults to ELFOSABI_HPUX.
+#
 # Note that some TI C6X targets use ELFOSABI_C6000_* but one doesn't,
 # so we don't try to sort out tic6x here.  (The effect is that linker
 # testcases will generally need to exclude tic6x or use a -m option.)
@@ -227,6 +229,7 @@ proc supports_gnu_osabi {} {
     }
     if { [istarget "arm*-*-*"]
 	 || [istarget "msp430-*-*"]
+	 || [istarget "hppa-unknown-elf"]
 	 || [istarget "visium-*-*"] } {
 	return 0
     }
diff --git a/gas/NEWS b/gas/NEWS
index 7ae58506ec..2056967a35 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -16,6 +16,12 @@
 
 * Configure with --enable-x86-used-note by default for Linux/x86.
 
+* Add support for the "R" flag in the .section directive.
+  This flag requires ELFOSABI_GNU or ELFOSABI_FREEBSD, and applies the
+  ELF SHF_GNU_RETAIN flag to the specified section.  This flag specifies
+  the section should not be garbage collected by the linker if it is
+  unused.
+
 Changes in 2.35:
 
 * X86 NaCl target support is removed.
diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index b1c99020a3..abc3c5d692 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -517,6 +517,10 @@ struct section_stack
 
 static struct section_stack *section_stack;
 
+/* Create unique input sections for sections with the same name, but different
+   values for the flags in this mask.  */
+#define SEC_ASSEMBLER_SHF_MASK SHF_GNU_RETAIN
+
 static bfd_boolean
 get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
 {
@@ -525,9 +529,12 @@ get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
   const char *group_name = elf_group_name (sec);
   const char *linked_to_symbol_name
     = sec->map_head.linked_to_symbol_name;
-  unsigned int info = elf_section_data (sec)->this_hdr.sh_info;
+  unsigned int sh_info = elf_section_data (sec)->this_hdr.sh_info;
+  bfd_vma sh_flags = (elf_section_data (sec)->this_hdr.sh_flags
+		      & SEC_ASSEMBLER_SHF_MASK);
 
-  return (info == match->info
+  return (sh_info == match->sh_info
+	  && sh_flags == match->sh_flags
 	  && ((bfd_section_flags (sec) & SEC_ASSEMBLER_SECTION_ID)
 	       == (match->flags & SEC_ASSEMBLER_SECTION_ID))
 	  && sec->section_id == match->section_id
@@ -736,7 +743,7 @@ obj_elf_change_section (const char *name,
 	type = bfd_elf_get_default_section_type (flags);
       elf_section_type (sec) = type;
       elf_section_flags (sec) = attr;
-      elf_section_data (sec)->this_hdr.sh_info = match_p->info;
+      elf_section_data (sec)->this_hdr.sh_info = match_p->sh_info;
 
       /* Prevent SEC_HAS_CONTENTS from being inadvertently set.  */
       if (type == SHT_NOBITS)
@@ -857,6 +864,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;
@@ -1250,18 +1260,21 @@ obj_elf_section (int push)
 	      if (ISDIGIT (* input_line_pointer))
 		{
 		  char *t = input_line_pointer;
-		  match.info = strtoul (input_line_pointer,
+		  match.sh_info = strtoul (input_line_pointer,
 					&input_line_pointer, 0);
-		  if (match.info == (unsigned int) -1)
+		  if (match.sh_info == (unsigned int) -1)
 		    {
 		      as_warn (_("unsupported mbind section info: %s"), t);
-		      match.info = 0;
+		      match.sh_info = 0;
 		    }
 		}
 	      else
 		input_line_pointer = save;
 	    }
 
+	  if ((gnu_attr & SHF_GNU_RETAIN) != 0)
+	    match.sh_flags |= SHF_GNU_RETAIN;
+
 	  if (*input_line_pointer == ',')
 	    {
 	      char *save = input_line_pointer;
@@ -1352,11 +1365,12 @@ obj_elf_section (int push)
   obj_elf_change_section (name, type, attr, entsize, &match, linkonce,
 			  push);
 
-  if ((gnu_attr & SHF_GNU_MBIND) != 0)
+  if ((gnu_attr & (SHF_GNU_MBIND | SHF_GNU_RETAIN)) != 0)
     {
       struct elf_backend_data *bed;
+      bfd_boolean mbind_p = (gnu_attr & SHF_GNU_MBIND) != 0;
 
-      if ((attr & SHF_ALLOC) == 0)
+      if (mbind_p && (attr & SHF_ALLOC) == 0)
 	as_bad (_("SHF_ALLOC isn't set for GNU_MBIND section: %s"), name);
 
       bed = (struct elf_backend_data *) get_elf_backend_data (stdoutput);
@@ -1364,9 +1378,12 @@ obj_elf_section (int push)
 	bed->elf_osabi = ELFOSABI_GNU;
       else if (bed->elf_osabi != ELFOSABI_GNU
 	       && bed->elf_osabi != ELFOSABI_FREEBSD)
-	as_bad (_("GNU_MBIND section is supported only by GNU "
-		  "and FreeBSD targets"));
-      elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_mbind;
+	as_bad (_("%s section is supported only by GNU and FreeBSD targets"),
+		mbind_p ? "GNU_MBIND" : "GNU_RETAIN");
+      if (mbind_p)
+	elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_mbind;
+      if ((gnu_attr & SHF_GNU_RETAIN) != 0)
+	elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_retain;
     }
   elf_section_flags (now_seg) |= gnu_attr;
 
diff --git a/gas/config/obj-elf.h b/gas/config/obj-elf.h
index b39a1a1ab6..6eb0a8ede4 100644
--- a/gas/config/obj-elf.h
+++ b/gas/config/obj-elf.h
@@ -106,8 +106,9 @@ struct elf_section_match
 {
   const char *group_name;
   const char *linked_to_symbol_name;
-  unsigned int info;
   unsigned int section_id;
+  unsigned int sh_info;		/* ELF section information.  */
+  bfd_vma sh_flags;		/* ELF section flags.  */
   flagword flags;
 };
 
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index b88c1f9997..31c32a8172 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -6559,6 +6559,9 @@ ignored.  (For compatibility with the ELF version)
 section is not readable (meaningful for PE targets)
 @item 0-9
 single-digit power-of-two section alignment (GNU extension)
+@item R
+retained section (apply SHF_GNU_RETAIN to prevent linker garbage
+collection, GNU ELF extension)
 @end table
 
 If no flags are specified, the default flags depend upon the section name.  If
diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
index 135ade24ec..a0ad2d8dd0 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -257,6 +257,7 @@ if { [is_elf_format] } then {
     run_dump_test "section19"
     run_dump_test "section20"
     run_dump_test "section21"
+    run_dump_test "section22"
     run_dump_test "dwarf2-1" $dump_opts
     run_dump_test "dwarf2-2" $dump_opts
     run_dump_test "dwarf2-3" $dump_opts
diff --git a/gas/testsuite/gas/elf/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/gas/testsuite/gas/elf/section22.d b/gas/testsuite/gas/elf/section22.d
new file mode 100644
index 0000000000..27d9127745
--- /dev/null
+++ b/gas/testsuite/gas/elf/section22.d
@@ -0,0 +1,19 @@
+#readelf: -h -S --wide
+#name: SHF_GNU_RETAIN sections 22
+#notarget: ![supports_gnu_osabi]
+
+#...
+ +OS/ABI: +UNIX - GNU
+#...
+  \[..\] .text[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  AX.*
+#...
+  \[..\] .data[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+#...
+  \[..\] .bss[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+#...
+  \[..\] .bss[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#...
+  \[..\] .data[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#...
+  \[..\] .text[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXR.*
+#pass
diff --git a/gas/testsuite/gas/elf/section22.s b/gas/testsuite/gas/elf/section22.s
new file mode 100644
index 0000000000..6e2b95c1e8
--- /dev/null
+++ b/gas/testsuite/gas/elf/section22.s
@@ -0,0 +1,34 @@
+	.section	.text,"ax",%progbits
+	.global	discard0
+	.type	discard0, %function
+discard0:
+	.word	0
+
+	.section	.data,"aw"
+	.global	discard1
+	.type	discard1, %object
+discard1:
+	.word	1
+
+	.section	.bss,"aw"
+	.global	discard2
+	.type	discard2, %object
+discard2:
+	.zero	2
+
+	.section	.bss,"awR",%nobits
+	.global	retain0
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.section	.data,"awR",%progbits
+	.type	retain1, %object
+retain1:
+	.word	1
+
+	.section	.text,"axR",%progbits
+	.global	retain2
+	.type	retain2, %function
+retain2:
+	.word	0
diff --git a/include/elf/common.h b/include/elf/common.h
index 571e21af29..c01e562c78 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/NEWS b/ld/NEWS
index e4ae43b257..72cdf0edd3 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -15,6 +15,10 @@
   unless you are working on a project that has its own analogue
   of symbol tables that are not reflected in the ELF symtabs.
 
+* Add support for the SHF_GNU_RETAIN ELF section flag.
+  This flag specifies that the section should not be garbage collected by the
+  linker if it is unused.
+
 Changes in 2.35:
 
 * X86 NaCl target support is removed.
diff --git a/ld/ld.texi b/ld/ld.texi
index ee592df6c2..526b642d78 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1787,6 +1787,10 @@ specified either by one of the options @samp{--entry},
 @samp{--undefined}, or @samp{--gc-keep-exported} or by a @code{ENTRY}
 command in the linker script.
 
+As a GNU extension, ELF input sections marked with the
+@code{SHF_GNU_RETAIN} flag will not be garbage collected if they are
+unused.
+
 @kindex --print-gc-sections
 @kindex --no-print-gc-sections
 @cindex garbage collection
@@ -5232,6 +5236,10 @@ The special output section name @samp{/DISCARD/} may be used to discard
 input sections.  Any input sections which are assigned to an output
 section named @samp{/DISCARD/} are not included in the output file.
 
+This can be used to discard input sections marked with the ELF flag
+@code{SHF_GNU_RETAIN}, which would otherwise have been saved from linker
+garbage collection when they are unused.
+
 Note, sections that match the @samp{/DISCARD/} output section will be
 discarded even if they are in an ELF section group which has other
 members which are not being discarded.  This is deliberate.
diff --git a/ld/testsuite/ld-elf/elf.exp b/ld/testsuite/ld-elf/elf.exp
index f2ff0397c7..bc27dbe3c5 100644
--- a/ld/testsuite/ld-elf/elf.exp
+++ b/ld/testsuite/ld-elf/elf.exp
@@ -228,6 +228,40 @@ if [check_gc_sections_available] {
 	]
 }
 
+# SHF_GNU_RETAIN requires the GNU OSABI.
+if { [check_gc_sections_available] && [supports_gnu_osabi] } {
+    run_ld_link_tests [list \
+	[list "SHF_GNU_RETAIN 1" \
+	    "--gc-sections -e _start --print-gc-sections" "" "" \
+	    {retain1.s} \
+	    {{ ld retain1.msg }} \
+	    "retain1.exe"] \
+	[list "SHF_GNU_RETAIN 3 (keep sections referenced by retained sections)" \
+	    "--gc-sections -e _start --print-gc-sections" "" "" \
+	    {retain3.s} {} \
+	    "retain3.exe"] \
+	[list "SHF_GNU_RETAIN 4 (keep orphaned sections when not discarding)" \
+	    "--gc-sections -e _start --print-gc-sections --orphan-handling=place" "" "" \
+	    {retain4.s} {} \
+	    "retain4.exe"] \
+	[list "Build libretain5.a" \
+	    "" "" "" \
+	    {retain5lib.s} {} "libretain5.a"] \
+	[list "SHF_GNU_RETAIN 5 (don't pull SHF_GNU_RETAIN section out of lib)" \
+	    "--gc-sections -e _start --print-gc-sections" "-Ltmpdir -lretain5" "" \
+	    {retain5main.s} {} \
+	    "retain5.exe"] \
+	[list "Build libretain6.a" \
+	    "" "" "" \
+	    {retain6lib.s} {} "libretain6.a"] \
+	[list "SHF_GNU_RETAIN 6 (pull section out of lib required by SHF_GNU_RETAIN section)" \
+	    "--gc-sections -e _start --print-gc-sections" "-Ltmpdir -lretain6" "" \
+	    {retain6main.s} \
+	    {{ ld retain6.msg }} \
+	    "retain6.exe"] \
+	]
+}
+
 set LDFLAGS $old_ldflags
 set ASFLAGS $old_asflags
 
diff --git a/ld/testsuite/ld-elf/retain1.msg b/ld/testsuite/ld-elf/retain1.msg
new file mode 100644
index 0000000000..9a265c980f
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1.msg
@@ -0,0 +1,9 @@
+.*: removing unused section '.bss.discard0' in file.*
+.*: removing unused section '.bss.discard1' in file.*
+.*: removing unused section '.data.discard2' in file.*
+.*: removing unused section '.bss.sdiscard0' in file.*
+.*: removing unused section '.bss.sdiscard1' in file.*
+.*: removing unused section '.data.sdiscard2' in file.*
+.*: removing unused section '.text.fndiscard0' in file.*
+.*: removing unused section '.text.fndiscard2' in file.*
+#pass
diff --git a/ld/testsuite/ld-elf/retain1.s b/ld/testsuite/ld-elf/retain1.s
new file mode 100644
index 0000000000..f7716faabe
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1.s
@@ -0,0 +1,104 @@
+	.global	discard0
+	.section	.bss.discard0,"aw"
+	.type	discard0, %object
+discard0:
+	.zero	2
+
+	.global	discard1
+	.section	.bss.discard1,"aw"
+	.type	discard1, %object
+discard1:
+	.zero	2
+
+	.global	discard2
+	.section	.data.discard2,"aw"
+	.type	discard2, %object
+discard2:
+	.word	1
+
+	.section	.bss.sdiscard0,"aw"
+	.type	sdiscard0, %object
+sdiscard0:
+	.zero	2
+
+	.section	.bss.sdiscard1,"aw"
+	.type	sdiscard1, %object
+sdiscard1:
+	.zero	2
+
+	.section	.data.sdiscard2,"aw"
+	.type	sdiscard2, %object
+sdiscard2:
+	.word	1
+
+	.section	.text.fndiscard0,"ax"
+	.global	fndiscard0
+	.type	fndiscard0, %function
+fndiscard0:
+	.word 0
+
+	.global	retain0
+	.section	.bss.retain0,"awR"
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.global	retain1
+	.section	.bss.retain1,"awR"
+	.type	retain1, %object
+retain1:
+	.zero	2
+
+	.global	retain2
+	.section	.data.retain2,"awR"
+	.type	retain2, %object
+retain2:
+	.word	1
+
+	.section	.bss.sretain0,"awR"
+	.type	sretain0, %object
+sretain0:
+	.zero	2
+
+	.section	.bss.sretain1,"awR"
+	.type	sretain1, %object
+sretain1:
+	.zero	2
+
+	.section	.data.sretain2,"aRw"
+	.type	sretain2, %object
+sretain2:
+	.word	1
+
+	.section	.text.fnretain1,"Rax"
+	.global	fnretain1
+	.type	fnretain1, %function
+fnretain1:
+	.word	0
+
+	.section	.text.fndiscard2,"ax"
+	.global	fndiscard2
+	.type	fndiscard2, %function
+fndiscard2:
+	.word	0
+
+	.section	.bss.lsretain0,"awR"
+	.type	lsretain0.2, %object
+lsretain0.2:
+	.zero	2
+
+	.section	.bss.lsretain1,"aRw"
+	.type	lsretain1.1, %object
+lsretain1.1:
+	.zero	2
+
+	.section	.data.lsretain2,"aRw"
+	.type	lsretain2.0, %object
+lsretain2.0:
+	.word	1
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain2.d b/ld/testsuite/ld-elf/retain2.d
new file mode 100644
index 0000000000..5d7204bb22
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.d
@@ -0,0 +1,7 @@
+# Test that sections marked with SHF_GNU_RETAIN can be removed by placing them
+# in /DISCARD/.
+#source: retain1.s
+#ld: -e _start -Map=retain2.map --gc-sections --script=retain2.ld
+#map: retain2.map
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi]
diff --git a/ld/testsuite/ld-elf/retain2.ld b/ld/testsuite/ld-elf/retain2.ld
new file mode 100644
index 0000000000..8ef982753c
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.ld
@@ -0,0 +1,7 @@
+SECTIONS
+{
+  /DISCARD/ :
+  {
+    *(.text.fnretain1)
+  }
+}
diff --git a/ld/testsuite/ld-elf/retain2.map b/ld/testsuite/ld-elf/retain2.map
new file mode 100644
index 0000000000..4028aa1f58
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.map
@@ -0,0 +1,32 @@
+# Test that .text.fnretain1, which has the SHF_GNU_RETAIN flag, can still be
+# explicitly discarded from the output file.
+
+#...
+Discarded input sections
+
+ .text.*
+#...
+ .data.*
+#...
+ .bss.*
+#...
+ .bss.discard0.*
+#...
+ .bss.discard1.*
+#...
+ .data.discard2.*
+#...
+ .bss.sdiscard0.*
+#...
+ .bss.sdiscard1.*
+#...
+ .data.sdiscard2.*
+#...
+ .text.fndiscard0.*
+#...
+ .text.fnretain1.*
+#...
+ .text.fndiscard2.*
+#...
+Memory Configuration
+#pass
diff --git a/ld/testsuite/ld-elf/retain3.s b/ld/testsuite/ld-elf/retain3.s
new file mode 100644
index 0000000000..ce315cbaa6
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain3.s
@@ -0,0 +1,19 @@
+/* The retention of bar should also prevent foo from being gc'ed, since bar
+   references foo.  */
+	.section	.text.foo,"ax"
+	.global	foo
+	.type	foo, %function
+foo:
+	.word 0
+
+	.section	.text.bar,"axR"
+	.global	bar
+	.type	bar, %function
+bar:
+	.long foo
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain4.s b/ld/testsuite/ld-elf/retain4.s
new file mode 100644
index 0000000000..83c4e738f4
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain4.s
@@ -0,0 +1,13 @@
+/* A section which doesn't match any linker script input section rules but
+   has SHF_GNU_RETAIN applied should not be garbage collected.  */
+	.section	.orphaned_section,"axR"
+	.global	foo
+	.type	foo, %function
+foo:
+	.word 0
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain5lib.s b/ld/testsuite/ld-elf/retain5lib.s
new file mode 100644
index 0000000000..4e83731719
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5lib.s
@@ -0,0 +1,6 @@
+/* The link will fail if foo is included because undefined_sym is not defined.  */
+	.section	.text.foo,"axR"
+	.global	foo
+	.type	foo, %function
+foo:
+	.long undefined_sym
diff --git a/ld/testsuite/ld-elf/retain5main.s b/ld/testsuite/ld-elf/retain5main.s
new file mode 100644
index 0000000000..89a7784d13
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5main.s
@@ -0,0 +1,5 @@
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain6.msg b/ld/testsuite/ld-elf/retain6.msg
new file mode 100644
index 0000000000..c21e3b9d75
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6.msg
@@ -0,0 +1 @@
+.*: removing unused section '.text.discard_from_lib' in file.*
diff --git a/ld/testsuite/ld-elf/retain6lib.s b/ld/testsuite/ld-elf/retain6lib.s
new file mode 100644
index 0000000000..a393dbac61
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6lib.s
@@ -0,0 +1,17 @@
+	.section	.text.bar,"ax"
+	.global	bar
+	.type	bar, %function
+bar:
+	.word 0
+
+	.section	.text.retain_from_lib,"axR"
+	.global	retain_from_lib
+	.type	retain_from_lib, %function
+retain_from_lib:
+	.word 0
+
+	.section	.text.discard_from_lib,"ax"
+	.global	discard_from_lib
+	.type	discard_from_lib, %function
+discard_from_lib:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain6main.s b/ld/testsuite/ld-elf/retain6main.s
new file mode 100644
index 0000000000..41cb3c26ca
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6main.s
@@ -0,0 +1,13 @@
+/* Undefined symbol reference in retained section .text.foo requires symbol
+   definition to be pulled out of library.  */
+	.section	.text.foo,"axR"
+	.global	foo
+	.type	foo, %function
+foo:
+	.long bar
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain7.s b/ld/testsuite/ld-elf/retain7.s
new file mode 100644
index 0000000000..2d80947fbd
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7.s
@@ -0,0 +1,104 @@
+	.section	.bss,"aw"
+	.global	discard0
+	.type	discard0, %object
+discard0:
+	.zero	2
+
+	.section	.bss,"aw"
+	.global	discard1
+	.type	discard1, %object
+discard1:
+	.zero	2
+
+	.section	.data,"aw"
+	.global	discard2
+	.type	discard2, %object
+discard2:
+	.word	1
+
+	.section	.bss,"aw"
+	.type	sdiscard0, %object
+sdiscard0:
+	.zero	2
+
+	.section	.bss,"aw"
+	.type	sdiscard1, %object
+sdiscard1:
+	.zero	2
+
+	.section	.data,"aw"
+	.type	sdiscard2, %object
+sdiscard2:
+	.word	1
+
+	.text
+	.global	fndiscard0
+	.type	fndiscard0, %function
+fndiscard0:
+	.word 0
+
+	.section	.bss,"awR"
+	.global	retain0
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.section	.bss,"awR"
+	.global	retain1
+	.type	retain1, %object
+retain1:
+	.zero	2
+
+	.section	.data,"awR"
+	.global	retain2
+	.type	retain2, %object
+retain2:
+	.word	1
+
+	.section	.bss,"awR"
+	.type	sretain0, %object
+sretain0:
+	.zero	2
+
+	.section	.bss,"awR"
+	.type	sretain1, %object
+sretain1:
+	.zero	2
+
+	.section	.data,"aRw"
+	.type	sretain2, %object
+sretain2:
+	.word	1
+
+	.section	.text,"Rax"
+	.global	fnretain1
+	.type	fnretain1, %function
+fnretain1:
+	.word	0
+
+	.section	.text,"ax"
+	.global	fndiscard2
+	.type	fndiscard2, %function
+fndiscard2:
+	.word	0
+
+	.section	.bss,"awR"
+	.type	lsretain0.2, %object
+lsretain0.2:
+	.zero	2
+
+	.section	.bss,"aRw"
+	.type	lsretain1.1, %object
+lsretain1.1:
+	.zero	2
+
+	.section	.data,"aRw"
+	.type	lsretain2.0, %object
+lsretain2.0:
+	.word	1
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain7a.d b/ld/testsuite/ld-elf/retain7a.d
new file mode 100644
index 0000000000..8e9643eadf
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7a.d
@@ -0,0 +1,27 @@
+#source: retain7.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . fnretain1
+#...
+[0-9a-f]+ . lsretain0.2
+#...
+[0-9a-f]+ . lsretain1.1
+#...
+[0-9a-f]+ . lsretain2.0
+#...
+[0-9a-f]+ . retain0
+#...
+[0-9a-f]+ . retain1
+#...
+[0-9a-f]+ . retain2
+#...
+[0-9a-f]+ . sretain0
+#...
+[0-9a-f]+ . sretain1
+#...
+[0-9a-f]+ . sretain2
+#pass
diff --git a/ld/testsuite/ld-elf/retain7b.d b/ld/testsuite/ld-elf/retain7b.d
new file mode 100644
index 0000000000..f6667611bf
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7b.d
@@ -0,0 +1,10 @@
+#source: retain7.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi]
+#nm: -n
+
+#failif
+#...
+[0-9a-f]+ . .*discard.*
+#...
-- 
2.28.0


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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-09-28 13:26 [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag Jozef Lawrynowicz
@ 2020-09-29  4:43 ` Fangrui Song
  2020-09-29 10:04   ` Jozef Lawrynowicz
  2020-09-30 22:13 ` H.J. Lu
  1 sibling, 1 reply; 22+ messages in thread
From: Fangrui Song @ 2020-09-29  4:43 UTC (permalink / raw)
  To: binutils

On 2020-09-28, Jozef Lawrynowicz wrote:
>The attached patch is version 2 of the SHF_GNU_RETAIN patch that was
>previously discussed here:
>https://sourceware.org/pipermail/binutils/2020-September/113406.html
>
>The following changes have been made:
>- Removed the .retain directive
>- The assembler will create different input sections for sections with
>  the same name but SHF_GNU_RETAIN set/unset (thanks to H.J. for that).
>  This means the linker will be able to do a better job garbage
>  collecting input sections, as the "retain" attribute applied to a
>  symbol declaration in the source code will not cause other parts of
>  the program that are not required, but are in the same section, to be
>  unnecessarily retained.
>- Added GNU OSABI handling (also thanks to H.J.).

My point from https://sourceware.org/pipermail/binutils/2020-September/113466.html stands.
Section flags are a bit cumbersome. If the following 

   // a.h
   __attribute__((section("sec")))
   inline void bar() { ... }
   // a.c
   #include "a.h"
   
   __attribute__((section("sec"), retain))
   void foo() {
   }

compiles to

   .section sec,"a",@progbits
   ...
   .section sec,"aR",@progbits
   ...

You will get a gas error for changing section flags
(https://sourceware.org/pipermail/binutils/2020-February/109945.html)

.reloc is really convenience in this case. You can add as many .reloc
directives as you like, each contributing one R_*_NONE to the object
file but zero cost to the linked image.

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-09-29  4:43 ` Fangrui Song
@ 2020-09-29 10:04   ` Jozef Lawrynowicz
  2020-09-29 19:38     ` Fangrui Song
  0 siblings, 1 reply; 22+ messages in thread
From: Jozef Lawrynowicz @ 2020-09-29 10:04 UTC (permalink / raw)
  To: Fangrui Song; +Cc: binutils

On Mon, Sep 28, 2020 at 09:43:53PM -0700, Fangrui Song wrote:
> On 2020-09-28, Jozef Lawrynowicz wrote:
> > The attached patch is version 2 of the SHF_GNU_RETAIN patch that was
> > previously discussed here:
> > https://sourceware.org/pipermail/binutils/2020-September/113406.html
> > 
> > The following changes have been made:
> > - Removed the .retain directive
> > - The assembler will create different input sections for sections with
> >  the same name but SHF_GNU_RETAIN set/unset (thanks to H.J. for that).
> >  This means the linker will be able to do a better job garbage
> >  collecting input sections, as the "retain" attribute applied to a
> >  symbol declaration in the source code will not cause other parts of
> >  the program that are not required, but are in the same section, to be
> >  unnecessarily retained.
> > - Added GNU OSABI handling (also thanks to H.J.).
> 
> My point from https://sourceware.org/pipermail/binutils/2020-September/113466.html stands.
> Section flags are a bit cumbersome. If the following
> 
>   // a.h
>   __attribute__((section("sec")))
>   inline void bar() { ... }
>   // a.c
>   #include "a.h"
>   __attribute__((section("sec"), retain))
>   void foo() {
>   }
> 
> compiles to
> 
>   .section sec,"a",@progbits
>   ...
>   .section sec,"aR",@progbits
>   ...
> 
> You will get a gas error for changing section flags
> (https://sourceware.org/pipermail/binutils/2020-February/109945.html)
> 

There is no error in this case.
The original patch handled it, and it has been further improved in v2.
There's even a testcase testing exactly the functionality you say is
broken.

  gas/testsuite/gas/elf/section22.s:
      .section	.text,"ax",%progbits
    ...
      .section	.data,"aw"
    ...
      .section	.bss,"aw"
    ...
      .section	.bss,"awR",%nobits
    ...
      .section	.data,"awR",%progbits
    ...
      .section	.text,"axR",%progbits

I already gave a detailed response to your reloc proposal:
https://sourceware.org/pipermail/binutils/2020-September/113450.html

Why don't you first answer my questions about why using relocs is a
really bad idea, is a hack, doesn't conceptually make any sense, and
will confuse users?

You never actually gave a reason that using relocs is better than
SHF_GNU_RETAIN, you seem to be pushing this alternative implementation just
because it is an alternative implementation. I don't count your
description of section flags as "cumbersome" as a reason we should
shelve this proposal.

> .reloc is really convenience in this case. You can add as many .reloc
> directives as you like, each contributing one R_*_NONE to the object
> file but zero cost to the linked image.

Are we really counting a section flag as adding "cost" to a linked
image?  Your method requires a "benign zero-sized section" (suggested in
your previous email), doesn't this also add cost? What about the cost of
having nonsensical relocs in object files?

If we are using the term "cost" loosely, and to further our own point,
then SHF_GNU_RETAIN actually has negative cost to the linked image. You
can have different input sections with the same name, but with different
states for SHF_GNU_RETAIN (set and unset), and so garbage collection
will operate with finer granularity, removing more unneeded parts of the
program compared to your reloc mechanism, which would keep the entire
section containing the symbol referenced by the reloc.

There are more logic holes in your other email that I didn't
respond to, but I've already spent a tonne of time trying to address
your points (most of which you ignored, so why did I bother?), so I
think I'm done debating this.
If other people back up your suggestion, and address my concerns, then
we can re-open this.

Thanks,
Jozef

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-09-29 10:04   ` Jozef Lawrynowicz
@ 2020-09-29 19:38     ` Fangrui Song
  2020-09-29 19:54       ` H.J. Lu
  2020-09-29 21:37       ` Jozef Lawrynowicz
  0 siblings, 2 replies; 22+ messages in thread
From: Fangrui Song @ 2020-09-29 19:38 UTC (permalink / raw)
  To: binutils, gnu-gabi

On 2020-09-29, Jozef Lawrynowicz wrote:
>There are more logic holes in your other email that I didn't
>respond to, but I've already spent a tonne of time trying to address
>your points (most of which you ignored, so why did I bother?), so I
>think I'm done debating this.
>If other people back up your suggestion, and address my concerns, then
>we can re-open this.

Hi Jozef, apologies if I did not respond to your previous replies in
time or if I acted as if I "blocked" your change. I maintain LLVM's
linker LLD and am also a contributor to its binary utilities
(llvm-readelf, llvm-objdump, ...). If GCC makes use of this flag for __attribute__((used)),
LLD and LLVM's binary utilities do need to support it.
So I want to participate in the design before we regret :)

I have studied linker GC quite a lot (contributed patches in LLD
and coordinated on the feature parity among the 3 linkers
(e.g. https://sourceware.org/pipermail/binutils/2020-August/112732.html)

LLD and GNU ld, LLVM's integrated assembler and GNU as have achieved consensus on many aspects
on SHF_LINK_ORDER and 'unique' linkage. Credits to H.J. for all the binutils side work.
)

I have asked a couple of toolchain folks. Many do share the same feeling
with me: an additional GC feature is useful but whether it should be
this exact form of a new flag we don't know.

Your patch also deprives an OS-specific flag from ELFOSABI_FREEBSD:)
I am not a committer of FreeBSD and I am surely not authoritative on
whether this is acceptable. But, FreeBSD does use the aforementioned
LLVM tools and I don't want to dirty the code base by adding
if (osabi == ELFOSABI_FREEBSD) do something. 

We have 8 bits in SHF_MASKOS: not too few, but also not too many.  We
should be prudent with new flags, especially if we already have a
facility for section retaining. There is a difference ".reloc requires a
known live section" which might cause friction but it has the advantage that it is
time-tested and has good toolchain support.


Opinions from others:

* Peter Smith mentioned that Arm's proprietary toolchain does something
   similar to SHF_GNU_RETAIN
   (https://www.keil.com/support/man/docs/armcc/armcc_chr1359124983230.htm)
   "I put __attribute__((used)) on my function and yet the tools removed
   it anyway."

   I have personally used a .reloc to retain
   __attribute__((used, section(".data.PERSIST_SIG"))) static char SigAfl[] = "##SIG_AFL_PERSISTENT##";

* James Henderson mentioned whether we can
   "create a new section type listing section indexes that should be
   retained"
   As a variant, we could use a SHT_GROUP with a new GRP_* bit.
   Anchor: [group] (see below)

> Do we want to make life easier for ourselves, or easier for our users?
>
> I get that ABI changes can be a bit disruptive, but this new flag in particular really isn't complicated anyway.

On 2020-09-29, Jozef Lawrynowicz wrote:
>On Mon, Sep 28, 2020 at 09:43:53PM -0700, Fangrui Song wrote:
>> On 2020-09-28, Jozef Lawrynowicz wrote:
>> > The attached patch is version 2 of the SHF_GNU_RETAIN patch that was
>> > previously discussed here:
>> > https://sourceware.org/pipermail/binutils/2020-September/113406.html
>> >
>> > The following changes have been made:
>> > - Removed the .retain directive
>> > - The assembler will create different input sections for sections with
>> >  the same name but SHF_GNU_RETAIN set/unset (thanks to H.J. for that).
>> >  This means the linker will be able to do a better job garbage
>> >  collecting input sections, as the "retain" attribute applied to a
>> >  symbol declaration in the source code will not cause other parts of
>> >  the program that are not required, but are in the same section, to be
>> >  unnecessarily retained.
>> > - Added GNU OSABI handling (also thanks to H.J.).
>>
>> My point from https://sourceware.org/pipermail/binutils/2020-September/113466.html stands.
>> Section flags are a bit cumbersome. If the following
>>
>>   // a.h
>>   __attribute__((section("sec")))
>>   inline void bar() { ... }
>>   // a.c
>>   #include "a.h"
>>   __attribute__((section("sec"), retain))
>>   void foo() {
>>   }
>>
>> compiles to
>>
>>   .section sec,"a",@progbits
>>   ...
>>   .section sec,"aR",@progbits
>>   ...
>>
>> You will get a gas error for changing section flags
>> (https://sourceware.org/pipermail/binutils/2020-February/109945.html)
>>
>
>There is no error in this case.
>The original patch handled it, and it has been further improved in v2.
>There's even a testcase testing exactly the functionality you say is
>broken.
>
>  gas/testsuite/gas/elf/section22.s:
>      .section	.bss,"aw"
>    ...
>      .section	.bss,"awR",%nobits
>
>I already gave a detailed response to your reloc proposal:
>https://sourceware.org/pipermail/binutils/2020-September/113450.html

Letting the following assembly creates two .bss sections adds an exception to
"gas: error for section type, attr, or entsize change"
(https://sourceware.org/pipermail/binutils/2020-February/109945.html)
for which I have achieved consensus with Alan Modra and some LLVM
toolchain folks. That is why I hope we could re-consider this design
choice.

.section	.bss,"aw"
.section	.bss,"awR",%nobits

See above for [group]: it is actually nice to use a group here, because
the quadruple
(section name, group name if "G", linked-to section if "o", unique id of
"unique") is the section key. The following creates a section different
from the default .bss:

   .section	.bss,"awG",%nobits,gc_root

>Why don't you first answer my questions about why using relocs is a
>really bad idea, is a hack, doesn't conceptually make any sense, and
>will confuse users?
>
>You never actually gave a reason that using relocs is better than
>SHF_GNU_RETAIN, you seem to be pushing this alternative implementation just
>because it is an alternative implementation. I don't count your
>description of section flags as "cumbersome" as a reason we should
>shelve this proposal.

I hope my previous paragraphs have answered this point.

>> .reloc is really convenience in this case. You can add as many .reloc
>> directives as you like, each contributing one R_*_NONE to the object
>> file but zero cost to the linked image.
>
>Are we really counting a section flag as adding "cost" to a linked
>image?  Your method requires a "benign zero-sized section" (suggested in
>your previous email), doesn't this also add cost? What about the cost of
>having nonsensical relocs in object files?
>
>If we are using the term "cost" loosely, and to further our own point,
>then SHF_GNU_RETAIN actually has negative cost to the linked image. You
>can have different input sections with the same name, but with different
>states for SHF_GNU_RETAIN (set and unset), and so garbage collection
>will operate with finer granularity, removing more unneeded parts of the
>program compared to your reloc mechanism, which would keep the entire
>section containing the symbol referenced by the reloc.
>
>Thanks,
>Jozef

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-09-29 19:38     ` Fangrui Song
@ 2020-09-29 19:54       ` H.J. Lu
  2020-09-29 21:37       ` Jozef Lawrynowicz
  1 sibling, 0 replies; 22+ messages in thread
From: H.J. Lu @ 2020-09-29 19:54 UTC (permalink / raw)
  To: Fangrui Song; +Cc: Binutils, GNU gABI gnu-gabi

On Tue, Sep 29, 2020 at 12:38 PM Fangrui Song <i@maskray.me> wrote:
>

> >>
> >>   // a.h
> >>   __attribute__((section("sec")))
> >>   inline void bar() { ... }
> >>   // a.c
> >>   #include "a.h"
> >>   __attribute__((section("sec"), retain))
> >>   void foo() {
> >>   }
> >>
> >> compiles to
> >>
> >>   .section sec,"a",@progbits
> >>   ...
> >>   .section sec,"aR",@progbits
> >>   ...
> >>
> >> You will get a gas error for changing section flags
> >> (https://sourceware.org/pipermail/binutils/2020-February/109945.html)
> >>
> >
> >There is no error in this case.
> >The original patch handled it, and it has been further improved in v2.
> >There's even a testcase testing exactly the functionality you say is
> >broken.
> >
> >  gas/testsuite/gas/elf/section22.s:
> >      .section .bss,"aw"
> >    ...
> >      .section .bss,"awR",%nobits
> >
> >I already gave a detailed response to your reloc proposal:
> >https://sourceware.org/pipermail/binutils/2020-September/113450.html
>
> Letting the following assembly creates two .bss sections adds an exception to
> "gas: error for section type, attr, or entsize change"
> (https://sourceware.org/pipermail/binutils/2020-February/109945.html)
> for which I have achieved consensus with Alan Modra and some LLVM
> toolchain folks. That is why I hope we could re-consider this design
> choice.
>
> .section        .bss,"aw"
> .section        .bss,"awR",%nobits
>

FWIW, GNU assembler has been able to create multiple sections with
the same section name for a while.  For SHF_GNU_RETAIN, we added

+/* Create unique input sections for sections with the same name, but different
+   values for the flags in this mask.  */
+#define SEC_ASSEMBLER_SHF_MASK SHF_GNU_RETAIN

to control when to create a new section with the same section name.
For other cases, no new section is created.

-- 
H.J.

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-09-29 19:38     ` Fangrui Song
  2020-09-29 19:54       ` H.J. Lu
@ 2020-09-29 21:37       ` Jozef Lawrynowicz
  2020-09-30  0:10         ` Roland McGrath
  1 sibling, 1 reply; 22+ messages in thread
From: Jozef Lawrynowicz @ 2020-09-29 21:37 UTC (permalink / raw)
  To: Fangrui Song; +Cc: binutils, gnu-gabi

On Tue, Sep 29, 2020 at 12:38:06PM -0700, Fangrui Song wrote:
> On 2020-09-29, Jozef Lawrynowicz wrote:
> > There are more logic holes in your other email that I didn't
> > respond to, but I've already spent a tonne of time trying to address
> > your points (most of which you ignored, so why did I bother?), so I
> > think I'm done debating this.
> > If other people back up your suggestion, and address my concerns, then
> > we can re-open this.
> 
> Hi Jozef, apologies if I did not respond to your previous replies in
> time or if I acted as if I "blocked" your change. I maintain LLVM's
> linker LLD and am also a contributor to its binary utilities
> (llvm-readelf, llvm-objdump, ...). If GCC makes use of this flag for __attribute__((used)),
> LLD and LLVM's binary utilities do need to support it.
> So I want to participate in the design before we regret :)
> 
> I have studied linker GC quite a lot (contributed patches in LLD
> and coordinated on the feature parity among the 3 linkers
> (e.g. https://sourceware.org/pipermail/binutils/2020-August/112732.html)
> 
> LLD and GNU ld, LLVM's integrated assembler and GNU as have achieved consensus on many aspects
> on SHF_LINK_ORDER and 'unique' linkage. Credits to H.J. for all the binutils side work.
> )
> 
> I have asked a couple of toolchain folks. Many do share the same feeling
> with me: an additional GC feature is useful but whether it should be
> this exact form of a new flag we don't know.

Hi Fangrui,

Thank you for providing some more information to backup your points, I
will address those below.

> 
> Your patch also deprives an OS-specific flag from ELFOSABI_FREEBSD:)
> I am not a committer of FreeBSD and I am surely not authoritative on
> whether this is acceptable. But, FreeBSD does use the aforementioned
> LLVM tools and I don't want to dirty the code base by adding
> if (osabi == ELFOSABI_FREEBSD) do something.

I don't have any insight into the ELFOSABI_FREEBSD change, H.J. added that
part, I assume it is very closely aligned with the "pure" GNU OSABI, so
any changes to one should be kept in parity with the other. However,
that is only my assumption.

> 
> We have 8 bits in SHF_MASKOS: not too few, but also not too many.  We
> should be prudent with new flags, especially if we already have a
> facility for section retaining. There is a difference ".reloc requires a
> known live section" which might cause friction but it has the advantage that it is
> time-tested and has good toolchain support.

Yes, this is something I considered, but there are 6 bits remaining to
be used, with SHF_GNU_RETAIN there will be 5 bits remaining.
Given how little movement there has been within the SHF_MAKOS bits for
the past 20 years, I don't think we need to be too protective of the
bits. They are there to be used after all, and IMO SHF_GNU_RETAIN is a
very well-defined use case to use one of those bits.

For the .reloc mechanism, in every object file with a retained section
you will need to have an empty input section which is guaranteed to be
kept by the linker. How is the compiler to know what that section is?

> 
> 
> Opinions from others:
> 
> * Peter Smith mentioned that Arm's proprietary toolchain does something
>   similar to SHF_GNU_RETAIN
>   (https://www.keil.com/support/man/docs/armcc/armcc_chr1359124983230.htm)
>   "I put __attribute__((used)) on my function and yet the tools removed
>   it anyway."
> 
> * James Henderson mentioned whether we can
>   "create a new section type listing section indexes that should be
>   retained"
>   As a variant, we could use a SHT_GROUP with a new GRP_* bit.
>   Anchor: [group] (see below)

Using groups was discussed on the GNU gABI thread, but I don't really
see the benefit of the added complication. Doesn't handling new section
group types still require significant coordination between all the
different compilers, assemblers and linkers?

Any attempt to reference a section which does not exist in the object
file, and is not guaranteed to be present in the linked output file, is
a non-starter in my opinion. We give users the freedom to do what they
want with linker scripts as ELF doesn't mandate any section must be
linked into the final executable. I think it's better to consolidate
the requirement to retain within the section that requires retaining,
instead of spreading the requirement to retain between ELF constructs
which have unrelated purposes, and need to be aligned between different
stages of the build process.

> 
> > Do we want to make life easier for ourselves, or easier for our users?
> > 
> > I get that ABI changes can be a bit disruptive, but this new flag in particular really isn't complicated anyway.
> 
> On 2020-09-29, Jozef Lawrynowicz wrote:
> > On Mon, Sep 28, 2020 at 09:43:53PM -0700, Fangrui Song wrote:
> > > On 2020-09-28, Jozef Lawrynowicz wrote:
> > > > The attached patch is version 2 of the SHF_GNU_RETAIN patch that was
> > > > previously discussed here:
> > > > https://sourceware.org/pipermail/binutils/2020-September/113406.html
> > > >
> > > > The following changes have been made:
> > > > - Removed the .retain directive
> > > > - The assembler will create different input sections for sections with
> > > >  the same name but SHF_GNU_RETAIN set/unset (thanks to H.J. for that).
> > > >  This means the linker will be able to do a better job garbage
> > > >  collecting input sections, as the "retain" attribute applied to a
> > > >  symbol declaration in the source code will not cause other parts of
> > > >  the program that are not required, but are in the same section, to be
> > > >  unnecessarily retained.
> > > > - Added GNU OSABI handling (also thanks to H.J.).
> > > 
> > > My point from https://sourceware.org/pipermail/binutils/2020-September/113466.html stands.
> > > Section flags are a bit cumbersome. If the following
> > > 
> > >   // a.h
> > >   __attribute__((section("sec")))
> > >   inline void bar() { ... }
> > >   // a.c
> > >   #include "a.h"
> > >   __attribute__((section("sec"), retain))
> > >   void foo() {
> > >   }
> > > 
> > > compiles to
> > > 
> > >   .section sec,"a",@progbits
> > >   ...
> > >   .section sec,"aR",@progbits
> > >   ...
> > > 
> > > You will get a gas error for changing section flags
> > > (https://sourceware.org/pipermail/binutils/2020-February/109945.html)
> > > 
> > 
> > There is no error in this case.
> > The original patch handled it, and it has been further improved in v2.
> > There's even a testcase testing exactly the functionality you say is
> > broken.
> > 
> >  gas/testsuite/gas/elf/section22.s:
> >      .section	.bss,"aw"
> >    ...
> >      .section	.bss,"awR",%nobits
> > 
> > I already gave a detailed response to your reloc proposal:
> > https://sourceware.org/pipermail/binutils/2020-September/113450.html
> 
> Letting the following assembly creates two .bss sections adds an exception to
> "gas: error for section type, attr, or entsize change"
> (https://sourceware.org/pipermail/binutils/2020-February/109945.html)
> for which I have achieved consensus with Alan Modra and some LLVM
> toolchain folks. That is why I hope we could re-consider this design
> choice.
> 
> .section	.bss,"aw"
> .section	.bss,"awR",%nobits

I agree that this could be considered slightly inelegant, but much less
so than having .reloc directives in arbitrary empty sections.
Once someone understands what the "R" flag does, it should be clear why
we want to create a separate input section for it.

If we really want, we can force the compiler to create unique section
names for declarations which have the "retain" attribute applied. I
assume most of the time, users will want this fine section
granularity. I would prefer not to go that route and leave it to the
users to specify unique sections if they want.

> 
> See above for [group]: it is actually nice to use a group here, because
> the quadruple
> (section name, group name if "G", linked-to section if "o", unique id of
> "unique") is the section key. The following creates a section different
> from the default .bss:
> 
>   .section	.bss,"awG",%nobits,gc_root

I don't think it is really very important whether input sections with
the same name are unique or not within an object file. ELF doesn't care
about this. You can have sections with the same name and same flags in
different object files and the linker can just deal with it. It's the
same situation if you have two sections from the same object file which
have the same name.

Within an object file, you'll end up with all the non-SHF_GNU_RETAIN
sections with the same name being merged together by the assembler, and
all those with SHF_GNU_RETAIN being merged. I don't think there is any
benefit to keep SHF_GNU_RETAIN sections with the same name as separate
input sections in the object file.

Thanks,
Jozef

> 
> > Why don't you first answer my questions about why using relocs is a
> > really bad idea, is a hack, doesn't conceptually make any sense, and
> > will confuse users?
> > 
> > You never actually gave a reason that using relocs is better than
> > SHF_GNU_RETAIN, you seem to be pushing this alternative implementation just
> > because it is an alternative implementation. I don't count your
> > description of section flags as "cumbersome" as a reason we should
> > shelve this proposal.
> 
> I hope my previous paragraphs have answered this point.
> 
> > > .reloc is really convenience in this case. You can add as many .reloc
> > > directives as you like, each contributing one R_*_NONE to the object
> > > file but zero cost to the linked image.
> > 
> > Are we really counting a section flag as adding "cost" to a linked
> > image?  Your method requires a "benign zero-sized section" (suggested in
> > your previous email), doesn't this also add cost? What about the cost of
> > having nonsensical relocs in object files?
> > 
> > If we are using the term "cost" loosely, and to further our own point,
> > then SHF_GNU_RETAIN actually has negative cost to the linked image. You
> > can have different input sections with the same name, but with different
> > states for SHF_GNU_RETAIN (set and unset), and so garbage collection
> > will operate with finer granularity, removing more unneeded parts of the
> > program compared to your reloc mechanism, which would keep the entire
> > section containing the symbol referenced by the reloc.
> > 
> > Thanks,
> > Jozef

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-09-29 21:37       ` Jozef Lawrynowicz
@ 2020-09-30  0:10         ` Roland McGrath
  2020-09-30 10:18           ` Jozef Lawrynowicz
  2020-09-30 14:13           ` Michael Matz
  0 siblings, 2 replies; 22+ messages in thread
From: Roland McGrath @ 2020-09-30  0:10 UTC (permalink / raw)
  To: Fangrui Song, Binutils Development, gnu-gabi

Since group semantics mean that if any section in a group is retained the
whole group must be retained, it seems to me that making the feature a
group flag rather than a section flag makes sense. I don't think it really
has any downside. It's a little bit more structure to generate a group but
everything already knows how to do it so that should be no problem.  While
it is true that multiple sections with the same name and different
attributes should already be fine, the place where multiple different
sections of the same name are usually seen today is when each different
section reusing a name is in a different group from the other sections with
the same name.

On Tue, Sep 29, 2020 at 2:37 PM Jozef Lawrynowicz <jozef.l@mittosystems.com>
wrote:

> On Tue, Sep 29, 2020 at 12:38:06PM -0700, Fangrui Song wrote:
> > On 2020-09-29, Jozef Lawrynowicz wrote:
> > > There are more logic holes in your other email that I didn't
> > > respond to, but I've already spent a tonne of time trying to address
> > > your points (most of which you ignored, so why did I bother?), so I
> > > think I'm done debating this.
> > > If other people back up your suggestion, and address my concerns, then
> > > we can re-open this.
> >
> > Hi Jozef, apologies if I did not respond to your previous replies in
> > time or if I acted as if I "blocked" your change. I maintain LLVM's
> > linker LLD and am also a contributor to its binary utilities
> > (llvm-readelf, llvm-objdump, ...). If GCC makes use of this flag for
> __attribute__((used)),
> > LLD and LLVM's binary utilities do need to support it.
> > So I want to participate in the design before we regret :)
> >
> > I have studied linker GC quite a lot (contributed patches in LLD
> > and coordinated on the feature parity among the 3 linkers
> > (e.g. https://sourceware.org/pipermail/binutils/2020-August/112732.html)
> >
> > LLD and GNU ld, LLVM's integrated assembler and GNU as have achieved
> consensus on many aspects
> > on SHF_LINK_ORDER and 'unique' linkage. Credits to H.J. for all the
> binutils side work.
> > )
> >
> > I have asked a couple of toolchain folks. Many do share the same feeling
> > with me: an additional GC feature is useful but whether it should be
> > this exact form of a new flag we don't know.
>
> Hi Fangrui,
>
> Thank you for providing some more information to backup your points, I
> will address those below.
>
> >
> > Your patch also deprives an OS-specific flag from ELFOSABI_FREEBSD:)
> > I am not a committer of FreeBSD and I am surely not authoritative on
> > whether this is acceptable. But, FreeBSD does use the aforementioned
> > LLVM tools and I don't want to dirty the code base by adding
> > if (osabi == ELFOSABI_FREEBSD) do something.
>
> I don't have any insight into the ELFOSABI_FREEBSD change, H.J. added that
> part, I assume it is very closely aligned with the "pure" GNU OSABI, so
> any changes to one should be kept in parity with the other. However,
> that is only my assumption.
>
> >
> > We have 8 bits in SHF_MASKOS: not too few, but also not too many.  We
> > should be prudent with new flags, especially if we already have a
> > facility for section retaining. There is a difference ".reloc requires a
> > known live section" which might cause friction but it has the advantage
> that it is
> > time-tested and has good toolchain support.
>
> Yes, this is something I considered, but there are 6 bits remaining to
> be used, with SHF_GNU_RETAIN there will be 5 bits remaining.
> Given how little movement there has been within the SHF_MAKOS bits for
> the past 20 years, I don't think we need to be too protective of the
> bits. They are there to be used after all, and IMO SHF_GNU_RETAIN is a
> very well-defined use case to use one of those bits.
>
> For the .reloc mechanism, in every object file with a retained section
> you will need to have an empty input section which is guaranteed to be
> kept by the linker. How is the compiler to know what that section is?
>
> >
> >
> > Opinions from others:
> >
> > * Peter Smith mentioned that Arm's proprietary toolchain does something
> >   similar to SHF_GNU_RETAIN
> >   (
> https://www.keil.com/support/man/docs/armcc/armcc_chr1359124983230.htm)
> >   "I put __attribute__((used)) on my function and yet the tools removed
> >   it anyway."
> >
> > * James Henderson mentioned whether we can
> >   "create a new section type listing section indexes that should be
> >   retained"
> >   As a variant, we could use a SHT_GROUP with a new GRP_* bit.
> >   Anchor: [group] (see below)
>
> Using groups was discussed on the GNU gABI thread, but I don't really
> see the benefit of the added complication. Doesn't handling new section
> group types still require significant coordination between all the
> different compilers, assemblers and linkers?
>
> Any attempt to reference a section which does not exist in the object
> file, and is not guaranteed to be present in the linked output file, is
> a non-starter in my opinion. We give users the freedom to do what they
> want with linker scripts as ELF doesn't mandate any section must be
> linked into the final executable. I think it's better to consolidate
> the requirement to retain within the section that requires retaining,
> instead of spreading the requirement to retain between ELF constructs
> which have unrelated purposes, and need to be aligned between different
> stages of the build process.
>
> >
> > > Do we want to make life easier for ourselves, or easier for our users?
> > >
> > > I get that ABI changes can be a bit disruptive, but this new flag in
> particular really isn't complicated anyway.
> >
> > On 2020-09-29, Jozef Lawrynowicz wrote:
> > > On Mon, Sep 28, 2020 at 09:43:53PM -0700, Fangrui Song wrote:
> > > > On 2020-09-28, Jozef Lawrynowicz wrote:
> > > > > The attached patch is version 2 of the SHF_GNU_RETAIN patch that
> was
> > > > > previously discussed here:
> > > > >
> https://sourceware.org/pipermail/binutils/2020-September/113406.html
> > > > >
> > > > > The following changes have been made:
> > > > > - Removed the .retain directive
> > > > > - The assembler will create different input sections for sections
> with
> > > > >  the same name but SHF_GNU_RETAIN set/unset (thanks to H.J. for
> that).
> > > > >  This means the linker will be able to do a better job garbage
> > > > >  collecting input sections, as the "retain" attribute applied to a
> > > > >  symbol declaration in the source code will not cause other parts
> of
> > > > >  the program that are not required, but are in the same section,
> to be
> > > > >  unnecessarily retained.
> > > > > - Added GNU OSABI handling (also thanks to H.J.).
> > > >
> > > > My point from
> https://sourceware.org/pipermail/binutils/2020-September/113466.html
> stands.
> > > > Section flags are a bit cumbersome. If the following
> > > >
> > > >   // a.h
> > > >   __attribute__((section("sec")))
> > > >   inline void bar() { ... }
> > > >   // a.c
> > > >   #include "a.h"
> > > >   __attribute__((section("sec"), retain))
> > > >   void foo() {
> > > >   }
> > > >
> > > > compiles to
> > > >
> > > >   .section sec,"a",@progbits
> > > >   ...
> > > >   .section sec,"aR",@progbits
> > > >   ...
> > > >
> > > > You will get a gas error for changing section flags
> > > > (https://sourceware.org/pipermail/binutils/2020-February/109945.html
> )
> > > >
> > >
> > > There is no error in this case.
> > > The original patch handled it, and it has been further improved in v2.
> > > There's even a testcase testing exactly the functionality you say is
> > > broken.
> > >
> > >  gas/testsuite/gas/elf/section22.s:
> > >      .section       .bss,"aw"
> > >    ...
> > >      .section       .bss,"awR",%nobits
> > >
> > > I already gave a detailed response to your reloc proposal:
> > > https://sourceware.org/pipermail/binutils/2020-September/113450.html
> >
> > Letting the following assembly creates two .bss sections adds an
> exception to
> > "gas: error for section type, attr, or entsize change"
> > (https://sourceware.org/pipermail/binutils/2020-February/109945.html)
> > for which I have achieved consensus with Alan Modra and some LLVM
> > toolchain folks. That is why I hope we could re-consider this design
> > choice.
> >
> > .section      .bss,"aw"
> > .section      .bss,"awR",%nobits
>
> I agree that this could be considered slightly inelegant, but much less
> so than having .reloc directives in arbitrary empty sections.
> Once someone understands what the "R" flag does, it should be clear why
> we want to create a separate input section for it.
>
> If we really want, we can force the compiler to create unique section
> names for declarations which have the "retain" attribute applied. I
> assume most of the time, users will want this fine section
> granularity. I would prefer not to go that route and leave it to the
> users to specify unique sections if they want.
>
> >
> > See above for [group]: it is actually nice to use a group here, because
> > the quadruple
> > (section name, group name if "G", linked-to section if "o", unique id of
> > "unique") is the section key. The following creates a section different
> > from the default .bss:
> >
> >   .section    .bss,"awG",%nobits,gc_root
>
> I don't think it is really very important whether input sections with
> the same name are unique or not within an object file. ELF doesn't care
> about this. You can have sections with the same name and same flags in
> different object files and the linker can just deal with it. It's the
> same situation if you have two sections from the same object file which
> have the same name.
>
> Within an object file, you'll end up with all the non-SHF_GNU_RETAIN
> sections with the same name being merged together by the assembler, and
> all those with SHF_GNU_RETAIN being merged. I don't think there is any
> benefit to keep SHF_GNU_RETAIN sections with the same name as separate
> input sections in the object file.
>
> Thanks,
> Jozef
>
> >
> > > Why don't you first answer my questions about why using relocs is a
> > > really bad idea, is a hack, doesn't conceptually make any sense, and
> > > will confuse users?
> > >
> > > You never actually gave a reason that using relocs is better than
> > > SHF_GNU_RETAIN, you seem to be pushing this alternative implementation
> just
> > > because it is an alternative implementation. I don't count your
> > > description of section flags as "cumbersome" as a reason we should
> > > shelve this proposal.
> >
> > I hope my previous paragraphs have answered this point.
> >
> > > > .reloc is really convenience in this case. You can add as many .reloc
> > > > directives as you like, each contributing one R_*_NONE to the object
> > > > file but zero cost to the linked image.
> > >
> > > Are we really counting a section flag as adding "cost" to a linked
> > > image?  Your method requires a "benign zero-sized section" (suggested
> in
> > > your previous email), doesn't this also add cost? What about the cost
> of
> > > having nonsensical relocs in object files?
> > >
> > > If we are using the term "cost" loosely, and to further our own point,
> > > then SHF_GNU_RETAIN actually has negative cost to the linked image. You
> > > can have different input sections with the same name, but with
> different
> > > states for SHF_GNU_RETAIN (set and unset), and so garbage collection
> > > will operate with finer granularity, removing more unneeded parts of
> the
> > > program compared to your reloc mechanism, which would keep the entire
> > > section containing the symbol referenced by the reloc.
> > >
> > > Thanks,
> > > Jozef
>
>

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-09-30  0:10         ` Roland McGrath
@ 2020-09-30 10:18           ` Jozef Lawrynowicz
  2020-09-30 14:01             ` H.J. Lu
  2020-10-01 19:22             ` Fangrui Song
  2020-09-30 14:13           ` Michael Matz
  1 sibling, 2 replies; 22+ messages in thread
From: Jozef Lawrynowicz @ 2020-09-30 10:18 UTC (permalink / raw)
  To: Roland McGrath; +Cc: Fangrui Song, Binutils Development, gnu-gabi

On Tue, Sep 29, 2020 at 05:10:09PM -0700, Roland McGrath wrote:
> Since group semantics mean that if any section in a group is retained the
> whole group must be retained, it seems to me that making the feature a
> group flag rather than a section flag makes sense. I don't think it really
> has any downside. It's a little bit more structure to generate a group but
> everything already knows how to do it so that should be no problem.  While
> it is true that multiple sections with the same name and different
> attributes should already be fine, the place where multiple different
> sections of the same name are usually seen today is when each different
> section reusing a name is in a different group from the other sections with
> the same name.
> 

Let's assume:
  GRP_RETAIN
    Sections in a group with this flag set should always be included in
    the linked object, even if they appear unused.

One issue I have with the group method is conceptual; groups are supposed
to be used to group related sections. They are related because of their
meaning from the application perspective, not because of their metadata
(i.e. sections to be retained are related by their metadata because they
all should be retained). 

Just because groups have a side effect that can be leveraged to
get a section to be retained in the final link, why does that mean we
need to leverage that property when it it's not actually the simplest or
most obvious way to implement the new behavior?

SHF_GNU_RETAIN describes in the simplest possible way that the section
should be retained in the final link, without relying on other
constructs.

Just because groups are discarded or retained as a group, doesn't mean
we need to leverage groups to try and implement retention or discarding
functionality.

Why wasn't SHF_EXCLUDE implemented as a group flag? After all, groups
are included or excluded from the link together.
  GRP_EXCLUDE
    Sections in a group with GRP_EXCLUDE set should be discarded from
    the link.

I mean, you could kind of use groups for anything when you decide
grouping sections by metadata is OK.
Why define SHT_NOBITS when you can create:
  GRP_NOBITS
    Sections in this group occupy no space in the file. They must have
    type SHT_PROGBITS.

Retention of a section is a property of the section. We are misusing ELF
constructs by using groups to indicate an arbitrary section needs to be
retained.

Another issue (if more is needed) is about how to name the groups.
* If it is mandated that GRP_RETAIN groups have the same name e.g.
  "grp_retain", that means you can't put a section you want to
  retain in a different logical group that makes sense from the
  application perspective. So the other sections you would want to put
  in a group with the retained section need to all be put in a bundle
  with all the other GRP_RETAIN sections.
* If GRP_RETAIN groups can have any name, so you can have multiple
  GRP_RETAIN groups, how does the compiler decide how to name the
  groups? It seems like it would be a mess. "grp_retain0", "grp_retain2"
  ... "grp_retain10" from one object file, "grp_retain0"...
  "grp_retain5" from another. Extra processing in the
  linker to clean up these group names and keep them unique would be
  required when performing a relocatable link.

As a general point, what if I decide that there's enough pressure from
the anti-SHF_GNU_RETAIN side that I change the implementation to use
groups. But then those who already backed the flag prefer that method
over using groups think the implementation should not have been changed.

I feel like we already got enough backing for SHF_GNU_RETAIN between the
GNU gABI and Binutils discussions. I understand, and welcome, more
feedback, but I haven't been convinced any other method is obviously
better than SHF_GNU_RETAIN, so why change it?

I'm not saying it's possible to quantify which mechanism for "retain" is
best, but SHF_GNU_RETAIN is the simplest, most obvious, and easiest to
understand. Surely that gives it top marks?

I'm also yet to hear one convincing reason why SHF_GNU_RETAIN is bad.
As far as I can tell, the main argument against it stems from the fact
that you can have two input sections with the same name but different
SHF_GNU_RETAIN flag states. Not only is this a non-issue, groups have
exactly the same problem!

It would be great if a global maintainer to chime in on whether the
attached patch is acceptable, because otherwise we are going to go back
and forth forever.

Thanks,
Jozef

> On Tue, Sep 29, 2020 at 2:37 PM Jozef Lawrynowicz <jozef.l@mittosystems.com>
> wrote:
> 
> > On Tue, Sep 29, 2020 at 12:38:06PM -0700, Fangrui Song wrote:
> > > On 2020-09-29, Jozef Lawrynowicz wrote:
> > > > There are more logic holes in your other email that I didn't
> > > > respond to, but I've already spent a tonne of time trying to address
> > > > your points (most of which you ignored, so why did I bother?), so I
> > > > think I'm done debating this.
> > > > If other people back up your suggestion, and address my concerns, then
> > > > we can re-open this.
> > >
> > > Hi Jozef, apologies if I did not respond to your previous replies in
> > > time or if I acted as if I "blocked" your change. I maintain LLVM's
> > > linker LLD and am also a contributor to its binary utilities
> > > (llvm-readelf, llvm-objdump, ...). If GCC makes use of this flag for
> > __attribute__((used)),
> > > LLD and LLVM's binary utilities do need to support it.
> > > So I want to participate in the design before we regret :)
> > >
> > > I have studied linker GC quite a lot (contributed patches in LLD
> > > and coordinated on the feature parity among the 3 linkers
> > > (e.g. https://sourceware.org/pipermail/binutils/2020-August/112732.html)
> > >
> > > LLD and GNU ld, LLVM's integrated assembler and GNU as have achieved
> > consensus on many aspects
> > > on SHF_LINK_ORDER and 'unique' linkage. Credits to H.J. for all the
> > binutils side work.
> > > )
> > >
> > > I have asked a couple of toolchain folks. Many do share the same feeling
> > > with me: an additional GC feature is useful but whether it should be
> > > this exact form of a new flag we don't know.
> >
> > Hi Fangrui,
> >
> > Thank you for providing some more information to backup your points, I
> > will address those below.
> >
> > >
> > > Your patch also deprives an OS-specific flag from ELFOSABI_FREEBSD:)
> > > I am not a committer of FreeBSD and I am surely not authoritative on
> > > whether this is acceptable. But, FreeBSD does use the aforementioned
> > > LLVM tools and I don't want to dirty the code base by adding
> > > if (osabi == ELFOSABI_FREEBSD) do something.
> >
> > I don't have any insight into the ELFOSABI_FREEBSD change, H.J. added that
> > part, I assume it is very closely aligned with the "pure" GNU OSABI, so
> > any changes to one should be kept in parity with the other. However,
> > that is only my assumption.
> >
> > >
> > > We have 8 bits in SHF_MASKOS: not too few, but also not too many.  We
> > > should be prudent with new flags, especially if we already have a
> > > facility for section retaining. There is a difference ".reloc requires a
> > > known live section" which might cause friction but it has the advantage
> > that it is
> > > time-tested and has good toolchain support.
> >
> > Yes, this is something I considered, but there are 6 bits remaining to
> > be used, with SHF_GNU_RETAIN there will be 5 bits remaining.
> > Given how little movement there has been within the SHF_MAKOS bits for
> > the past 20 years, I don't think we need to be too protective of the
> > bits. They are there to be used after all, and IMO SHF_GNU_RETAIN is a
> > very well-defined use case to use one of those bits.
> >
> > For the .reloc mechanism, in every object file with a retained section
> > you will need to have an empty input section which is guaranteed to be
> > kept by the linker. How is the compiler to know what that section is?
> >
> > >
> > >
> > > Opinions from others:
> > >
> > > * Peter Smith mentioned that Arm's proprietary toolchain does something
> > >   similar to SHF_GNU_RETAIN
> > >   (
> > https://www.keil.com/support/man/docs/armcc/armcc_chr1359124983230.htm)
> > >   "I put __attribute__((used)) on my function and yet the tools removed
> > >   it anyway."
> > >
> > > * James Henderson mentioned whether we can
> > >   "create a new section type listing section indexes that should be
> > >   retained"
> > >   As a variant, we could use a SHT_GROUP with a new GRP_* bit.
> > >   Anchor: [group] (see below)
> >
> > Using groups was discussed on the GNU gABI thread, but I don't really
> > see the benefit of the added complication. Doesn't handling new section
> > group types still require significant coordination between all the
> > different compilers, assemblers and linkers?
> >
> > Any attempt to reference a section which does not exist in the object
> > file, and is not guaranteed to be present in the linked output file, is
> > a non-starter in my opinion. We give users the freedom to do what they
> > want with linker scripts as ELF doesn't mandate any section must be
> > linked into the final executable. I think it's better to consolidate
> > the requirement to retain within the section that requires retaining,
> > instead of spreading the requirement to retain between ELF constructs
> > which have unrelated purposes, and need to be aligned between different
> > stages of the build process.
> >
> > >
> > > > Do we want to make life easier for ourselves, or easier for our users?
> > > >
> > > > I get that ABI changes can be a bit disruptive, but this new flag in
> > particular really isn't complicated anyway.
> > >
> > > On 2020-09-29, Jozef Lawrynowicz wrote:
> > > > On Mon, Sep 28, 2020 at 09:43:53PM -0700, Fangrui Song wrote:
> > > > > On 2020-09-28, Jozef Lawrynowicz wrote:
> > > > > > The attached patch is version 2 of the SHF_GNU_RETAIN patch that
> > was
> > > > > > previously discussed here:
> > > > > >
> > https://sourceware.org/pipermail/binutils/2020-September/113406.html
> > > > > >
> > > > > > The following changes have been made:
> > > > > > - Removed the .retain directive
> > > > > > - The assembler will create different input sections for sections
> > with
> > > > > >  the same name but SHF_GNU_RETAIN set/unset (thanks to H.J. for
> > that).
> > > > > >  This means the linker will be able to do a better job garbage
> > > > > >  collecting input sections, as the "retain" attribute applied to a
> > > > > >  symbol declaration in the source code will not cause other parts
> > of
> > > > > >  the program that are not required, but are in the same section,
> > to be
> > > > > >  unnecessarily retained.
> > > > > > - Added GNU OSABI handling (also thanks to H.J.).
> > > > >
> > > > > My point from
> > https://sourceware.org/pipermail/binutils/2020-September/113466.html
> > stands.
> > > > > Section flags are a bit cumbersome. If the following
> > > > >
> > > > >   // a.h
> > > > >   __attribute__((section("sec")))
> > > > >   inline void bar() { ... }
> > > > >   // a.c
> > > > >   #include "a.h"
> > > > >   __attribute__((section("sec"), retain))
> > > > >   void foo() {
> > > > >   }
> > > > >
> > > > > compiles to
> > > > >
> > > > >   .section sec,"a",@progbits
> > > > >   ...
> > > > >   .section sec,"aR",@progbits
> > > > >   ...
> > > > >
> > > > > You will get a gas error for changing section flags
> > > > > (https://sourceware.org/pipermail/binutils/2020-February/109945.html
> > )
> > > > >
> > > >
> > > > There is no error in this case.
> > > > The original patch handled it, and it has been further improved in v2.
> > > > There's even a testcase testing exactly the functionality you say is
> > > > broken.
> > > >
> > > >  gas/testsuite/gas/elf/section22.s:
> > > >      .section       .bss,"aw"
> > > >    ...
> > > >      .section       .bss,"awR",%nobits
> > > >
> > > > I already gave a detailed response to your reloc proposal:
> > > > https://sourceware.org/pipermail/binutils/2020-September/113450.html
> > >
> > > Letting the following assembly creates two .bss sections adds an
> > exception to
> > > "gas: error for section type, attr, or entsize change"
> > > (https://sourceware.org/pipermail/binutils/2020-February/109945.html)
> > > for which I have achieved consensus with Alan Modra and some LLVM
> > > toolchain folks. That is why I hope we could re-consider this design
> > > choice.
> > >
> > > .section      .bss,"aw"
> > > .section      .bss,"awR",%nobits
> >
> > I agree that this could be considered slightly inelegant, but much less
> > so than having .reloc directives in arbitrary empty sections.
> > Once someone understands what the "R" flag does, it should be clear why
> > we want to create a separate input section for it.
> >
> > If we really want, we can force the compiler to create unique section
> > names for declarations which have the "retain" attribute applied. I
> > assume most of the time, users will want this fine section
> > granularity. I would prefer not to go that route and leave it to the
> > users to specify unique sections if they want.
> >
> > >
> > > See above for [group]: it is actually nice to use a group here, because
> > > the quadruple
> > > (section name, group name if "G", linked-to section if "o", unique id of
> > > "unique") is the section key. The following creates a section different
> > > from the default .bss:
> > >
> > >   .section    .bss,"awG",%nobits,gc_root
> >
> > I don't think it is really very important whether input sections with
> > the same name are unique or not within an object file. ELF doesn't care
> > about this. You can have sections with the same name and same flags in
> > different object files and the linker can just deal with it. It's the
> > same situation if you have two sections from the same object file which
> > have the same name.
> >
> > Within an object file, you'll end up with all the non-SHF_GNU_RETAIN
> > sections with the same name being merged together by the assembler, and
> > all those with SHF_GNU_RETAIN being merged. I don't think there is any
> > benefit to keep SHF_GNU_RETAIN sections with the same name as separate
> > input sections in the object file.
> >
> > Thanks,
> > Jozef
> >
> > >
> > > > Why don't you first answer my questions about why using relocs is a
> > > > really bad idea, is a hack, doesn't conceptually make any sense, and
> > > > will confuse users?
> > > >
> > > > You never actually gave a reason that using relocs is better than
> > > > SHF_GNU_RETAIN, you seem to be pushing this alternative implementation
> > just
> > > > because it is an alternative implementation. I don't count your
> > > > description of section flags as "cumbersome" as a reason we should
> > > > shelve this proposal.
> > >
> > > I hope my previous paragraphs have answered this point.
> > >
> > > > > .reloc is really convenience in this case. You can add as many .reloc
> > > > > directives as you like, each contributing one R_*_NONE to the object
> > > > > file but zero cost to the linked image.
> > > >
> > > > Are we really counting a section flag as adding "cost" to a linked
> > > > image?  Your method requires a "benign zero-sized section" (suggested
> > in
> > > > your previous email), doesn't this also add cost? What about the cost
> > of
> > > > having nonsensical relocs in object files?
> > > >
> > > > If we are using the term "cost" loosely, and to further our own point,
> > > > then SHF_GNU_RETAIN actually has negative cost to the linked image. You
> > > > can have different input sections with the same name, but with
> > different
> > > > states for SHF_GNU_RETAIN (set and unset), and so garbage collection
> > > > will operate with finer granularity, removing more unneeded parts of
> > the
> > > > program compared to your reloc mechanism, which would keep the entire
> > > > section containing the symbol referenced by the reloc.
> > > >
> > > > Thanks,
> > > > Jozef
> >
> >

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-09-30 10:18           ` Jozef Lawrynowicz
@ 2020-09-30 14:01             ` H.J. Lu
  2020-10-01 19:22             ` Fangrui Song
  1 sibling, 0 replies; 22+ messages in thread
From: H.J. Lu @ 2020-09-30 14:01 UTC (permalink / raw)
  To: Roland McGrath, Fangrui Song, Binutils Development, GNU gABI gnu-gabi

On Wed, Sep 30, 2020 at 3:19 AM Jozef Lawrynowicz
<jozef.l@mittosystems.com> wrote:
>
> On Tue, Sep 29, 2020 at 05:10:09PM -0700, Roland McGrath wrote:
> > Since group semantics mean that if any section in a group is retained the
> > whole group must be retained, it seems to me that making the feature a
> > group flag rather than a section flag makes sense. I don't think it really
> > has any downside. It's a little bit more structure to generate a group but
> > everything already knows how to do it so that should be no problem.  While
> > it is true that multiple sections with the same name and different
> > attributes should already be fine, the place where multiple different
> > sections of the same name are usually seen today is when each different
> > section reusing a name is in a different group from the other sections with
> > the same name.
> >
>
> Let's assume:
>   GRP_RETAIN
>     Sections in a group with this flag set should always be included in
>     the linked object, even if they appear unused.
>
> One issue I have with the group method is conceptual; groups are supposed
> to be used to group related sections. They are related because of their
> meaning from the application perspective, not because of their metadata
> (i.e. sections to be retained are related by their metadata because they
> all should be retained).
>
> Just because groups have a side effect that can be leveraged to
> get a section to be retained in the final link, why does that mean we
> need to leverage that property when it it's not actually the simplest or
> most obvious way to implement the new behavior?
>
> SHF_GNU_RETAIN describes in the simplest possible way that the section
> should be retained in the final link, without relying on other
> constructs.
>
> Just because groups are discarded or retained as a group, doesn't mean
> we need to leverage groups to try and implement retention or discarding
> functionality.
>
> Why wasn't SHF_EXCLUDE implemented as a group flag? After all, groups
> are included or excluded from the link together.
>   GRP_EXCLUDE
>     Sections in a group with GRP_EXCLUDE set should be discarded from
>     the link.
>
> I mean, you could kind of use groups for anything when you decide
> grouping sections by metadata is OK.
> Why define SHT_NOBITS when you can create:
>   GRP_NOBITS
>     Sections in this group occupy no space in the file. They must have
>     type SHT_PROGBITS.
>
> Retention of a section is a property of the section. We are misusing ELF
> constructs by using groups to indicate an arbitrary section needs to be
> retained.
>
> Another issue (if more is needed) is about how to name the groups.
> * If it is mandated that GRP_RETAIN groups have the same name e.g.
>   "grp_retain", that means you can't put a section you want to
>   retain in a different logical group that makes sense from the
>   application perspective. So the other sections you would want to put
>   in a group with the retained section need to all be put in a bundle
>   with all the other GRP_RETAIN sections.
> * If GRP_RETAIN groups can have any name, so you can have multiple
>   GRP_RETAIN groups, how does the compiler decide how to name the
>   groups? It seems like it would be a mess. "grp_retain0", "grp_retain2"
>   ... "grp_retain10" from one object file, "grp_retain0"...
>   "grp_retain5" from another. Extra processing in the
>   linker to clean up these group names and keep them unique would be
>   required when performing a relocatable link.
>
> As a general point, what if I decide that there's enough pressure from
> the anti-SHF_GNU_RETAIN side that I change the implementation to use
> groups. But then those who already backed the flag prefer that method
> over using groups think the implementation should not have been changed.
>
> I feel like we already got enough backing for SHF_GNU_RETAIN between the
> GNU gABI and Binutils discussions. I understand, and welcome, more
> feedback, but I haven't been convinced any other method is obviously
> better than SHF_GNU_RETAIN, so why change it?
>
> I'm not saying it's possible to quantify which mechanism for "retain" is
> best, but SHF_GNU_RETAIN is the simplest, most obvious, and easiest to
> understand. Surely that gives it top marks?
>
> I'm also yet to hear one convincing reason why SHF_GNU_RETAIN is bad.
> As far as I can tell, the main argument against it stems from the fact
> that you can have two input sections with the same name but different
> SHF_GNU_RETAIN flag states. Not only is this a non-issue, groups have
> exactly the same problem!
>
> It would be great if a global maintainer to chime in on whether the
> attached patch is acceptable, because otherwise we are going to go back
> and forth forever.
>

I like SHF_GNU_RETAIN which is complementary to SHF_EXCLUDE.

-- 
H.J.

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-09-30  0:10         ` Roland McGrath
  2020-09-30 10:18           ` Jozef Lawrynowicz
@ 2020-09-30 14:13           ` Michael Matz
  1 sibling, 0 replies; 22+ messages in thread
From: Michael Matz @ 2020-09-30 14:13 UTC (permalink / raw)
  To: Roland McGrath; +Cc: Fangrui Song, Binutils Development, gnu-gabi

Hello,

On Tue, 29 Sep 2020, Roland McGrath wrote:

> Since group semantics mean that if any section in a group is retained the
> whole group must be retained, it seems to me that making the feature a
> group flag rather than a section flag makes sense. I don't think it really
> has any downside. It's a little bit more structure to generate a group but
> everything already knows how to do it so that should be no problem.  While
> it is true that multiple sections with the same name and different
> attributes should already be fine, the place where multiple different
> sections of the same name are usually seen today is when each different
> section reusing a name is in a different group from the other sections with
> the same name.

pseudo-code for retaining a section in producer.  SHF_GNU_RETAIN:

  retain_section(S):
    S.flag |= SHF_GNU_RETAIN

GRP_RETAIN:

  retain_section(S):
    if !retain_group:
      retain_group = new_group(GRP_RETAIN)
    retain_group.add (S)

pseudo-code for interpreting this in the consumer (which presumably is 
section based as basic building block, as groups are optional).  
SHF_GNU_RETAIN:

  in the 'output_section_p' predicate, add " || S.flag & SHF_GNU_RETAIN".

GRP_RETAIN:

  in preparatory per-object parsing, in the existing group parser:
  
    if G.type == GRP_RETAIN:
      foreach S in G:
        S.needed = true

  in the 'output_section_p' predicate, add " || S.needed"

That's the additional structure you mention.  While it's not much 
down-side, what is the up-side?  There should be one, not just only small 
down-sides.


Ciao,
Michael.

 > 
> On Tue, Sep 29, 2020 at 2:37 PM Jozef Lawrynowicz <jozef.l@mittosystems.com>
> wrote:
> 
> > On Tue, Sep 29, 2020 at 12:38:06PM -0700, Fangrui Song wrote:
> > > On 2020-09-29, Jozef Lawrynowicz wrote:
> > > > There are more logic holes in your other email that I didn't
> > > > respond to, but I've already spent a tonne of time trying to address
> > > > your points (most of which you ignored, so why did I bother?), so I
> > > > think I'm done debating this.
> > > > If other people back up your suggestion, and address my concerns, then
> > > > we can re-open this.
> > >
> > > Hi Jozef, apologies if I did not respond to your previous replies in
> > > time or if I acted as if I "blocked" your change. I maintain LLVM's
> > > linker LLD and am also a contributor to its binary utilities
> > > (llvm-readelf, llvm-objdump, ...). If GCC makes use of this flag for
> > __attribute__((used)),
> > > LLD and LLVM's binary utilities do need to support it.
> > > So I want to participate in the design before we regret :)
> > >
> > > I have studied linker GC quite a lot (contributed patches in LLD
> > > and coordinated on the feature parity among the 3 linkers
> > > (e.g. https://sourceware.org/pipermail/binutils/2020-August/112732.html)
> > >
> > > LLD and GNU ld, LLVM's integrated assembler and GNU as have achieved
> > consensus on many aspects
> > > on SHF_LINK_ORDER and 'unique' linkage. Credits to H.J. for all the
> > binutils side work.
> > > )
> > >
> > > I have asked a couple of toolchain folks. Many do share the same feeling
> > > with me: an additional GC feature is useful but whether it should be
> > > this exact form of a new flag we don't know.
> >
> > Hi Fangrui,
> >
> > Thank you for providing some more information to backup your points, I
> > will address those below.
> >
> > >
> > > Your patch also deprives an OS-specific flag from ELFOSABI_FREEBSD:)
> > > I am not a committer of FreeBSD and I am surely not authoritative on
> > > whether this is acceptable. But, FreeBSD does use the aforementioned
> > > LLVM tools and I don't want to dirty the code base by adding
> > > if (osabi == ELFOSABI_FREEBSD) do something.
> >
> > I don't have any insight into the ELFOSABI_FREEBSD change, H.J. added that
> > part, I assume it is very closely aligned with the "pure" GNU OSABI, so
> > any changes to one should be kept in parity with the other. However,
> > that is only my assumption.
> >
> > >
> > > We have 8 bits in SHF_MASKOS: not too few, but also not too many.  We
> > > should be prudent with new flags, especially if we already have a
> > > facility for section retaining. There is a difference ".reloc requires a
> > > known live section" which might cause friction but it has the advantage
> > that it is
> > > time-tested and has good toolchain support.
> >
> > Yes, this is something I considered, but there are 6 bits remaining to
> > be used, with SHF_GNU_RETAIN there will be 5 bits remaining.
> > Given how little movement there has been within the SHF_MAKOS bits for
> > the past 20 years, I don't think we need to be too protective of the
> > bits. They are there to be used after all, and IMO SHF_GNU_RETAIN is a
> > very well-defined use case to use one of those bits.
> >
> > For the .reloc mechanism, in every object file with a retained section
> > you will need to have an empty input section which is guaranteed to be
> > kept by the linker. How is the compiler to know what that section is?
> >
> > >
> > >
> > > Opinions from others:
> > >
> > > * Peter Smith mentioned that Arm's proprietary toolchain does something
> > >   similar to SHF_GNU_RETAIN
> > >   (
> > https://www.keil.com/support/man/docs/armcc/armcc_chr1359124983230.htm)
> > >   "I put __attribute__((used)) on my function and yet the tools removed
> > >   it anyway."
> > >
> > > * James Henderson mentioned whether we can
> > >   "create a new section type listing section indexes that should be
> > >   retained"
> > >   As a variant, we could use a SHT_GROUP with a new GRP_* bit.
> > >   Anchor: [group] (see below)
> >
> > Using groups was discussed on the GNU gABI thread, but I don't really
> > see the benefit of the added complication. Doesn't handling new section
> > group types still require significant coordination between all the
> > different compilers, assemblers and linkers?
> >
> > Any attempt to reference a section which does not exist in the object
> > file, and is not guaranteed to be present in the linked output file, is
> > a non-starter in my opinion. We give users the freedom to do what they
> > want with linker scripts as ELF doesn't mandate any section must be
> > linked into the final executable. I think it's better to consolidate
> > the requirement to retain within the section that requires retaining,
> > instead of spreading the requirement to retain between ELF constructs
> > which have unrelated purposes, and need to be aligned between different
> > stages of the build process.
> >
> > >
> > > > Do we want to make life easier for ourselves, or easier for our users?
> > > >
> > > > I get that ABI changes can be a bit disruptive, but this new flag in
> > particular really isn't complicated anyway.
> > >
> > > On 2020-09-29, Jozef Lawrynowicz wrote:
> > > > On Mon, Sep 28, 2020 at 09:43:53PM -0700, Fangrui Song wrote:
> > > > > On 2020-09-28, Jozef Lawrynowicz wrote:
> > > > > > The attached patch is version 2 of the SHF_GNU_RETAIN patch that
> > was
> > > > > > previously discussed here:
> > > > > >
> > https://sourceware.org/pipermail/binutils/2020-September/113406.html
> > > > > >
> > > > > > The following changes have been made:
> > > > > > - Removed the .retain directive
> > > > > > - The assembler will create different input sections for sections
> > with
> > > > > >  the same name but SHF_GNU_RETAIN set/unset (thanks to H.J. for
> > that).
> > > > > >  This means the linker will be able to do a better job garbage
> > > > > >  collecting input sections, as the "retain" attribute applied to a
> > > > > >  symbol declaration in the source code will not cause other parts
> > of
> > > > > >  the program that are not required, but are in the same section,
> > to be
> > > > > >  unnecessarily retained.
> > > > > > - Added GNU OSABI handling (also thanks to H.J.).
> > > > >
> > > > > My point from
> > https://sourceware.org/pipermail/binutils/2020-September/113466.html
> > stands.
> > > > > Section flags are a bit cumbersome. If the following
> > > > >
> > > > >   // a.h
> > > > >   __attribute__((section("sec")))
> > > > >   inline void bar() { ... }
> > > > >   // a.c
> > > > >   #include "a.h"
> > > > >   __attribute__((section("sec"), retain))
> > > > >   void foo() {
> > > > >   }
> > > > >
> > > > > compiles to
> > > > >
> > > > >   .section sec,"a",@progbits
> > > > >   ...
> > > > >   .section sec,"aR",@progbits
> > > > >   ...
> > > > >
> > > > > You will get a gas error for changing section flags
> > > > > (https://sourceware.org/pipermail/binutils/2020-February/109945.html
> > )
> > > > >
> > > >
> > > > There is no error in this case.
> > > > The original patch handled it, and it has been further improved in v2.
> > > > There's even a testcase testing exactly the functionality you say is
> > > > broken.
> > > >
> > > >  gas/testsuite/gas/elf/section22.s:
> > > >      .section       .bss,"aw"
> > > >    ...
> > > >      .section       .bss,"awR",%nobits
> > > >
> > > > I already gave a detailed response to your reloc proposal:
> > > > https://sourceware.org/pipermail/binutils/2020-September/113450.html
> > >
> > > Letting the following assembly creates two .bss sections adds an
> > exception to
> > > "gas: error for section type, attr, or entsize change"
> > > (https://sourceware.org/pipermail/binutils/2020-February/109945.html)
> > > for which I have achieved consensus with Alan Modra and some LLVM
> > > toolchain folks. That is why I hope we could re-consider this design
> > > choice.
> > >
> > > .section      .bss,"aw"
> > > .section      .bss,"awR",%nobits
> >
> > I agree that this could be considered slightly inelegant, but much less
> > so than having .reloc directives in arbitrary empty sections.
> > Once someone understands what the "R" flag does, it should be clear why
> > we want to create a separate input section for it.
> >
> > If we really want, we can force the compiler to create unique section
> > names for declarations which have the "retain" attribute applied. I
> > assume most of the time, users will want this fine section
> > granularity. I would prefer not to go that route and leave it to the
> > users to specify unique sections if they want.
> >
> > >
> > > See above for [group]: it is actually nice to use a group here, because
> > > the quadruple
> > > (section name, group name if "G", linked-to section if "o", unique id of
> > > "unique") is the section key. The following creates a section different
> > > from the default .bss:
> > >
> > >   .section    .bss,"awG",%nobits,gc_root
> >
> > I don't think it is really very important whether input sections with
> > the same name are unique or not within an object file. ELF doesn't care
> > about this. You can have sections with the same name and same flags in
> > different object files and the linker can just deal with it. It's the
> > same situation if you have two sections from the same object file which
> > have the same name.
> >
> > Within an object file, you'll end up with all the non-SHF_GNU_RETAIN
> > sections with the same name being merged together by the assembler, and
> > all those with SHF_GNU_RETAIN being merged. I don't think there is any
> > benefit to keep SHF_GNU_RETAIN sections with the same name as separate
> > input sections in the object file.
> >
> > Thanks,
> > Jozef
> >
> > >
> > > > Why don't you first answer my questions about why using relocs is a
> > > > really bad idea, is a hack, doesn't conceptually make any sense, and
> > > > will confuse users?
> > > >
> > > > You never actually gave a reason that using relocs is better than
> > > > SHF_GNU_RETAIN, you seem to be pushing this alternative implementation
> > just
> > > > because it is an alternative implementation. I don't count your
> > > > description of section flags as "cumbersome" as a reason we should
> > > > shelve this proposal.
> > >
> > > I hope my previous paragraphs have answered this point.
> > >
> > > > > .reloc is really convenience in this case. You can add as many .reloc
> > > > > directives as you like, each contributing one R_*_NONE to the object
> > > > > file but zero cost to the linked image.
> > > >
> > > > Are we really counting a section flag as adding "cost" to a linked
> > > > image?  Your method requires a "benign zero-sized section" (suggested
> > in
> > > > your previous email), doesn't this also add cost? What about the cost
> > of
> > > > having nonsensical relocs in object files?
> > > >
> > > > If we are using the term "cost" loosely, and to further our own point,
> > > > then SHF_GNU_RETAIN actually has negative cost to the linked image. You
> > > > can have different input sections with the same name, but with
> > different
> > > > states for SHF_GNU_RETAIN (set and unset), and so garbage collection
> > > > will operate with finer granularity, removing more unneeded parts of
> > the
> > > > program compared to your reloc mechanism, which would keep the entire
> > > > section containing the symbol referenced by the reloc.
> > > >
> > > > Thanks,
> > > > Jozef
> >
> >
> 

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-09-28 13:26 [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag Jozef Lawrynowicz
  2020-09-29  4:43 ` Fangrui Song
@ 2020-09-30 22:13 ` H.J. Lu
  2020-10-01 10:50   ` Jozef Lawrynowicz
  1 sibling, 1 reply; 22+ messages in thread
From: H.J. Lu @ 2020-09-30 22:13 UTC (permalink / raw)
  To: Binutils

On Mon, Sep 28, 2020 at 6:28 AM Jozef Lawrynowicz
<jozef.l@mittosystems.com> wrote:
>
> The attached patch is version 2 of the SHF_GNU_RETAIN patch that was
> previously discussed here:
> https://sourceware.org/pipermail/binutils/2020-September/113406.html
>
> The following changes have been made:
> - Removed the .retain directive
> - The assembler will create different input sections for sections with
>   the same name but SHF_GNU_RETAIN set/unset (thanks to H.J. for that).
>   This means the linker will be able to do a better job garbage
>   collecting input sections, as the "retain" attribute applied to a
>   symbol declaration in the source code will not cause other parts of
>   the program that are not required, but are in the same section, to be
>   unnecessarily retained.
> - Added GNU OSABI handling (also thanks to H.J.).
>
> I've successfully regtested the patch for the Binutils, GAS and LD
> testsuites for the following targets:
>
> aarch64-elf arc-elf arm-eabi arm-elf avr-elf bfin-elf cr16-elf cris-elf
> crx-elf csky-elf d10v-elf d30v-elf dlx-elf epiphany-elf fr30-elf frv-elf
> ft32-elf h8300-elf hppa-elf i386-elf ip2k-elf iq2000-elf lm32-elf
> m32c-elf m32r-elf m68hc11-elf m68hc12-elf m68k-elf mcore-elf mep-elf
> metag-elf microblaze-elf mips-elf moxie-elf msp430-elf mt-elf nios2-elf
> or1k-elf pj-elf ppc-elf pru-elf riscv-elf rl78-elf rx-elf s12z-elf
> score-elf sh-elf sparc-elf spu-elf tic6x-elf tilegx-elf tilepro-elf
> v850-elf visium-elf wasm32-elf xgate-elf xstormy16-elf xtensa-elf
> z80-elf.
>
> The new tests only run for the targets that use the GNU OSABI. From the
> above list, arm-elf, hppa-elf, msp430-elf, visium-elf do not use the GNU
> OSABI, so do not support SHF_GNU_RETAIN.
>
> Ok to apply?
>
> Thanks,
> Jozef

+# SHF_GNU_RETAIN requires the GNU OSABI.
+if { [check_gc_sections_available] && [supports_gnu_osabi] } {
+    run_ld_link_tests [list \
+ [list "SHF_GNU_RETAIN 1" \
+     "--gc-sections -e _start --print-gc-sections" "" "" \
+     {retain1.s} \
+     {{ ld retain1.msg }} \
+     "retain1.exe"] \
+ [list "SHF_GNU_RETAIN 3 (keep sections referenced by retained sections)" \
+     "--gc-sections -e _start --print-gc-sections" "" "" \
+     {retain3.s} {} \
+     "retain3.exe"] \
+ [list "SHF_GNU_RETAIN 4 (keep orphaned sections when not discarding)" \
+     "--gc-sections -e _start --print-gc-sections
--orphan-handling=place" "" "" \
+     {retain4.s} {} \
+     "retain4.exe"] \
+ [list "Build libretain5.a" \
+     "" "" "" \
+     {retain5lib.s} {} "libretain5.a"] \
+ [list "SHF_GNU_RETAIN 5 (don't pull SHF_GNU_RETAIN section out of lib)" \
+     "--gc-sections -e _start --print-gc-sections" "-Ltmpdir -lretain5" "" \
+     {retain5main.s} {} \
+     "retain5.exe"] \
+ [list "Build libretain6.a" \
+     "" "" "" \
+     {retain6lib.s} {} "libretain6.a"] \
+ [list "SHF_GNU_RETAIN 6 (pull section out of lib required by
SHF_GNU_RETAIN section)" \
+     "--gc-sections -e _start --print-gc-sections" "-Ltmpdir -lretain6" "" \
+     {retain6main.s} \
+     {{ ld retain6.msg }} \
+     "retain6.exe"] \
+ ]
+}
+

Can you use *.d files like

retain6.d:
#ld: --gc-sections --print-gc-sections -e _start
#warning_output: retain6.l
#target: [check_gc_sections_available]

instead?

-- 
H.J.

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-09-30 22:13 ` H.J. Lu
@ 2020-10-01 10:50   ` Jozef Lawrynowicz
  2020-10-01 11:39     ` Alan Modra
  0 siblings, 1 reply; 22+ messages in thread
From: Jozef Lawrynowicz @ 2020-10-01 10:50 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Binutils

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

On Wed, Sep 30, 2020 at 03:13:15PM -0700, H.J. Lu via Binutils wrote:
> On Mon, Sep 28, 2020 at 6:28 AM Jozef Lawrynowicz
> <jozef.l@mittosystems.com> wrote:
> >
> > The attached patch is version 2 of the SHF_GNU_RETAIN patch that was
> > previously discussed here:
> > https://sourceware.org/pipermail/binutils/2020-September/113406.html
> >
> > The following changes have been made:
> > - Removed the .retain directive
> > - The assembler will create different input sections for sections with
> >   the same name but SHF_GNU_RETAIN set/unset (thanks to H.J. for that).
> >   This means the linker will be able to do a better job garbage
> >   collecting input sections, as the "retain" attribute applied to a
> >   symbol declaration in the source code will not cause other parts of
> >   the program that are not required, but are in the same section, to be
> >   unnecessarily retained.
> > - Added GNU OSABI handling (also thanks to H.J.).
> >
> > I've successfully regtested the patch for the Binutils, GAS and LD
> > testsuites for the following targets:
> >
> > aarch64-elf arc-elf arm-eabi arm-elf avr-elf bfin-elf cr16-elf cris-elf
> > crx-elf csky-elf d10v-elf d30v-elf dlx-elf epiphany-elf fr30-elf frv-elf
> > ft32-elf h8300-elf hppa-elf i386-elf ip2k-elf iq2000-elf lm32-elf
> > m32c-elf m32r-elf m68hc11-elf m68hc12-elf m68k-elf mcore-elf mep-elf
> > metag-elf microblaze-elf mips-elf moxie-elf msp430-elf mt-elf nios2-elf
> > or1k-elf pj-elf ppc-elf pru-elf riscv-elf rl78-elf rx-elf s12z-elf
> > score-elf sh-elf sparc-elf spu-elf tic6x-elf tilegx-elf tilepro-elf
> > v850-elf visium-elf wasm32-elf xgate-elf xstormy16-elf xtensa-elf
> > z80-elf.
> >
> > The new tests only run for the targets that use the GNU OSABI. From the
> > above list, arm-elf, hppa-elf, msp430-elf, visium-elf do not use the GNU
> > OSABI, so do not support SHF_GNU_RETAIN.
> >
> > Ok to apply?
> >
> > Thanks,
> > Jozef
> 
> +# SHF_GNU_RETAIN requires the GNU OSABI.
> +if { [check_gc_sections_available] && [supports_gnu_osabi] } {
> +    run_ld_link_tests [list \
> + [list "SHF_GNU_RETAIN 1" \
> +     "--gc-sections -e _start --print-gc-sections" "" "" \
> +     {retain1.s} \
> +     {{ ld retain1.msg }} \
> +     "retain1.exe"] \
> + [list "SHF_GNU_RETAIN 3 (keep sections referenced by retained sections)" \
> +     "--gc-sections -e _start --print-gc-sections" "" "" \
> +     {retain3.s} {} \
> +     "retain3.exe"] \
> + [list "SHF_GNU_RETAIN 4 (keep orphaned sections when not discarding)" \
> +     "--gc-sections -e _start --print-gc-sections
> --orphan-handling=place" "" "" \
> +     {retain4.s} {} \
> +     "retain4.exe"] \
> + [list "Build libretain5.a" \
> +     "" "" "" \
> +     {retain5lib.s} {} "libretain5.a"] \
> + [list "SHF_GNU_RETAIN 5 (don't pull SHF_GNU_RETAIN section out of lib)" \
> +     "--gc-sections -e _start --print-gc-sections" "-Ltmpdir -lretain5" "" \
> +     {retain5main.s} {} \
> +     "retain5.exe"] \
> + [list "Build libretain6.a" \
> +     "" "" "" \
> +     {retain6lib.s} {} "libretain6.a"] \
> + [list "SHF_GNU_RETAIN 6 (pull section out of lib required by
> SHF_GNU_RETAIN section)" \
> +     "--gc-sections -e _start --print-gc-sections" "-Ltmpdir -lretain6" "" \
> +     {retain6main.s} \
> +     {{ ld retain6.msg }} \
> +     "retain6.exe"] \
> + ]
> +}
> +
> 
> Can you use *.d files like
> 
> retain6.d:
> #ld: --gc-sections --print-gc-sections -e _start
> #warning_output: retain6.l
> #target: [check_gc_sections_available]
> 
> instead?

Fixed in the attached patch.

Thanks,
Jozef
> 
> -- 
> H.J.

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

From c089da6a64f293e1fc15cdf31e647b4f04af62b4 Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@mittosystems.com>
Date: Thu, 1 Oct 2020 11:49:04 +0100
Subject: [PATCH] Support SHF_GNU_RETAIN ELF section flag

The GNU-specific SHF_GNU_RETAIN ELF section flag is defined as follows:

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

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

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

Note that there is not a direct mapping of SHF_GNU_RETAIN to the BFD
section flag SEC_KEEP. This would prevent the user being able to
explicitly remove an SHF_GNU_RETAIN section by placing it in /DISCARD/.

bfd/ChangeLog:

2020-09-28  H.J. Lu  <hongjiu.lu@intel.com>
	Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* elf-bfd.h (enum elf_gnu_osabi): Add elf_gnu_osabi_retain.
	(struct elf_obj_tdata): Increase has_gnu_osabi to 4 bits.
	* elf.c (_bfd_elf_make_section_from_shdr): Set elf_gnu_osabi_retain
	for SHF_GNU_RETAIN.
	* elflink.c (bfd_elf_gc_sections): gc_mark the section if
	SHF_GNU_RETAIN is set.

binutils/ChangeLog:

2020-09-28  Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* NEWS: Announce SHF_GNU_RETAIN.
	* readelf.c (get_elf_section_flags): Handle SHF_GNU_RETAIN.
	* testsuite/binutils-all/readelf.exp: Run new test.
	Don't run run_dump_test when there isn't an assembler available.
	* testsuite/lib/binutils-common.exp (supports_gnu_osabi): Adjust
	comment.
	* testsuite/binutils-all/retain1.d: New test.
	* testsuite/binutils-all/retain1.s: New test.

gas/ChangeLog:

2020-09-28  H.J. Lu  <hongjiu.lu@intel.com>
	Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* NEWS: Announce SHF_GNU_RETAIN.
	* config/obj-elf.c (SEC_ASSEMBLER_SHF_MASK): New.
	(get_section): Use SEC_ASSEMBLER_SHF_MASK.
	(obj_elf_change_section): Update struct member name.
	(obj_elf_parse_section_letters): Handle 'R' flag.
	(obj_elf_section): Set elf_gnu_osabi_retain
	for SHF_GNU_RETAIN.
	* config/obj-elf.h (struct elf_section_match): Adjust "info" member
	name to "sh_info".  Add "sh_flags" member.
	* doc/as.texi (Section): Document 'R' flag.
	* testsuite/gas/elf/elf.exp: Run new tests.
	* testsuite/gas/elf/section10.d: Adjust test.
	* testsuite/gas/elf/section22.d: New test.
	* testsuite/gas/elf/section22.s: New test.

include/ChangeLog:

2020-09-28  Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* elf/common.h (SHF_GNU_RETAIN): Define.

ld/ChangeLog:

2020-09-28  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
	H.J. Lu  <hongjiu.lu@intel.com>

	* NEWS: Announce SHF_GNU_RETAIN.
	* ld.texi (garbage collection): Document SHF_GNU_RETAIN.
	(Output Section Discarding): Likewise.
	* testsuite/ld-elf/elf.exp: Run new tests.
	* testsuite/ld-elf/retain1.s: New test.
	* testsuite/ld-elf/retain1a.d: New test.
	* testsuite/ld-elf/retain1b.d: New test.
	* testsuite/ld-elf/retain2.d: New test.
	* testsuite/ld-elf/retain2.ld: New test.
	* testsuite/ld-elf/retain2.map: New test.
	* testsuite/ld-elf/retain3.d: New test.
	* testsuite/ld-elf/retain3.s: New test.
	* testsuite/ld-elf/retain4.d: New test.
	* testsuite/ld-elf/retain4.s: New test.
	* testsuite/ld-elf/retain5.d: New test.
	* testsuite/ld-elf/retain5.map: New test.
	* testsuite/ld-elf/retain5lib.s: New test.
	* testsuite/ld-elf/retain5main.s: New test.
	* testsuite/ld-elf/retain6a.d: New test.
	* testsuite/ld-elf/retain6b.d: New test.
	* testsuite/ld-elf/retain6lib.s: New test.
	* testsuite/ld-elf/retain6main.s: New test.
	* testsuite/ld-elf/retain7.s: New test.
	* testsuite/ld-elf/retain7a.d: New test.
	* testsuite/ld-elf/retain7b.d: New test.
---
 bfd/elf-bfd.h                               |   9 +-
 bfd/elf.c                                   |   5 +-
 bfd/elflink.c                               |   3 +-
 binutils/NEWS                               |   4 +
 binutils/readelf.c                          |   4 +
 binutils/testsuite/binutils-all/readelf.exp |   6 +-
 binutils/testsuite/binutils-all/retain1.d   |  18 ++++
 binutils/testsuite/binutils-all/retain1.s   | 104 ++++++++++++++++++++
 binutils/testsuite/lib/binutils-common.exp  |   5 +-
 gas/NEWS                                    |   6 ++
 gas/config/obj-elf.c                        |  39 +++++---
 gas/config/obj-elf.h                        |   3 +-
 gas/doc/as.texi                             |   3 +
 gas/testsuite/gas/elf/elf.exp               |   1 +
 gas/testsuite/gas/elf/section10.d           |   4 +-
 gas/testsuite/gas/elf/section22.d           |  19 ++++
 gas/testsuite/gas/elf/section22.s           |  34 +++++++
 include/elf/common.h                        |   1 +
 ld/NEWS                                     |   4 +
 ld/ld.texi                                  |   8 ++
 ld/testsuite/ld-elf/elf.exp                 |  11 +++
 ld/testsuite/ld-elf/retain1.s               | 104 ++++++++++++++++++++
 ld/testsuite/ld-elf/retain1a.d              |  28 ++++++
 ld/testsuite/ld-elf/retain1b.d              |  11 +++
 ld/testsuite/ld-elf/retain2.d               |   6 ++
 ld/testsuite/ld-elf/retain2.ld              |   7 ++
 ld/testsuite/ld-elf/retain2.map             |  32 ++++++
 ld/testsuite/ld-elf/retain3.d               |  12 +++
 ld/testsuite/ld-elf/retain3.s               |  19 ++++
 ld/testsuite/ld-elf/retain4.d               |  10 ++
 ld/testsuite/ld-elf/retain4.s               |  13 +++
 ld/testsuite/ld-elf/retain5.d               |  12 +++
 ld/testsuite/ld-elf/retain5.map             |   5 +
 ld/testsuite/ld-elf/retain5lib.s            |   6 ++
 ld/testsuite/ld-elf/retain5main.s           |   5 +
 ld/testsuite/ld-elf/retain6a.d              |  14 +++
 ld/testsuite/ld-elf/retain6b.d              |  11 +++
 ld/testsuite/ld-elf/retain6lib.s            |  17 ++++
 ld/testsuite/ld-elf/retain6main.s           |  13 +++
 ld/testsuite/ld-elf/retain7.s               | 104 ++++++++++++++++++++
 ld/testsuite/ld-elf/retain7a.d              |  28 ++++++
 ld/testsuite/ld-elf/retain7b.d              |  11 +++
 42 files changed, 737 insertions(+), 22 deletions(-)
 create mode 100644 binutils/testsuite/binutils-all/retain1.d
 create mode 100644 binutils/testsuite/binutils-all/retain1.s
 create mode 100644 gas/testsuite/gas/elf/section22.d
 create mode 100644 gas/testsuite/gas/elf/section22.s
 create mode 100644 ld/testsuite/ld-elf/retain1.s
 create mode 100644 ld/testsuite/ld-elf/retain1a.d
 create mode 100644 ld/testsuite/ld-elf/retain1b.d
 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.d
 create mode 100644 ld/testsuite/ld-elf/retain3.s
 create mode 100644 ld/testsuite/ld-elf/retain4.d
 create mode 100644 ld/testsuite/ld-elf/retain4.s
 create mode 100644 ld/testsuite/ld-elf/retain5.d
 create mode 100644 ld/testsuite/ld-elf/retain5.map
 create mode 100644 ld/testsuite/ld-elf/retain5lib.s
 create mode 100644 ld/testsuite/ld-elf/retain5main.s
 create mode 100644 ld/testsuite/ld-elf/retain6a.d
 create mode 100644 ld/testsuite/ld-elf/retain6b.d
 create mode 100644 ld/testsuite/ld-elf/retain6lib.s
 create mode 100644 ld/testsuite/ld-elf/retain6main.s
 create mode 100644 ld/testsuite/ld-elf/retain7.s
 create mode 100644 ld/testsuite/ld-elf/retain7a.d
 create mode 100644 ld/testsuite/ld-elf/retain7b.d

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 140a98594d..ffb75f7919 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1897,14 +1897,15 @@ struct output_elf_obj_tdata
   bfd_boolean flags_init;
 };
 
-/* Indicate if the bfd contains SHF_GNU_MBIND sections or symbols that
-   have the STT_GNU_IFUNC symbol type or STB_GNU_UNIQUE binding.  Used
-   to set the osabi field in the ELF header structure.  */
+/* Indicate if the bfd contains SHF_GNU_MBIND/SHF_GNU_RETAIN sections or
+   symbols that have the STT_GNU_IFUNC symbol type or STB_GNU_UNIQUE
+   binding.  Used to set the osabi field in the ELF header structure.  */
 enum elf_gnu_osabi
 {
   elf_gnu_osabi_mbind = 1 << 0,
   elf_gnu_osabi_ifunc = 1 << 1,
   elf_gnu_osabi_unique = 1 << 2,
+  elf_gnu_osabi_retain = 1 << 3,
 };
 
 typedef struct elf_section_list
@@ -2034,7 +2035,7 @@ struct elf_obj_tdata
   ENUM_BITFIELD (dynamic_lib_link_class) dyn_lib_class : 4;
 
   /* Whether the bfd uses OS specific bits that require ELFOSABI_GNU.  */
-  ENUM_BITFIELD (elf_gnu_osabi) has_gnu_osabi : 3;
+  ENUM_BITFIELD (elf_gnu_osabi) has_gnu_osabi : 4;
 
   /* Whether if the bfd contains the GNU_PROPERTY_NO_COPY_ON_PROTECTED
      property.  */
diff --git a/bfd/elf.c b/bfd/elf.c
index 00594020c9..85a889a97f 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1068,9 +1068,12 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
       /* FIXME: We should not recognize SHF_GNU_MBIND for ELFOSABI_NONE,
 	 but binutils as of 2019-07-23 did not set the EI_OSABI header
 	 byte.  */
-    case ELFOSABI_NONE:
     case ELFOSABI_GNU:
     case ELFOSABI_FREEBSD:
+      if ((hdr->sh_flags & SHF_GNU_RETAIN) != 0)
+	elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_retain;
+      /* Fall through */
+    case ELFOSABI_NONE:
       if ((hdr->sh_flags & SHF_GNU_MBIND) != 0)
 	elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_mbind;
       break;
diff --git a/bfd/elflink.c b/bfd/elflink.c
index b6937293e8..65b2d6b8aa 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -14102,7 +14102,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/NEWS b/binutils/NEWS
index c0dc73d7d8..6c7d3f3953 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -4,6 +4,10 @@
   symbol names.  In addition the --demangle=<style>, --no-demangle,
   --recurse-limit and --no-recurse-limit options are also now availale.
 
+* Add support for the SHF_GNU_RETAIN ELF section flag.
+  This flag specifies that the section should not be garbage collected by the
+  linker if it is unused.
+
 Changes in 2.35:
 
 * Changed readelf's display of symbol names when wide mode is not enabled.
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 9ba4e29a65..d136b750ed 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/binutils/testsuite/binutils-all/readelf.exp b/binutils/testsuite/binutils-all/readelf.exp
index 1fb36ae5c4..6dea09e305 100644
--- a/binutils/testsuite/binutils-all/readelf.exp
+++ b/binutils/testsuite/binutils-all/readelf.exp
@@ -364,8 +364,12 @@ readelf_wi_test
 readelf_compressed_wa_test
 
 readelf_dump_test
-run_dump_test "pr25543"
 
+# These dump tests require an assembler.
+if {[which $AS] != 0} then {
+    run_dump_test "pr25543"
+    run_dump_test "retain1"
+}
 
 # PR 13482 - Check for off-by-one errors when dumping .note sections.
 if {![binutils_assemble $srcdir/$subdir/version.s tmpdir/version.o]} then {
diff --git a/binutils/testsuite/binutils-all/retain1.d b/binutils/testsuite/binutils-all/retain1.d
new file mode 100644
index 0000000000..01cd32a475
--- /dev/null
+++ b/binutils/testsuite/binutils-all/retain1.d
@@ -0,0 +1,18 @@
+#source: retain1.s
+#readelf: -S --wide
+#name: readelf SHF_GNU_RETAIN
+#notarget: ![supports_gnu_osabi]
+
+#...
+  \[[ 0-9]+\] .bss.retain0.*WAR.*
+  \[[ 0-9]+\] .bss.retain1.*WAR.*
+  \[[ 0-9]+\] .data.retain2.*WAR.*
+  \[[ 0-9]+\] .bss.sretain0.*WAR.*
+  \[[ 0-9]+\] .bss.sretain1.*WAR.*
+  \[[ 0-9]+\] .data.sretain2.*WAR.*
+  \[[ 0-9]+\] .text.fnretain1.*AXR.*
+#...
+  \[[ 0-9]+\] .bss.lsretain0.*WAR.*
+  \[[ 0-9]+\] .bss.lsretain1.*WAR.*
+  \[[ 0-9]+\] .data.lsretain2.*WAR.*
+#pass
diff --git a/binutils/testsuite/binutils-all/retain1.s b/binutils/testsuite/binutils-all/retain1.s
new file mode 100644
index 0000000000..f7716faabe
--- /dev/null
+++ b/binutils/testsuite/binutils-all/retain1.s
@@ -0,0 +1,104 @@
+	.global	discard0
+	.section	.bss.discard0,"aw"
+	.type	discard0, %object
+discard0:
+	.zero	2
+
+	.global	discard1
+	.section	.bss.discard1,"aw"
+	.type	discard1, %object
+discard1:
+	.zero	2
+
+	.global	discard2
+	.section	.data.discard2,"aw"
+	.type	discard2, %object
+discard2:
+	.word	1
+
+	.section	.bss.sdiscard0,"aw"
+	.type	sdiscard0, %object
+sdiscard0:
+	.zero	2
+
+	.section	.bss.sdiscard1,"aw"
+	.type	sdiscard1, %object
+sdiscard1:
+	.zero	2
+
+	.section	.data.sdiscard2,"aw"
+	.type	sdiscard2, %object
+sdiscard2:
+	.word	1
+
+	.section	.text.fndiscard0,"ax"
+	.global	fndiscard0
+	.type	fndiscard0, %function
+fndiscard0:
+	.word 0
+
+	.global	retain0
+	.section	.bss.retain0,"awR"
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.global	retain1
+	.section	.bss.retain1,"awR"
+	.type	retain1, %object
+retain1:
+	.zero	2
+
+	.global	retain2
+	.section	.data.retain2,"awR"
+	.type	retain2, %object
+retain2:
+	.word	1
+
+	.section	.bss.sretain0,"awR"
+	.type	sretain0, %object
+sretain0:
+	.zero	2
+
+	.section	.bss.sretain1,"awR"
+	.type	sretain1, %object
+sretain1:
+	.zero	2
+
+	.section	.data.sretain2,"aRw"
+	.type	sretain2, %object
+sretain2:
+	.word	1
+
+	.section	.text.fnretain1,"Rax"
+	.global	fnretain1
+	.type	fnretain1, %function
+fnretain1:
+	.word	0
+
+	.section	.text.fndiscard2,"ax"
+	.global	fndiscard2
+	.type	fndiscard2, %function
+fndiscard2:
+	.word	0
+
+	.section	.bss.lsretain0,"awR"
+	.type	lsretain0.2, %object
+lsretain0.2:
+	.zero	2
+
+	.section	.bss.lsretain1,"aRw"
+	.type	lsretain1.1, %object
+lsretain1.1:
+	.zero	2
+
+	.section	.data.lsretain2,"aRw"
+	.type	lsretain2.0, %object
+lsretain2.0:
+	.word	1
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/binutils/testsuite/lib/binutils-common.exp b/binutils/testsuite/lib/binutils-common.exp
index b9a1e6e4bc..a43639bafb 100644
--- a/binutils/testsuite/lib/binutils-common.exp
+++ b/binutils/testsuite/lib/binutils-common.exp
@@ -195,13 +195,15 @@ proc match_target { target } {
 
 # True if the ELF target supports setting the ELF header OSABI field
 # to ELFOSABI_GNU or ELFOSABI_FREEBSD, a requirement for STT_GNU_IFUNC
-# symbol and SHF_GNU_MBIND section support.
+# symbol and SHF_GNU_MBIND or SHF_GNU_RETAIN section support.
 #
 # This generally depends on the target OS only, however there are a
 # number of exceptions for bare metal targets as follows.  The MSP430
 # and Visium targets set OSABI to ELFOSABI_STANDALONE.  Likewise
 # non-EABI ARM targets set OSABI to ELFOSABI_ARM
 #
+# Non-Linux HPPA defaults to ELFOSABI_HPUX.
+#
 # Note that some TI C6X targets use ELFOSABI_C6000_* but one doesn't,
 # so we don't try to sort out tic6x here.  (The effect is that linker
 # testcases will generally need to exclude tic6x or use a -m option.)
@@ -227,6 +229,7 @@ proc supports_gnu_osabi {} {
     }
     if { [istarget "arm*-*-*"]
 	 || [istarget "msp430-*-*"]
+	 || [istarget "hppa-unknown-elf"]
 	 || [istarget "visium-*-*"] } {
 	return 0
     }
diff --git a/gas/NEWS b/gas/NEWS
index 7ae58506ec..2056967a35 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -16,6 +16,12 @@
 
 * Configure with --enable-x86-used-note by default for Linux/x86.
 
+* Add support for the "R" flag in the .section directive.
+  This flag requires ELFOSABI_GNU or ELFOSABI_FREEBSD, and applies the
+  ELF SHF_GNU_RETAIN flag to the specified section.  This flag specifies
+  the section should not be garbage collected by the linker if it is
+  unused.
+
 Changes in 2.35:
 
 * X86 NaCl target support is removed.
diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index b1c99020a3..abc3c5d692 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -517,6 +517,10 @@ struct section_stack
 
 static struct section_stack *section_stack;
 
+/* Create unique input sections for sections with the same name, but different
+   values for the flags in this mask.  */
+#define SEC_ASSEMBLER_SHF_MASK SHF_GNU_RETAIN
+
 static bfd_boolean
 get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
 {
@@ -525,9 +529,12 @@ get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
   const char *group_name = elf_group_name (sec);
   const char *linked_to_symbol_name
     = sec->map_head.linked_to_symbol_name;
-  unsigned int info = elf_section_data (sec)->this_hdr.sh_info;
+  unsigned int sh_info = elf_section_data (sec)->this_hdr.sh_info;
+  bfd_vma sh_flags = (elf_section_data (sec)->this_hdr.sh_flags
+		      & SEC_ASSEMBLER_SHF_MASK);
 
-  return (info == match->info
+  return (sh_info == match->sh_info
+	  && sh_flags == match->sh_flags
 	  && ((bfd_section_flags (sec) & SEC_ASSEMBLER_SECTION_ID)
 	       == (match->flags & SEC_ASSEMBLER_SECTION_ID))
 	  && sec->section_id == match->section_id
@@ -736,7 +743,7 @@ obj_elf_change_section (const char *name,
 	type = bfd_elf_get_default_section_type (flags);
       elf_section_type (sec) = type;
       elf_section_flags (sec) = attr;
-      elf_section_data (sec)->this_hdr.sh_info = match_p->info;
+      elf_section_data (sec)->this_hdr.sh_info = match_p->sh_info;
 
       /* Prevent SEC_HAS_CONTENTS from being inadvertently set.  */
       if (type == SHT_NOBITS)
@@ -857,6 +864,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;
@@ -1250,18 +1260,21 @@ obj_elf_section (int push)
 	      if (ISDIGIT (* input_line_pointer))
 		{
 		  char *t = input_line_pointer;
-		  match.info = strtoul (input_line_pointer,
+		  match.sh_info = strtoul (input_line_pointer,
 					&input_line_pointer, 0);
-		  if (match.info == (unsigned int) -1)
+		  if (match.sh_info == (unsigned int) -1)
 		    {
 		      as_warn (_("unsupported mbind section info: %s"), t);
-		      match.info = 0;
+		      match.sh_info = 0;
 		    }
 		}
 	      else
 		input_line_pointer = save;
 	    }
 
+	  if ((gnu_attr & SHF_GNU_RETAIN) != 0)
+	    match.sh_flags |= SHF_GNU_RETAIN;
+
 	  if (*input_line_pointer == ',')
 	    {
 	      char *save = input_line_pointer;
@@ -1352,11 +1365,12 @@ obj_elf_section (int push)
   obj_elf_change_section (name, type, attr, entsize, &match, linkonce,
 			  push);
 
-  if ((gnu_attr & SHF_GNU_MBIND) != 0)
+  if ((gnu_attr & (SHF_GNU_MBIND | SHF_GNU_RETAIN)) != 0)
     {
       struct elf_backend_data *bed;
+      bfd_boolean mbind_p = (gnu_attr & SHF_GNU_MBIND) != 0;
 
-      if ((attr & SHF_ALLOC) == 0)
+      if (mbind_p && (attr & SHF_ALLOC) == 0)
 	as_bad (_("SHF_ALLOC isn't set for GNU_MBIND section: %s"), name);
 
       bed = (struct elf_backend_data *) get_elf_backend_data (stdoutput);
@@ -1364,9 +1378,12 @@ obj_elf_section (int push)
 	bed->elf_osabi = ELFOSABI_GNU;
       else if (bed->elf_osabi != ELFOSABI_GNU
 	       && bed->elf_osabi != ELFOSABI_FREEBSD)
-	as_bad (_("GNU_MBIND section is supported only by GNU "
-		  "and FreeBSD targets"));
-      elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_mbind;
+	as_bad (_("%s section is supported only by GNU and FreeBSD targets"),
+		mbind_p ? "GNU_MBIND" : "GNU_RETAIN");
+      if (mbind_p)
+	elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_mbind;
+      if ((gnu_attr & SHF_GNU_RETAIN) != 0)
+	elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_retain;
     }
   elf_section_flags (now_seg) |= gnu_attr;
 
diff --git a/gas/config/obj-elf.h b/gas/config/obj-elf.h
index b39a1a1ab6..6eb0a8ede4 100644
--- a/gas/config/obj-elf.h
+++ b/gas/config/obj-elf.h
@@ -106,8 +106,9 @@ struct elf_section_match
 {
   const char *group_name;
   const char *linked_to_symbol_name;
-  unsigned int info;
   unsigned int section_id;
+  unsigned int sh_info;		/* ELF section information.  */
+  bfd_vma sh_flags;		/* ELF section flags.  */
   flagword flags;
 };
 
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index b88c1f9997..31c32a8172 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -6559,6 +6559,9 @@ ignored.  (For compatibility with the ELF version)
 section is not readable (meaningful for PE targets)
 @item 0-9
 single-digit power-of-two section alignment (GNU extension)
+@item R
+retained section (apply SHF_GNU_RETAIN to prevent linker garbage
+collection, GNU ELF extension)
 @end table
 
 If no flags are specified, the default flags depend upon the section name.  If
diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
index 135ade24ec..a0ad2d8dd0 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -257,6 +257,7 @@ if { [is_elf_format] } then {
     run_dump_test "section19"
     run_dump_test "section20"
     run_dump_test "section21"
+    run_dump_test "section22"
     run_dump_test "dwarf2-1" $dump_opts
     run_dump_test "dwarf2-2" $dump_opts
     run_dump_test "dwarf2-3" $dump_opts
diff --git a/gas/testsuite/gas/elf/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/gas/testsuite/gas/elf/section22.d b/gas/testsuite/gas/elf/section22.d
new file mode 100644
index 0000000000..27d9127745
--- /dev/null
+++ b/gas/testsuite/gas/elf/section22.d
@@ -0,0 +1,19 @@
+#readelf: -h -S --wide
+#name: SHF_GNU_RETAIN sections 22
+#notarget: ![supports_gnu_osabi]
+
+#...
+ +OS/ABI: +UNIX - GNU
+#...
+  \[..\] .text[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  AX.*
+#...
+  \[..\] .data[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+#...
+  \[..\] .bss[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+#...
+  \[..\] .bss[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#...
+  \[..\] .data[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#...
+  \[..\] .text[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXR.*
+#pass
diff --git a/gas/testsuite/gas/elf/section22.s b/gas/testsuite/gas/elf/section22.s
new file mode 100644
index 0000000000..6e2b95c1e8
--- /dev/null
+++ b/gas/testsuite/gas/elf/section22.s
@@ -0,0 +1,34 @@
+	.section	.text,"ax",%progbits
+	.global	discard0
+	.type	discard0, %function
+discard0:
+	.word	0
+
+	.section	.data,"aw"
+	.global	discard1
+	.type	discard1, %object
+discard1:
+	.word	1
+
+	.section	.bss,"aw"
+	.global	discard2
+	.type	discard2, %object
+discard2:
+	.zero	2
+
+	.section	.bss,"awR",%nobits
+	.global	retain0
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.section	.data,"awR",%progbits
+	.type	retain1, %object
+retain1:
+	.word	1
+
+	.section	.text,"axR",%progbits
+	.global	retain2
+	.type	retain2, %function
+retain2:
+	.word	0
diff --git a/include/elf/common.h b/include/elf/common.h
index 571e21af29..c01e562c78 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/NEWS b/ld/NEWS
index e4ae43b257..72cdf0edd3 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -15,6 +15,10 @@
   unless you are working on a project that has its own analogue
   of symbol tables that are not reflected in the ELF symtabs.
 
+* Add support for the SHF_GNU_RETAIN ELF section flag.
+  This flag specifies that the section should not be garbage collected by the
+  linker if it is unused.
+
 Changes in 2.35:
 
 * X86 NaCl target support is removed.
diff --git a/ld/ld.texi b/ld/ld.texi
index ee592df6c2..526b642d78 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1787,6 +1787,10 @@ specified either by one of the options @samp{--entry},
 @samp{--undefined}, or @samp{--gc-keep-exported} or by a @code{ENTRY}
 command in the linker script.
 
+As a GNU extension, ELF input sections marked with the
+@code{SHF_GNU_RETAIN} flag will not be garbage collected if they are
+unused.
+
 @kindex --print-gc-sections
 @kindex --no-print-gc-sections
 @cindex garbage collection
@@ -5232,6 +5236,10 @@ The special output section name @samp{/DISCARD/} may be used to discard
 input sections.  Any input sections which are assigned to an output
 section named @samp{/DISCARD/} are not included in the output file.
 
+This can be used to discard input sections marked with the ELF flag
+@code{SHF_GNU_RETAIN}, which would otherwise have been saved from linker
+garbage collection when they are unused.
+
 Note, sections that match the @samp{/DISCARD/} output section will be
 discarded even if they are in an ELF section group which has other
 members which are not being discarded.  This is deliberate.
diff --git a/ld/testsuite/ld-elf/elf.exp b/ld/testsuite/ld-elf/elf.exp
index f2ff0397c7..bd06ab0d39 100644
--- a/ld/testsuite/ld-elf/elf.exp
+++ b/ld/testsuite/ld-elf/elf.exp
@@ -119,6 +119,17 @@ if { [istarget "i?86-*-*"] || [istarget "x86_64-*-*"] } {
     set ASFLAGS "$ASFLAGS -mx86-used-note=no"
 }
 
+# Build libraries required for SHF_GNU_RETAIN tests.
+if { [check_gc_sections_available] && [supports_gnu_osabi] } {
+    run_ld_link_tests [list \
+	[list "Build libretain5.a" "" "" "" \
+	    {retain5lib.s} {} "libretain5.a"] \
+	[list "Build libretain6.a" "" "" "" \
+	    {retain6lib.s} {} "libretain6.a"] \
+	]
+}
+
+
 set test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
 foreach t $test_list {
     # We need to strip the ".d", but can leave the dirname.
diff --git a/ld/testsuite/ld-elf/retain1.s b/ld/testsuite/ld-elf/retain1.s
new file mode 100644
index 0000000000..f7716faabe
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1.s
@@ -0,0 +1,104 @@
+	.global	discard0
+	.section	.bss.discard0,"aw"
+	.type	discard0, %object
+discard0:
+	.zero	2
+
+	.global	discard1
+	.section	.bss.discard1,"aw"
+	.type	discard1, %object
+discard1:
+	.zero	2
+
+	.global	discard2
+	.section	.data.discard2,"aw"
+	.type	discard2, %object
+discard2:
+	.word	1
+
+	.section	.bss.sdiscard0,"aw"
+	.type	sdiscard0, %object
+sdiscard0:
+	.zero	2
+
+	.section	.bss.sdiscard1,"aw"
+	.type	sdiscard1, %object
+sdiscard1:
+	.zero	2
+
+	.section	.data.sdiscard2,"aw"
+	.type	sdiscard2, %object
+sdiscard2:
+	.word	1
+
+	.section	.text.fndiscard0,"ax"
+	.global	fndiscard0
+	.type	fndiscard0, %function
+fndiscard0:
+	.word 0
+
+	.global	retain0
+	.section	.bss.retain0,"awR"
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.global	retain1
+	.section	.bss.retain1,"awR"
+	.type	retain1, %object
+retain1:
+	.zero	2
+
+	.global	retain2
+	.section	.data.retain2,"awR"
+	.type	retain2, %object
+retain2:
+	.word	1
+
+	.section	.bss.sretain0,"awR"
+	.type	sretain0, %object
+sretain0:
+	.zero	2
+
+	.section	.bss.sretain1,"awR"
+	.type	sretain1, %object
+sretain1:
+	.zero	2
+
+	.section	.data.sretain2,"aRw"
+	.type	sretain2, %object
+sretain2:
+	.word	1
+
+	.section	.text.fnretain1,"Rax"
+	.global	fnretain1
+	.type	fnretain1, %function
+fnretain1:
+	.word	0
+
+	.section	.text.fndiscard2,"ax"
+	.global	fndiscard2
+	.type	fndiscard2, %function
+fndiscard2:
+	.word	0
+
+	.section	.bss.lsretain0,"awR"
+	.type	lsretain0.2, %object
+lsretain0.2:
+	.zero	2
+
+	.section	.bss.lsretain1,"aRw"
+	.type	lsretain1.1, %object
+lsretain1.1:
+	.zero	2
+
+	.section	.data.lsretain2,"aRw"
+	.type	lsretain2.0, %object
+lsretain2.0:
+	.word	1
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain1a.d b/ld/testsuite/ld-elf/retain1a.d
new file mode 100644
index 0000000000..75abb9856c
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1a.d
@@ -0,0 +1,28 @@
+#name: SHF_GNU_RETAIN 1a
+#source: retain1.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . fnretain1
+#...
+[0-9a-f]+ . lsretain0.2
+#...
+[0-9a-f]+ . lsretain1.1
+#...
+[0-9a-f]+ . lsretain2.0
+#...
+[0-9a-f]+ . retain0
+#...
+[0-9a-f]+ . retain1
+#...
+[0-9a-f]+ . retain2
+#...
+[0-9a-f]+ . sretain0
+#...
+[0-9a-f]+ . sretain1
+#...
+[0-9a-f]+ . sretain2
+#pass
diff --git a/ld/testsuite/ld-elf/retain1b.d b/ld/testsuite/ld-elf/retain1b.d
new file mode 100644
index 0000000000..815c0150f5
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1b.d
@@ -0,0 +1,11 @@
+#name: SHF_GNU_RETAIN 1b
+#source: retain1.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#nm: -n
+
+#failif
+#...
+[0-9a-f]+ . .*discard.*
+#...
diff --git a/ld/testsuite/ld-elf/retain2.d b/ld/testsuite/ld-elf/retain2.d
new file mode 100644
index 0000000000..11efd6ddb8
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.d
@@ -0,0 +1,6 @@
+#name: SHF_GNU_RETAIN 2 (remove SHF_GNU_RETAIN sections by placing in /DISCARD/)
+#source: retain1.s
+#ld: -e _start -Map=retain2.map --gc-sections --script=retain2.ld
+#map: retain2.map
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
diff --git a/ld/testsuite/ld-elf/retain2.ld b/ld/testsuite/ld-elf/retain2.ld
new file mode 100644
index 0000000000..8ef982753c
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.ld
@@ -0,0 +1,7 @@
+SECTIONS
+{
+  /DISCARD/ :
+  {
+    *(.text.fnretain1)
+  }
+}
diff --git a/ld/testsuite/ld-elf/retain2.map b/ld/testsuite/ld-elf/retain2.map
new file mode 100644
index 0000000000..4028aa1f58
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.map
@@ -0,0 +1,32 @@
+# Test that .text.fnretain1, which has the SHF_GNU_RETAIN flag, can still be
+# explicitly discarded from the output file.
+
+#...
+Discarded input sections
+
+ .text.*
+#...
+ .data.*
+#...
+ .bss.*
+#...
+ .bss.discard0.*
+#...
+ .bss.discard1.*
+#...
+ .data.discard2.*
+#...
+ .bss.sdiscard0.*
+#...
+ .bss.sdiscard1.*
+#...
+ .data.sdiscard2.*
+#...
+ .text.fndiscard0.*
+#...
+ .text.fnretain1.*
+#...
+ .text.fndiscard2.*
+#...
+Memory Configuration
+#pass
diff --git a/ld/testsuite/ld-elf/retain3.d b/ld/testsuite/ld-elf/retain3.d
new file mode 100644
index 0000000000..911f5b7594
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain3.d
@@ -0,0 +1,12 @@
+#name: SHF_GNU_RETAIN 3 (keep sections referenced by retained sections)
+#source: retain3.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . bar
+#...
+[0-9a-f]+ . foo
+#pass
diff --git a/ld/testsuite/ld-elf/retain3.s b/ld/testsuite/ld-elf/retain3.s
new file mode 100644
index 0000000000..ce315cbaa6
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain3.s
@@ -0,0 +1,19 @@
+/* The retention of bar should also prevent foo from being gc'ed, since bar
+   references foo.  */
+	.section	.text.foo,"ax"
+	.global	foo
+	.type	foo, %function
+foo:
+	.word 0
+
+	.section	.text.bar,"axR"
+	.global	bar
+	.type	bar, %function
+bar:
+	.long foo
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain4.d b/ld/testsuite/ld-elf/retain4.d
new file mode 100644
index 0000000000..e94898d681
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain4.d
@@ -0,0 +1,10 @@
+#name: SHF_GNU_RETAIN 4 (keep orphaned sections when not discarding)
+#source: retain4.s
+#ld: -e _start --gc-sections --orphan-handling=place
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . orphaned_fn
+#pass
diff --git a/ld/testsuite/ld-elf/retain4.s b/ld/testsuite/ld-elf/retain4.s
new file mode 100644
index 0000000000..9f350cd3b2
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain4.s
@@ -0,0 +1,13 @@
+/* A section which doesn't match any linker script input section rules but
+   has SHF_GNU_RETAIN applied should not be garbage collected.  */
+	.section	.orphaned_section,"axR"
+	.global	orphaned_fn
+	.type	orphaned_fn, %function
+orphaned_fn:
+	.word 0
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain5.d b/ld/testsuite/ld-elf/retain5.d
new file mode 100644
index 0000000000..378799599e
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5.d
@@ -0,0 +1,12 @@
+#name: SHF_GNU_RETAIN 5 (don't pull SHF_GNU_RETAIN section out of lib)
+#source: retain5main.s
+#ld: --gc-sections -e _start --print-gc-sections -Ltmpdir -lretain5 -Map=retain5.map
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#map: retain5.map
+#DUMPPROG: nm
+
+#failif
+#...
+[0-9a-f]+ . foo
+#...
diff --git a/ld/testsuite/ld-elf/retain5.map b/ld/testsuite/ld-elf/retain5.map
new file mode 100644
index 0000000000..6b97c2a220
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5.map
@@ -0,0 +1,5 @@
+# Check that the library was actually loaded to catch any false PASS.
+
+#...
+LOAD tmpdir/libretain5.a
+#pass
diff --git a/ld/testsuite/ld-elf/retain5lib.s b/ld/testsuite/ld-elf/retain5lib.s
new file mode 100644
index 0000000000..4e83731719
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5lib.s
@@ -0,0 +1,6 @@
+/* The link will fail if foo is included because undefined_sym is not defined.  */
+	.section	.text.foo,"axR"
+	.global	foo
+	.type	foo, %function
+foo:
+	.long undefined_sym
diff --git a/ld/testsuite/ld-elf/retain5main.s b/ld/testsuite/ld-elf/retain5main.s
new file mode 100644
index 0000000000..89a7784d13
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5main.s
@@ -0,0 +1,5 @@
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain6a.d b/ld/testsuite/ld-elf/retain6a.d
new file mode 100644
index 0000000000..92872deffc
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6a.d
@@ -0,0 +1,14 @@
+#name: SHF_GNU_RETAIN 6a (pull section out of lib required by SHF_GNU_RETAIN section)
+#source: retain6main.s
+#ld: --gc-sections -e _start -u bar -Ltmpdir -lretain6
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . bar
+#...
+[0-9a-f]+ . retain_from_lib
+#...
+[0-9a-f]+ . retained_fn
+#pass
diff --git a/ld/testsuite/ld-elf/retain6b.d b/ld/testsuite/ld-elf/retain6b.d
new file mode 100644
index 0000000000..a797bf7837
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6b.d
@@ -0,0 +1,11 @@
+#name: SHF_GNU_RETAIN 6b (pull section out of lib required by SHF_GNU_RETAIN section)
+#source: retain6main.s
+#ld: --gc-sections -e _start -u bar -Ltmpdir -lretain6
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#failif
+#...
+[0-9a-f]+ . .*discard.*
+#...
diff --git a/ld/testsuite/ld-elf/retain6lib.s b/ld/testsuite/ld-elf/retain6lib.s
new file mode 100644
index 0000000000..a393dbac61
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6lib.s
@@ -0,0 +1,17 @@
+	.section	.text.bar,"ax"
+	.global	bar
+	.type	bar, %function
+bar:
+	.word 0
+
+	.section	.text.retain_from_lib,"axR"
+	.global	retain_from_lib
+	.type	retain_from_lib, %function
+retain_from_lib:
+	.word 0
+
+	.section	.text.discard_from_lib,"ax"
+	.global	discard_from_lib
+	.type	discard_from_lib, %function
+discard_from_lib:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain6main.s b/ld/testsuite/ld-elf/retain6main.s
new file mode 100644
index 0000000000..a66c5b3247
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6main.s
@@ -0,0 +1,13 @@
+/* Undefined symbol reference in retained section .text.retained_fn requires
+   symbol definition to be pulled out of library.  */
+	.section	.text.retained_fn,"axR"
+	.global	retained_fn
+	.type	retained_fn, %function
+retained_fn:
+	.long bar
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain7.s b/ld/testsuite/ld-elf/retain7.s
new file mode 100644
index 0000000000..2d80947fbd
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7.s
@@ -0,0 +1,104 @@
+	.section	.bss,"aw"
+	.global	discard0
+	.type	discard0, %object
+discard0:
+	.zero	2
+
+	.section	.bss,"aw"
+	.global	discard1
+	.type	discard1, %object
+discard1:
+	.zero	2
+
+	.section	.data,"aw"
+	.global	discard2
+	.type	discard2, %object
+discard2:
+	.word	1
+
+	.section	.bss,"aw"
+	.type	sdiscard0, %object
+sdiscard0:
+	.zero	2
+
+	.section	.bss,"aw"
+	.type	sdiscard1, %object
+sdiscard1:
+	.zero	2
+
+	.section	.data,"aw"
+	.type	sdiscard2, %object
+sdiscard2:
+	.word	1
+
+	.text
+	.global	fndiscard0
+	.type	fndiscard0, %function
+fndiscard0:
+	.word 0
+
+	.section	.bss,"awR"
+	.global	retain0
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.section	.bss,"awR"
+	.global	retain1
+	.type	retain1, %object
+retain1:
+	.zero	2
+
+	.section	.data,"awR"
+	.global	retain2
+	.type	retain2, %object
+retain2:
+	.word	1
+
+	.section	.bss,"awR"
+	.type	sretain0, %object
+sretain0:
+	.zero	2
+
+	.section	.bss,"awR"
+	.type	sretain1, %object
+sretain1:
+	.zero	2
+
+	.section	.data,"aRw"
+	.type	sretain2, %object
+sretain2:
+	.word	1
+
+	.section	.text,"Rax"
+	.global	fnretain1
+	.type	fnretain1, %function
+fnretain1:
+	.word	0
+
+	.section	.text,"ax"
+	.global	fndiscard2
+	.type	fndiscard2, %function
+fndiscard2:
+	.word	0
+
+	.section	.bss,"awR"
+	.type	lsretain0.2, %object
+lsretain0.2:
+	.zero	2
+
+	.section	.bss,"aRw"
+	.type	lsretain1.1, %object
+lsretain1.1:
+	.zero	2
+
+	.section	.data,"aRw"
+	.type	lsretain2.0, %object
+lsretain2.0:
+	.word	1
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain7a.d b/ld/testsuite/ld-elf/retain7a.d
new file mode 100644
index 0000000000..055bb74da9
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7a.d
@@ -0,0 +1,28 @@
+#name: SHF_GNU_RETAIN 7a (flag applied to default section names)
+#source: retain7.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . fnretain1
+#...
+[0-9a-f]+ . lsretain0.2
+#...
+[0-9a-f]+ . lsretain1.1
+#...
+[0-9a-f]+ . lsretain2.0
+#...
+[0-9a-f]+ . retain0
+#...
+[0-9a-f]+ . retain1
+#...
+[0-9a-f]+ . retain2
+#...
+[0-9a-f]+ . sretain0
+#...
+[0-9a-f]+ . sretain1
+#...
+[0-9a-f]+ . sretain2
+#pass
diff --git a/ld/testsuite/ld-elf/retain7b.d b/ld/testsuite/ld-elf/retain7b.d
new file mode 100644
index 0000000000..f268047c35
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7b.d
@@ -0,0 +1,11 @@
+#name: SHF_GNU_RETAIN 7b (flag applied to default section names)
+#source: retain7.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#nm: -n
+
+#failif
+#...
+[0-9a-f]+ . .*discard.*
+#...
-- 
2.28.0


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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-10-01 10:50   ` Jozef Lawrynowicz
@ 2020-10-01 11:39     ` Alan Modra
  2020-10-02 12:30       ` Jozef Lawrynowicz
  0 siblings, 1 reply; 22+ messages in thread
From: Alan Modra @ 2020-10-01 11:39 UTC (permalink / raw)
  To: H.J. Lu, Binutils

On Thu, Oct 01, 2020 at 11:50:33AM +0100, Jozef Lawrynowicz wrote:
> --- a/bfd/elflink.c
> +++ b/bfd/elflink.c
> @@ -14102,7 +14102,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)))

Flag bits in SHF_MASKOS depend on OS, so this needs a test of OSABI.
That can be done by checking elf_tdata (sub)->has_gnu_osabi for the
appropriate bit.

>  	  {
>  	    if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
>  	      return FALSE;
> diff --git a/binutils/NEWS b/binutils/NEWS
> index c0dc73d7d8..6c7d3f3953 100644
> --- a/binutils/NEWS
> +++ b/binutils/NEWS
> @@ -4,6 +4,10 @@
>    symbol names.  In addition the --demangle=<style>, --no-demangle,
>    --recurse-limit and --no-recurse-limit options are also now availale.
>  
> +* Add support for the SHF_GNU_RETAIN ELF section flag.
> +  This flag specifies that the section should not be garbage collected by the
> +  linker if it is unused.

I would drop "if it is unused".  The phrase doesn't really add
anything to a user's understanding.

> --- a/binutils/readelf.c
> +++ b/binutils/readelf.c
> @@ -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;

Again, interpretation of the bit depends on e_ident[EI_OSABI].
SHF_GNU_RETAIN should only be printed for ELFOSABI_GNU and
ELFOSABI_FREEBSD.

-- 
Alan Modra
Australia Development Lab, IBM

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-09-30 10:18           ` Jozef Lawrynowicz
  2020-09-30 14:01             ` H.J. Lu
@ 2020-10-01 19:22             ` Fangrui Song
  2020-10-01 19:53               ` H.J. Lu
  2020-10-02 12:44               ` Jozef Lawrynowicz
  1 sibling, 2 replies; 22+ messages in thread
From: Fangrui Song @ 2020-10-01 19:22 UTC (permalink / raw)
  To: Roland McGrath, H.J. Lu, Binutils Development, gnu-gabi,
	Peter Smith, George Rimar, James Henderson, James Y Knight

On 2020-09-30, Jozef Lawrynowicz wrote:
>On Tue, Sep 29, 2020 at 05:10:09PM -0700, Roland McGrath wrote:
>> Since group semantics mean that if any section in a group is retained the
>> whole group must be retained, it seems to me that making the feature a
>> group flag rather than a section flag makes sense. I don't think it really
>> has any downside. It's a little bit more structure to generate a group but
>> everything already knows how to do it so that should be no problem.  While
>> it is true that multiple sections with the same name and different
>> attributes should already be fine, the place where multiple different
>> sections of the same name are usually seen today is when each different
>> section reusing a name is in a different group from the other sections with
>> the same name.
>>
>
>Let's assume:
>  GRP_RETAIN
>    Sections in a group with this flag set should always be included in
>    the linked object, even if they appear unused.
>
>One issue I have with the group method is conceptual; groups are supposed
>to be used to group related sections. They are related because of their
>meaning from the application perspective, not because of their metadata
>(i.e. sections to be retained are related by their metadata because they
>all should be retained).
>
>Just because groups have a side effect that can be leveraged to
>get a section to be retained in the final link, why does that mean we
>need to leverage that property when it it's not actually the simplest or
>most obvious way to implement the new behavior?
>
>SHF_GNU_RETAIN describes in the simplest possible way that the section
>should be retained in the final link, without relying on other
>constructs.
>
>Just because groups are discarded or retained as a group, doesn't mean
>we need to leverage groups to try and implement retention or discarding
>functionality.
>
>Why wasn't SHF_EXCLUDE implemented as a group flag? After all, groups
>are included or excluded from the link together.
>  GRP_EXCLUDE
>    Sections in a group with GRP_EXCLUDE set should be discarded from
>    the link.
>
>I mean, you could kind of use groups for anything when you decide
>grouping sections by metadata is OK.
>Why define SHT_NOBITS when you can create:
>  GRP_NOBITS
>    Sections in this group occupy no space in the file. They must have
>    type SHT_PROGBITS.
>
>Retention of a section is a property of the section. We are misusing ELF
>constructs by using groups to indicate an arbitrary section needs to be
>retained.
>
>Another issue (if more is needed) is about how to name the groups.
>* If it is mandated that GRP_RETAIN groups have the same name e.g.
>  "grp_retain", that means you can't put a section you want to
>  retain in a different logical group that makes sense from the
>  application perspective. So the other sections you would want to put
>  in a group with the retained section need to all be put in a bundle
>  with all the other GRP_RETAIN sections.
>* If GRP_RETAIN groups can have any name, so you can have multiple
>  GRP_RETAIN groups, how does the compiler decide how to name the
>  groups? It seems like it would be a mess. "grp_retain0", "grp_retain2"
>  ... "grp_retain10" from one object file, "grp_retain0"...
>  "grp_retain5" from another. Extra processing in the
>  linker to clean up these group names and keep them unique would be
>  required when performing a relocatable link.
>
>As a general point, what if I decide that there's enough pressure from
>the anti-SHF_GNU_RETAIN side that I change the implementation to use
>groups. But then those who already backed the flag prefer that method
>over using groups think the implementation should not have been changed.
>
>I feel like we already got enough backing for SHF_GNU_RETAIN between the
>GNU gABI and Binutils discussions. I understand, and welcome, more
>feedback, but I haven't been convinced any other method is obviously
>better than SHF_GNU_RETAIN, so why change it?
>
>I'm not saying it's possible to quantify which mechanism for "retain" is
>best, but SHF_GNU_RETAIN is the simplest, most obvious, and easiest to
>understand. Surely that gives it top marks?
>
>I'm also yet to hear one convincing reason why SHF_GNU_RETAIN is bad.
>As far as I can tell, the main argument against it stems from the fact
>that you can have two input sections with the same name but different
>SHF_GNU_RETAIN flag states. Not only is this a non-issue, groups have
>exactly the same problem!
>
>It would be great if a global maintainer to chime in on whether the
>attached patch is acceptable, because otherwise we are going to go back
>and forth forever.
>
>Thanks,
>Jozef

Hi Jozef,

I have checked with a few folks on the LLVM side. James Henderson and James Y
Knight seem to prefer a section flag to other mechanism. I prefer a
section flag, too (I was on the fence and wanted the alternatives to be considered).

About the section flag 'R' in assembly:

I'd still prefer an error to not add another exception to https://sourceware.org/pipermail/binutils/2020-February/109945.html
(a consensus GNU as and LLVM's integrated assembler have reached)

   .section retain,"a",@progbits
   .section retain,"aR",@progbits  # error for section flags change

If a separate section is desired, I'd prefer an explicit ,unique,0 or ,unique,1 or ...

   .section retain,"a",@progbits
   .section retain,"aR",@progbits,unique,0   # 'unique' is a binutils 2.35 feature (available in LLVM for a while)


About the use case in GCC (and probably Clang in the future):

   // a.h
   __attribute__((section("sec"))) inline void bar() { ... }

   // a.c
   #include "a.h"
   __attribute__((section("sec"), retain))   // retain may be the pre-existing used.
   void foo() { ... }

Perhaps there needs a function attribute to lower to ,unique,1 in assembly.

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-10-01 19:22             ` Fangrui Song
@ 2020-10-01 19:53               ` H.J. Lu
  2020-10-02 12:44               ` Jozef Lawrynowicz
  1 sibling, 0 replies; 22+ messages in thread
From: H.J. Lu @ 2020-10-01 19:53 UTC (permalink / raw)
  To: Fangrui Song
  Cc: Roland McGrath, Binutils Development, GNU gABI gnu-gabi,
	Peter Smith, George Rimar, James Henderson, James Y Knight

On Thu, Oct 1, 2020 at 12:22 PM Fangrui Song <i@maskray.me> wrote:
>
> On 2020-09-30, Jozef Lawrynowicz wrote:
> >On Tue, Sep 29, 2020 at 05:10:09PM -0700, Roland McGrath wrote:
> >> Since group semantics mean that if any section in a group is retained the
> >> whole group must be retained, it seems to me that making the feature a
> >> group flag rather than a section flag makes sense. I don't think it really
> >> has any downside. It's a little bit more structure to generate a group but
> >> everything already knows how to do it so that should be no problem.  While
> >> it is true that multiple sections with the same name and different
> >> attributes should already be fine, the place where multiple different
> >> sections of the same name are usually seen today is when each different
> >> section reusing a name is in a different group from the other sections with
> >> the same name.
> >>
> >
> >Let's assume:
> >  GRP_RETAIN
> >    Sections in a group with this flag set should always be included in
> >    the linked object, even if they appear unused.
> >
> >One issue I have with the group method is conceptual; groups are supposed
> >to be used to group related sections. They are related because of their
> >meaning from the application perspective, not because of their metadata
> >(i.e. sections to be retained are related by their metadata because they
> >all should be retained).
> >
> >Just because groups have a side effect that can be leveraged to
> >get a section to be retained in the final link, why does that mean we
> >need to leverage that property when it it's not actually the simplest or
> >most obvious way to implement the new behavior?
> >
> >SHF_GNU_RETAIN describes in the simplest possible way that the section
> >should be retained in the final link, without relying on other
> >constructs.
> >
> >Just because groups are discarded or retained as a group, doesn't mean
> >we need to leverage groups to try and implement retention or discarding
> >functionality.
> >
> >Why wasn't SHF_EXCLUDE implemented as a group flag? After all, groups
> >are included or excluded from the link together.
> >  GRP_EXCLUDE
> >    Sections in a group with GRP_EXCLUDE set should be discarded from
> >    the link.
> >
> >I mean, you could kind of use groups for anything when you decide
> >grouping sections by metadata is OK.
> >Why define SHT_NOBITS when you can create:
> >  GRP_NOBITS
> >    Sections in this group occupy no space in the file. They must have
> >    type SHT_PROGBITS.
> >
> >Retention of a section is a property of the section. We are misusing ELF
> >constructs by using groups to indicate an arbitrary section needs to be
> >retained.
> >
> >Another issue (if more is needed) is about how to name the groups.
> >* If it is mandated that GRP_RETAIN groups have the same name e.g.
> >  "grp_retain", that means you can't put a section you want to
> >  retain in a different logical group that makes sense from the
> >  application perspective. So the other sections you would want to put
> >  in a group with the retained section need to all be put in a bundle
> >  with all the other GRP_RETAIN sections.
> >* If GRP_RETAIN groups can have any name, so you can have multiple
> >  GRP_RETAIN groups, how does the compiler decide how to name the
> >  groups? It seems like it would be a mess. "grp_retain0", "grp_retain2"
> >  ... "grp_retain10" from one object file, "grp_retain0"...
> >  "grp_retain5" from another. Extra processing in the
> >  linker to clean up these group names and keep them unique would be
> >  required when performing a relocatable link.
> >
> >As a general point, what if I decide that there's enough pressure from
> >the anti-SHF_GNU_RETAIN side that I change the implementation to use
> >groups. But then those who already backed the flag prefer that method
> >over using groups think the implementation should not have been changed.
> >
> >I feel like we already got enough backing for SHF_GNU_RETAIN between the
> >GNU gABI and Binutils discussions. I understand, and welcome, more
> >feedback, but I haven't been convinced any other method is obviously
> >better than SHF_GNU_RETAIN, so why change it?
> >
> >I'm not saying it's possible to quantify which mechanism for "retain" is
> >best, but SHF_GNU_RETAIN is the simplest, most obvious, and easiest to
> >understand. Surely that gives it top marks?
> >
> >I'm also yet to hear one convincing reason why SHF_GNU_RETAIN is bad.
> >As far as I can tell, the main argument against it stems from the fact
> >that you can have two input sections with the same name but different
> >SHF_GNU_RETAIN flag states. Not only is this a non-issue, groups have
> >exactly the same problem!
> >
> >It would be great if a global maintainer to chime in on whether the
> >attached patch is acceptable, because otherwise we are going to go back
> >and forth forever.
> >
> >Thanks,
> >Jozef
>
> Hi Jozef,
>
> I have checked with a few folks on the LLVM side. James Henderson and James Y
> Knight seem to prefer a section flag to other mechanism. I prefer a
> section flag, too (I was on the fence and wanted the alternatives to be considered).
>
> About the section flag 'R' in assembly:
>
> I'd still prefer an error to not add another exception to https://sourceware.org/pipermail/binutils/2020-February/109945.html
> (a consensus GNU as and LLVM's integrated assembler have reached)
>
>    .section retain,"a",@progbits
>    .section retain,"aR",@progbits  # error for section flags change
>
> If a separate section is desired, I'd prefer an explicit ,unique,0 or ,unique,1 or ...
>
>    .section retain,"a",@progbits
>    .section retain,"aR",@progbits,unique,0   # 'unique' is a binutils 2.35 feature (available in LLVM for a while)

I don't think it is desirable since it requires tracking the unique number
which isn't an issue with the compiler.  But it is a hassle for handwritten
assembly codes with #include.

>
> About the use case in GCC (and probably Clang in the future):
>
>    // a.h
>    __attribute__((section("sec"))) inline void bar() { ... }
>
>    // a.c
>    #include "a.h"
>    __attribute__((section("sec"), retain))   // retain may be the pre-existing used.
>    void foo() { ... }
>
> Perhaps there needs a function attribute to lower to ,unique,1 in assembly.



-- 
H.J.

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-10-01 11:39     ` Alan Modra
@ 2020-10-02 12:30       ` Jozef Lawrynowicz
  2020-10-02 12:33         ` H.J. Lu
  2020-10-02 14:11         ` Alan Modra
  0 siblings, 2 replies; 22+ messages in thread
From: Jozef Lawrynowicz @ 2020-10-02 12:30 UTC (permalink / raw)
  To: Alan Modra; +Cc: H.J. Lu, Binutils

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

On Thu, Oct 01, 2020 at 09:09:07PM +0930, Alan Modra via Binutils wrote:
> On Thu, Oct 01, 2020 at 11:50:33AM +0100, Jozef Lawrynowicz wrote:
> > --- a/bfd/elflink.c
> > +++ b/bfd/elflink.c
> > @@ -14102,7 +14102,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)))
> 
> Flag bits in SHF_MASKOS depend on OS, so this needs a test of OSABI.
> That can be done by checking elf_tdata (sub)->has_gnu_osabi for the
> appropriate bit.
> 

Fixed the two OSABI issues in the attached patch.

I also added handling of numeric flag values in the SHF_MASKOS range for
the .section directive for some OSABIs.
There are new GAS tests to test this behavior for targets that either do
or do not support the GNU OSABI.

> >  	  {
> >  	    if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
> >  	      return FALSE;
> > diff --git a/binutils/NEWS b/binutils/NEWS
> > index c0dc73d7d8..6c7d3f3953 100644
> > --- a/binutils/NEWS
> > +++ b/binutils/NEWS
> > @@ -4,6 +4,10 @@
> >    symbol names.  In addition the --demangle=<style>, --no-demangle,
> >    --recurse-limit and --no-recurse-limit options are also now availale.
> >  
> > +* Add support for the SHF_GNU_RETAIN ELF section flag.
> > +  This flag specifies that the section should not be garbage collected by the
> > +  linker if it is unused.
> 
> I would drop "if it is unused".  The phrase doesn't really add
> anything to a user's understanding.
> 

I don't really have a strong opinion either way, but I thought "if it is
unused" might be helpful to add to the description since "garbage
collection" is not precisely defined in ELF.

However, since the flag is only part of the GNU gABI, and the GNU linker
supports "garbage collection", it probably does not need the extra
clarification, so I'm fine with removing it.

Since there was consensus for that explicit wording on the gABI thread
(https://sourceware.org/pipermail/gnu-gabi/2020q3/000449.htm), I'll wait
until next week to see if there are any objections before adjusting it.

Thanks,
Jozef

> > --- a/binutils/readelf.c
> > +++ b/binutils/readelf.c
> > @@ -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;
> 
> Again, interpretation of the bit depends on e_ident[EI_OSABI].
> SHF_GNU_RETAIN should only be printed for ELFOSABI_GNU and
> ELFOSABI_FREEBSD.
> 
> -- 
> Alan Modra
> Australia Development Lab, IBM

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

From cbac6da160859cd4ffbfc85d06774d1962f5faa3 Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@mittosystems.com>
Date: Thu, 1 Oct 2020 11:49:04 +0100
Subject: [PATCH] Support SHF_GNU_RETAIN ELF section flag

The SHF_GNU_RETAIN section flag is an extension to the GNU ELF OSABI.
It is defined as follows:

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

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

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

Note that there is not a direct mapping of SHF_GNU_RETAIN to the BFD
section flag SEC_KEEP. This would prevent the user being able to
explicitly remove an SHF_GNU_RETAIN section by placing it in /DISCARD/.

bfd/ChangeLog:

2020-10-02  H.J. Lu  <hongjiu.lu@intel.com>
	Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* elf-bfd.h (enum elf_gnu_osabi): Add elf_gnu_osabi_retain.
	(struct elf_obj_tdata): Increase has_gnu_osabi to 4 bits.
	* elf.c (_bfd_elf_make_section_from_shdr): Set elf_gnu_osabi_retain
	for SHF_GNU_RETAIN.
	(_bfd_elf_final_write_processing): Report if SHF_GNU_RETAIN is
	not supported by the OSABI.
	Adjust error messages.
	* elflink.c (bfd_elf_gc_sections): gc_mark the section if
	SHF_GNU_RETAIN is set.

binutils/ChangeLog:

2020-10-02  Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* NEWS: Announce SHF_GNU_RETAIN.
	* readelf.c (get_elf_section_flags): Handle SHF_GNU_RETAIN.
	Recognize SHF_GNU_RETAIN and SHF_GNU_MBIND only for supported OSABIs.
	* testsuite/binutils-all/readelf.exp: Run new test.
	Don't run run_dump_test when there isn't an assembler available.
	* testsuite/lib/binutils-common.exp (supports_gnu_osabi): Adjust
	comment.
	* testsuite/binutils-all/retain1.d: New test.
	* testsuite/binutils-all/retain1.s: New test.

gas/ChangeLog:

2020-10-02  H.J. Lu  <hongjiu.lu@intel.com>
	Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* NEWS: Announce SHF_GNU_RETAIN.
	* config/obj-elf.c (SEC_ASSEMBLER_SHF_MASK): New.
	(get_section): Use SEC_ASSEMBLER_SHF_MASK.
	(obj_elf_change_section): Update struct member name.
	(obj_elf_parse_section_letters): Handle 'R' flag.
	Handle numeric flag values within the SHF_MASKOS range.
	(obj_elf_section): Set elf_gnu_osabi_retain
	for SHF_GNU_RETAIN.
	* config/obj-elf.h (struct elf_section_match): Adjust "info" member
	name to "sh_info".  Add "sh_flags" member.
	* doc/as.texi (Section): Document 'R' flag.
	* testsuite/gas/elf/elf.exp: Run new tests.
	* testsuite/gas/elf/section10.d: Don't test SHF_GNU_RETAIN bit of
	section flag.
	* testsuite/gas/elf/section10.s: Don't set SHF_GNU_RETAIN bit of
	section flag.
	* testsuite/gas/elf/section22.d: New test.
	* testsuite/gas/elf/section22.s: New test.
	* testsuite/gas/elf/section23.s: New test.
	* testsuite/gas/elf/section23a.d: New test.
	* testsuite/gas/elf/section23b.d: New test.
	* testsuite/gas/elf/section23b.err: New test.

include/ChangeLog:

2020-10-02  Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* elf/common.h (SHF_GNU_RETAIN): Define.

ld/ChangeLog:

2020-10-02  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
	H.J. Lu  <hongjiu.lu@intel.com>

	* NEWS: Announce SHF_GNU_RETAIN.
	* ld.texi (garbage collection): Document SHF_GNU_RETAIN.
	(Output Section Discarding): Likewise.
	* testsuite/ld-elf/elf.exp: Run new tests.
	* testsuite/ld-elf/retain1.s: New test.
	* testsuite/ld-elf/retain1a.d: New test.
	* testsuite/ld-elf/retain1b.d: New test.
	* testsuite/ld-elf/retain2.d: New test.
	* testsuite/ld-elf/retain2.ld: New test.
	* testsuite/ld-elf/retain2.map: New test.
	* testsuite/ld-elf/retain3.d: New test.
	* testsuite/ld-elf/retain3.s: New test.
	* testsuite/ld-elf/retain4.d: New test.
	* testsuite/ld-elf/retain4.s: New test.
	* testsuite/ld-elf/retain5.d: New test.
	* testsuite/ld-elf/retain5.map: New test.
	* testsuite/ld-elf/retain5lib.s: New test.
	* testsuite/ld-elf/retain5main.s: New test.
	* testsuite/ld-elf/retain6a.d: New test.
	* testsuite/ld-elf/retain6b.d: New test.
	* testsuite/ld-elf/retain6lib.s: New test.
	* testsuite/ld-elf/retain6main.s: New test.
	* testsuite/ld-elf/retain7.s: New test.
	* testsuite/ld-elf/retain7a.d: New test.
	* testsuite/ld-elf/retain7b.d: New test.
---
 bfd/elf-bfd.h                               |   9 +-
 bfd/elf.c                                   |  17 +++-
 bfd/elflink.c                               |   4 +-
 binutils/NEWS                               |   4 +
 binutils/readelf.c                          |  21 +++-
 binutils/testsuite/binutils-all/readelf.exp |   6 +-
 binutils/testsuite/binutils-all/retain1.d   |  18 ++++
 binutils/testsuite/binutils-all/retain1.s   | 104 ++++++++++++++++++++
 binutils/testsuite/lib/binutils-common.exp  |   5 +-
 gas/NEWS                                    |   6 ++
 gas/config/obj-elf.c                        |  65 +++++++++---
 gas/config/obj-elf.h                        |   3 +-
 gas/doc/as.texi                             |   3 +
 gas/testsuite/gas/elf/elf.exp               |   3 +
 gas/testsuite/gas/elf/section10.d           |   4 +-
 gas/testsuite/gas/elf/section10.s           |   4 +-
 gas/testsuite/gas/elf/section22.d           |  19 ++++
 gas/testsuite/gas/elf/section22.s           |  34 +++++++
 gas/testsuite/gas/elf/section23.s           |  11 +++
 gas/testsuite/gas/elf/section23a.d          |  11 +++
 gas/testsuite/gas/elf/section23b.d          |   6 ++
 gas/testsuite/gas/elf/section23b.err        |   2 +
 include/elf/common.h                        |   1 +
 ld/NEWS                                     |   4 +
 ld/ld.texi                                  |   8 ++
 ld/testsuite/ld-elf/elf.exp                 |  11 +++
 ld/testsuite/ld-elf/retain1.s               | 104 ++++++++++++++++++++
 ld/testsuite/ld-elf/retain1a.d              |  28 ++++++
 ld/testsuite/ld-elf/retain1b.d              |  11 +++
 ld/testsuite/ld-elf/retain2.d               |   6 ++
 ld/testsuite/ld-elf/retain2.ld              |   7 ++
 ld/testsuite/ld-elf/retain2.map             |  32 ++++++
 ld/testsuite/ld-elf/retain3.d               |  12 +++
 ld/testsuite/ld-elf/retain3.s               |  19 ++++
 ld/testsuite/ld-elf/retain4.d               |  10 ++
 ld/testsuite/ld-elf/retain4.s               |  13 +++
 ld/testsuite/ld-elf/retain5.d               |  12 +++
 ld/testsuite/ld-elf/retain5.map             |   5 +
 ld/testsuite/ld-elf/retain5lib.s            |   6 ++
 ld/testsuite/ld-elf/retain5main.s           |   5 +
 ld/testsuite/ld-elf/retain6a.d              |  14 +++
 ld/testsuite/ld-elf/retain6b.d              |  11 +++
 ld/testsuite/ld-elf/retain6lib.s            |  17 ++++
 ld/testsuite/ld-elf/retain6main.s           |  13 +++
 ld/testsuite/ld-elf/retain7.s               | 104 ++++++++++++++++++++
 ld/testsuite/ld-elf/retain7a.d              |  28 ++++++
 ld/testsuite/ld-elf/retain7b.d              |  11 +++
 47 files changed, 822 insertions(+), 29 deletions(-)
 create mode 100644 binutils/testsuite/binutils-all/retain1.d
 create mode 100644 binutils/testsuite/binutils-all/retain1.s
 create mode 100644 gas/testsuite/gas/elf/section22.d
 create mode 100644 gas/testsuite/gas/elf/section22.s
 create mode 100644 gas/testsuite/gas/elf/section23.s
 create mode 100644 gas/testsuite/gas/elf/section23a.d
 create mode 100644 gas/testsuite/gas/elf/section23b.d
 create mode 100644 gas/testsuite/gas/elf/section23b.err
 create mode 100644 ld/testsuite/ld-elf/retain1.s
 create mode 100644 ld/testsuite/ld-elf/retain1a.d
 create mode 100644 ld/testsuite/ld-elf/retain1b.d
 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.d
 create mode 100644 ld/testsuite/ld-elf/retain3.s
 create mode 100644 ld/testsuite/ld-elf/retain4.d
 create mode 100644 ld/testsuite/ld-elf/retain4.s
 create mode 100644 ld/testsuite/ld-elf/retain5.d
 create mode 100644 ld/testsuite/ld-elf/retain5.map
 create mode 100644 ld/testsuite/ld-elf/retain5lib.s
 create mode 100644 ld/testsuite/ld-elf/retain5main.s
 create mode 100644 ld/testsuite/ld-elf/retain6a.d
 create mode 100644 ld/testsuite/ld-elf/retain6b.d
 create mode 100644 ld/testsuite/ld-elf/retain6lib.s
 create mode 100644 ld/testsuite/ld-elf/retain6main.s
 create mode 100644 ld/testsuite/ld-elf/retain7.s
 create mode 100644 ld/testsuite/ld-elf/retain7a.d
 create mode 100644 ld/testsuite/ld-elf/retain7b.d

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 140a98594d..ffb75f7919 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1897,14 +1897,15 @@ struct output_elf_obj_tdata
   bfd_boolean flags_init;
 };
 
-/* Indicate if the bfd contains SHF_GNU_MBIND sections or symbols that
-   have the STT_GNU_IFUNC symbol type or STB_GNU_UNIQUE binding.  Used
-   to set the osabi field in the ELF header structure.  */
+/* Indicate if the bfd contains SHF_GNU_MBIND/SHF_GNU_RETAIN sections or
+   symbols that have the STT_GNU_IFUNC symbol type or STB_GNU_UNIQUE
+   binding.  Used to set the osabi field in the ELF header structure.  */
 enum elf_gnu_osabi
 {
   elf_gnu_osabi_mbind = 1 << 0,
   elf_gnu_osabi_ifunc = 1 << 1,
   elf_gnu_osabi_unique = 1 << 2,
+  elf_gnu_osabi_retain = 1 << 3,
 };
 
 typedef struct elf_section_list
@@ -2034,7 +2035,7 @@ struct elf_obj_tdata
   ENUM_BITFIELD (dynamic_lib_link_class) dyn_lib_class : 4;
 
   /* Whether the bfd uses OS specific bits that require ELFOSABI_GNU.  */
-  ENUM_BITFIELD (elf_gnu_osabi) has_gnu_osabi : 3;
+  ENUM_BITFIELD (elf_gnu_osabi) has_gnu_osabi : 4;
 
   /* Whether if the bfd contains the GNU_PROPERTY_NO_COPY_ON_PROTECTED
      property.  */
diff --git a/bfd/elf.c b/bfd/elf.c
index 00594020c9..5daf8ec0f5 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1068,9 +1068,12 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
       /* FIXME: We should not recognize SHF_GNU_MBIND for ELFOSABI_NONE,
 	 but binutils as of 2019-07-23 did not set the EI_OSABI header
 	 byte.  */
-    case ELFOSABI_NONE:
     case ELFOSABI_GNU:
     case ELFOSABI_FREEBSD:
+      if ((hdr->sh_flags & SHF_GNU_RETAIN) != 0)
+	elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_retain;
+      /* Fall through */
+    case ELFOSABI_NONE:
       if ((hdr->sh_flags & SHF_GNU_MBIND) != 0)
 	elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_mbind;
       break;
@@ -12476,11 +12479,17 @@ _bfd_elf_final_write_processing (bfd *abfd)
 	       && i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_FREEBSD)
 	{
 	  if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_mbind)
-	    _bfd_error_handler (_("GNU_MBIND section is unsupported"));
+	    _bfd_error_handler (_("GNU_MBIND section is supported only by GNU "
+				  "and FreeBSD targets"));
 	  if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_ifunc)
-	    _bfd_error_handler (_("symbol type STT_GNU_IFUNC is unsupported"));
+	    _bfd_error_handler (_("symbol type STT_GNU_IFUNC is supported "
+				  "only by GNU and FreeBSD targets"));
 	  if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_unique)
-	    _bfd_error_handler (_("symbol binding STB_GNU_UNIQUE is unsupported"));
+	    _bfd_error_handler (_("symbol binding STB_GNU_UNIQUE is supported "
+				  "only by GNU and FreeBSD targets"));
+	  if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_retain)
+	    _bfd_error_handler (_("GNU_RETAIN section is supported "
+				  "only by GNU and FreeBSD targets"));
 	  bfd_set_error (bfd_error_sorry);
 	  return FALSE;
 	}
diff --git a/bfd/elflink.c b/bfd/elflink.c
index b6937293e8..6efd181a32 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -14102,7 +14102,9 @@ 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_tdata (sub)->has_gnu_osabi & elf_gnu_osabi_retain
+		    && elf_section_flags (o) & SHF_GNU_RETAIN)))
 	  {
 	    if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
 	      return FALSE;
diff --git a/binutils/NEWS b/binutils/NEWS
index c0dc73d7d8..6c7d3f3953 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -4,6 +4,10 @@
   symbol names.  In addition the --demangle=<style>, --no-demangle,
   --recurse-limit and --no-recurse-limit options are also now availale.
 
+* Add support for the SHF_GNU_RETAIN ELF section flag.
+  This flag specifies that the section should not be garbage collected by the
+  linker if it is unused.
+
 Changes in 2.35:
 
 * Changed readelf's display of symbol names when wide mode is not enabled.
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 9ba4e29a65..5b3e508aef 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)
@@ -6009,7 +6011,6 @@ get_elf_section_flags (Filedata * filedata, bfd_vma sh_flags)
 	    case SHF_TLS:		sindex = 9; break;
 	    case SHF_EXCLUDE:		sindex = 18; break;
 	    case SHF_COMPRESSED:	sindex = 20; break;
-	    case SHF_GNU_MBIND:		sindex = 24; break;
 
 	    default:
 	      sindex = -1;
@@ -6063,6 +6064,23 @@ get_elf_section_flags (Filedata * filedata, bfd_vma sh_flags)
 		  break;
 
 		default:
+		  switch (filedata->file_header.e_ident[EI_OSABI])
+		    {
+		    case ELFOSABI_GNU:
+		    case ELFOSABI_FREEBSD:
+		      if (flag == SHF_GNU_RETAIN)
+			sindex = 26;
+		      /* Fall through */
+		    case ELFOSABI_NONE:
+		      if (flag == SHF_GNU_MBIND)
+			/* We should not recognize SHF_GNU_MBIND for
+			   ELFOSABI_NONE, but binutils as of 2019-07-23 did
+			   not set the EI_OSABI header byte.  */
+			sindex = 24;
+		      break;
+		    default:
+		      break;
+		    }
 		  break;
 		}
 	    }
@@ -6108,6 +6126,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/binutils/testsuite/binutils-all/readelf.exp b/binutils/testsuite/binutils-all/readelf.exp
index 1fb36ae5c4..6dea09e305 100644
--- a/binutils/testsuite/binutils-all/readelf.exp
+++ b/binutils/testsuite/binutils-all/readelf.exp
@@ -364,8 +364,12 @@ readelf_wi_test
 readelf_compressed_wa_test
 
 readelf_dump_test
-run_dump_test "pr25543"
 
+# These dump tests require an assembler.
+if {[which $AS] != 0} then {
+    run_dump_test "pr25543"
+    run_dump_test "retain1"
+}
 
 # PR 13482 - Check for off-by-one errors when dumping .note sections.
 if {![binutils_assemble $srcdir/$subdir/version.s tmpdir/version.o]} then {
diff --git a/binutils/testsuite/binutils-all/retain1.d b/binutils/testsuite/binutils-all/retain1.d
new file mode 100644
index 0000000000..01cd32a475
--- /dev/null
+++ b/binutils/testsuite/binutils-all/retain1.d
@@ -0,0 +1,18 @@
+#source: retain1.s
+#readelf: -S --wide
+#name: readelf SHF_GNU_RETAIN
+#notarget: ![supports_gnu_osabi]
+
+#...
+  \[[ 0-9]+\] .bss.retain0.*WAR.*
+  \[[ 0-9]+\] .bss.retain1.*WAR.*
+  \[[ 0-9]+\] .data.retain2.*WAR.*
+  \[[ 0-9]+\] .bss.sretain0.*WAR.*
+  \[[ 0-9]+\] .bss.sretain1.*WAR.*
+  \[[ 0-9]+\] .data.sretain2.*WAR.*
+  \[[ 0-9]+\] .text.fnretain1.*AXR.*
+#...
+  \[[ 0-9]+\] .bss.lsretain0.*WAR.*
+  \[[ 0-9]+\] .bss.lsretain1.*WAR.*
+  \[[ 0-9]+\] .data.lsretain2.*WAR.*
+#pass
diff --git a/binutils/testsuite/binutils-all/retain1.s b/binutils/testsuite/binutils-all/retain1.s
new file mode 100644
index 0000000000..f7716faabe
--- /dev/null
+++ b/binutils/testsuite/binutils-all/retain1.s
@@ -0,0 +1,104 @@
+	.global	discard0
+	.section	.bss.discard0,"aw"
+	.type	discard0, %object
+discard0:
+	.zero	2
+
+	.global	discard1
+	.section	.bss.discard1,"aw"
+	.type	discard1, %object
+discard1:
+	.zero	2
+
+	.global	discard2
+	.section	.data.discard2,"aw"
+	.type	discard2, %object
+discard2:
+	.word	1
+
+	.section	.bss.sdiscard0,"aw"
+	.type	sdiscard0, %object
+sdiscard0:
+	.zero	2
+
+	.section	.bss.sdiscard1,"aw"
+	.type	sdiscard1, %object
+sdiscard1:
+	.zero	2
+
+	.section	.data.sdiscard2,"aw"
+	.type	sdiscard2, %object
+sdiscard2:
+	.word	1
+
+	.section	.text.fndiscard0,"ax"
+	.global	fndiscard0
+	.type	fndiscard0, %function
+fndiscard0:
+	.word 0
+
+	.global	retain0
+	.section	.bss.retain0,"awR"
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.global	retain1
+	.section	.bss.retain1,"awR"
+	.type	retain1, %object
+retain1:
+	.zero	2
+
+	.global	retain2
+	.section	.data.retain2,"awR"
+	.type	retain2, %object
+retain2:
+	.word	1
+
+	.section	.bss.sretain0,"awR"
+	.type	sretain0, %object
+sretain0:
+	.zero	2
+
+	.section	.bss.sretain1,"awR"
+	.type	sretain1, %object
+sretain1:
+	.zero	2
+
+	.section	.data.sretain2,"aRw"
+	.type	sretain2, %object
+sretain2:
+	.word	1
+
+	.section	.text.fnretain1,"Rax"
+	.global	fnretain1
+	.type	fnretain1, %function
+fnretain1:
+	.word	0
+
+	.section	.text.fndiscard2,"ax"
+	.global	fndiscard2
+	.type	fndiscard2, %function
+fndiscard2:
+	.word	0
+
+	.section	.bss.lsretain0,"awR"
+	.type	lsretain0.2, %object
+lsretain0.2:
+	.zero	2
+
+	.section	.bss.lsretain1,"aRw"
+	.type	lsretain1.1, %object
+lsretain1.1:
+	.zero	2
+
+	.section	.data.lsretain2,"aRw"
+	.type	lsretain2.0, %object
+lsretain2.0:
+	.word	1
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/binutils/testsuite/lib/binutils-common.exp b/binutils/testsuite/lib/binutils-common.exp
index b9a1e6e4bc..a43639bafb 100644
--- a/binutils/testsuite/lib/binutils-common.exp
+++ b/binutils/testsuite/lib/binutils-common.exp
@@ -195,13 +195,15 @@ proc match_target { target } {
 
 # True if the ELF target supports setting the ELF header OSABI field
 # to ELFOSABI_GNU or ELFOSABI_FREEBSD, a requirement for STT_GNU_IFUNC
-# symbol and SHF_GNU_MBIND section support.
+# symbol and SHF_GNU_MBIND or SHF_GNU_RETAIN section support.
 #
 # This generally depends on the target OS only, however there are a
 # number of exceptions for bare metal targets as follows.  The MSP430
 # and Visium targets set OSABI to ELFOSABI_STANDALONE.  Likewise
 # non-EABI ARM targets set OSABI to ELFOSABI_ARM
 #
+# Non-Linux HPPA defaults to ELFOSABI_HPUX.
+#
 # Note that some TI C6X targets use ELFOSABI_C6000_* but one doesn't,
 # so we don't try to sort out tic6x here.  (The effect is that linker
 # testcases will generally need to exclude tic6x or use a -m option.)
@@ -227,6 +229,7 @@ proc supports_gnu_osabi {} {
     }
     if { [istarget "arm*-*-*"]
 	 || [istarget "msp430-*-*"]
+	 || [istarget "hppa-unknown-elf"]
 	 || [istarget "visium-*-*"] } {
 	return 0
     }
diff --git a/gas/NEWS b/gas/NEWS
index 7ae58506ec..2056967a35 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -16,6 +16,12 @@
 
 * Configure with --enable-x86-used-note by default for Linux/x86.
 
+* Add support for the "R" flag in the .section directive.
+  This flag requires ELFOSABI_GNU or ELFOSABI_FREEBSD, and applies the
+  ELF SHF_GNU_RETAIN flag to the specified section.  This flag specifies
+  the section should not be garbage collected by the linker if it is
+  unused.
+
 Changes in 2.35:
 
 * X86 NaCl target support is removed.
diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index b1c99020a3..4d6c8ef921 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -517,6 +517,10 @@ struct section_stack
 
 static struct section_stack *section_stack;
 
+/* Create unique input sections for sections with the same name, but different
+   values for the flags in this mask.  */
+#define SEC_ASSEMBLER_SHF_MASK SHF_GNU_RETAIN
+
 static bfd_boolean
 get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
 {
@@ -525,9 +529,12 @@ get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
   const char *group_name = elf_group_name (sec);
   const char *linked_to_symbol_name
     = sec->map_head.linked_to_symbol_name;
-  unsigned int info = elf_section_data (sec)->this_hdr.sh_info;
+  unsigned int sh_info = elf_section_data (sec)->this_hdr.sh_info;
+  bfd_vma sh_flags = (elf_section_data (sec)->this_hdr.sh_flags
+		      & SEC_ASSEMBLER_SHF_MASK);
 
-  return (info == match->info
+  return (sh_info == match->sh_info
+	  && sh_flags == match->sh_flags
 	  && ((bfd_section_flags (sec) & SEC_ASSEMBLER_SECTION_ID)
 	       == (match->flags & SEC_ASSEMBLER_SECTION_ID))
 	  && sec->section_id == match->section_id
@@ -736,7 +743,7 @@ obj_elf_change_section (const char *name,
 	type = bfd_elf_get_default_section_type (flags);
       elf_section_type (sec) = type;
       elf_section_flags (sec) = attr;
-      elf_section_data (sec)->this_hdr.sh_info = match_p->info;
+      elf_section_data (sec)->this_hdr.sh_info = match_p->sh_info;
 
       /* Prevent SEC_HAS_CONTENTS from being inadvertently set.  */
       if (type == SHT_NOBITS)
@@ -857,6 +864,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;
@@ -886,8 +896,32 @@ obj_elf_parse_section_letters (char *str, size_t len,
 	      if (ISDIGIT (*str))
 		{
 		  char * end;
+		  struct elf_backend_data *bed;
+		  bfd_vma numeric_flags = strtoul (str, &end, 0);
+
+		  attr |= numeric_flags;
+
+		  bed = (struct elf_backend_data *)
+		    get_elf_backend_data (stdoutput);
+
+		  if (bed->elf_osabi == ELFOSABI_NONE
+		      || bed->elf_osabi == ELFOSABI_STANDALONE
+		      || bed->elf_osabi == ELFOSABI_GNU
+		      || bed->elf_osabi == ELFOSABI_FREEBSD)
+		    {
+		      /* Add flags in the SHF_MASKOS range to gnu_attr for
+			 OSABIs that support those flags.
+			 Also adding the flags for ELFOSABI_{NONE,STANDALONE}
+			 allows them to be validated later in obj_elf_section.
+			 We can't just always set these bits in gnu_attr for
+			 all OSABIs, since Binutils does not recognize all
+			 SHF_MASKOS bits for non-GNU OSABIs.  It's therefore
+			 possible that numeric flags are being used to set bits
+			 in the SHF_MASKOS range for those targets, and we
+			 don't want assembly to fail in those situations.  */
+		      *gnu_attr |= (numeric_flags & SHF_MASKOS);
+		    }
 
-		  attr |= strtoul (str, & end, 0);
 		  /* Update str and len, allowing for the fact that
 		     we will execute str++ and len-- below.  */
 		  end --;
@@ -1250,18 +1284,21 @@ obj_elf_section (int push)
 	      if (ISDIGIT (* input_line_pointer))
 		{
 		  char *t = input_line_pointer;
-		  match.info = strtoul (input_line_pointer,
+		  match.sh_info = strtoul (input_line_pointer,
 					&input_line_pointer, 0);
-		  if (match.info == (unsigned int) -1)
+		  if (match.sh_info == (unsigned int) -1)
 		    {
 		      as_warn (_("unsupported mbind section info: %s"), t);
-		      match.info = 0;
+		      match.sh_info = 0;
 		    }
 		}
 	      else
 		input_line_pointer = save;
 	    }
 
+	  if ((gnu_attr & SHF_GNU_RETAIN) != 0)
+	    match.sh_flags |= SHF_GNU_RETAIN;
+
 	  if (*input_line_pointer == ',')
 	    {
 	      char *save = input_line_pointer;
@@ -1352,11 +1389,12 @@ obj_elf_section (int push)
   obj_elf_change_section (name, type, attr, entsize, &match, linkonce,
 			  push);
 
-  if ((gnu_attr & SHF_GNU_MBIND) != 0)
+  if ((gnu_attr & (SHF_GNU_MBIND | SHF_GNU_RETAIN)) != 0)
     {
       struct elf_backend_data *bed;
+      bfd_boolean mbind_p = (gnu_attr & SHF_GNU_MBIND) != 0;
 
-      if ((attr & SHF_ALLOC) == 0)
+      if (mbind_p && (attr & SHF_ALLOC) == 0)
 	as_bad (_("SHF_ALLOC isn't set for GNU_MBIND section: %s"), name);
 
       bed = (struct elf_backend_data *) get_elf_backend_data (stdoutput);
@@ -1364,9 +1402,12 @@ obj_elf_section (int push)
 	bed->elf_osabi = ELFOSABI_GNU;
       else if (bed->elf_osabi != ELFOSABI_GNU
 	       && bed->elf_osabi != ELFOSABI_FREEBSD)
-	as_bad (_("GNU_MBIND section is supported only by GNU "
-		  "and FreeBSD targets"));
-      elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_mbind;
+	as_bad (_("%s section is supported only by GNU and FreeBSD targets"),
+		mbind_p ? "GNU_MBIND" : "GNU_RETAIN");
+      if (mbind_p)
+	elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_mbind;
+      if ((gnu_attr & SHF_GNU_RETAIN) != 0)
+	elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_retain;
     }
   elf_section_flags (now_seg) |= gnu_attr;
 
diff --git a/gas/config/obj-elf.h b/gas/config/obj-elf.h
index b39a1a1ab6..6eb0a8ede4 100644
--- a/gas/config/obj-elf.h
+++ b/gas/config/obj-elf.h
@@ -106,8 +106,9 @@ struct elf_section_match
 {
   const char *group_name;
   const char *linked_to_symbol_name;
-  unsigned int info;
   unsigned int section_id;
+  unsigned int sh_info;		/* ELF section information.  */
+  bfd_vma sh_flags;		/* ELF section flags.  */
   flagword flags;
 };
 
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index b88c1f9997..a697ccb2c1 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -6649,6 +6649,9 @@ section is a member of a section group
 section is used for thread-local-storage
 @item ?
 section is a member of the previously-current section's group, if any
+@item R
+retained section (apply SHF_GNU_RETAIN to prevent linker garbage
+collection, GNU ELF extension)
 @item @code{<number>}
 a numeric value indicating the bits to be set in the ELF section header's flags
 field.  Note - if one or more of the alphabetic characters described above is
diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
index 135ade24ec..7c89bea91b 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -257,6 +257,9 @@ if { [is_elf_format] } then {
     run_dump_test "section19"
     run_dump_test "section20"
     run_dump_test "section21"
+    run_dump_test "section22"
+    run_dump_test "section23a"
+    run_dump_test "section23b"
     run_dump_test "dwarf2-1" $dump_opts
     run_dump_test "dwarf2-2" $dump_opts
     run_dump_test "dwarf2-3" $dump_opts
diff --git a/gas/testsuite/gas/elf/section10.d b/gas/testsuite/gas/elf/section10.d
index 554a791f1d..6aa7b088b1 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\)
+[ 	]*\[.*fedff030\]: 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\)
+[ 	]*\[.*fedf0000\]:.* EXCLUDE, OS \(.*ed00000\), PROC \(.*[3467]0000000\), UNKNOWN \(.*f0000\)
 [ 	]*\[.*\][ 	]+.data.foo
 [ 	]*LOUSER\+0x7f000000[ 	].*
 [ 	]*\[0+003\]: WRITE, ALLOC
diff --git a/gas/testsuite/gas/elf/section10.s b/gas/testsuite/gas/elf/section10.s
index 29f1184523..d52b3458fb 100644
--- a/gas/testsuite/gas/elf/section10.s
+++ b/gas/testsuite/gas/elf/section10.s
@@ -7,7 +7,7 @@
 	.word 2
 
 	# Make sure that specifying further arguments to .sections is still supported
-	.section sec3, "0xfefff000MS", %progbits, 32
+	.section sec3, "0xfedff000MS", %progbits, 32
 	.word 3
 
 	# Make sure that extra flags can be set for well known sections as well.
@@ -19,7 +19,7 @@
 	.word 5
 
 	# Test both together, with a quoted type value.
-	.section sec5, "0xfeff0000", "0x80000009"
+	.section sec5, "0xfedf0000", "0x80000009"
 	.word 6
 
 	# Test that declaring an extended version of a known special section works.
diff --git a/gas/testsuite/gas/elf/section22.d b/gas/testsuite/gas/elf/section22.d
new file mode 100644
index 0000000000..27d9127745
--- /dev/null
+++ b/gas/testsuite/gas/elf/section22.d
@@ -0,0 +1,19 @@
+#readelf: -h -S --wide
+#name: SHF_GNU_RETAIN sections 22
+#notarget: ![supports_gnu_osabi]
+
+#...
+ +OS/ABI: +UNIX - GNU
+#...
+  \[..\] .text[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  AX.*
+#...
+  \[..\] .data[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+#...
+  \[..\] .bss[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+#...
+  \[..\] .bss[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#...
+  \[..\] .data[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#...
+  \[..\] .text[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXR.*
+#pass
diff --git a/gas/testsuite/gas/elf/section22.s b/gas/testsuite/gas/elf/section22.s
new file mode 100644
index 0000000000..6e2b95c1e8
--- /dev/null
+++ b/gas/testsuite/gas/elf/section22.s
@@ -0,0 +1,34 @@
+	.section	.text,"ax",%progbits
+	.global	discard0
+	.type	discard0, %function
+discard0:
+	.word	0
+
+	.section	.data,"aw"
+	.global	discard1
+	.type	discard1, %object
+discard1:
+	.word	1
+
+	.section	.bss,"aw"
+	.global	discard2
+	.type	discard2, %object
+discard2:
+	.zero	2
+
+	.section	.bss,"awR",%nobits
+	.global	retain0
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.section	.data,"awR",%progbits
+	.type	retain1, %object
+retain1:
+	.word	1
+
+	.section	.text,"axR",%progbits
+	.global	retain2
+	.type	retain2, %function
+retain2:
+	.word	0
diff --git a/gas/testsuite/gas/elf/section23.s b/gas/testsuite/gas/elf/section23.s
new file mode 100644
index 0000000000..d671119bca
--- /dev/null
+++ b/gas/testsuite/gas/elf/section23.s
@@ -0,0 +1,11 @@
+  .section	.data.retain_var,"0x200003"
+	.global	retain_var
+	.type	retain_var, %object
+retain_var:
+	.long	2
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/gas/testsuite/gas/elf/section23a.d b/gas/testsuite/gas/elf/section23a.d
new file mode 100644
index 0000000000..1d850d9e8e
--- /dev/null
+++ b/gas/testsuite/gas/elf/section23a.d
@@ -0,0 +1,11 @@
+#name: SHF_GNU_RETAIN set with numeric flag value in .section
+#source: section23.s
+#target: [supports_gnu_osabi]
+#readelf: -h -S --wide
+
+#...
+ +OS/ABI: +UNIX - GNU
+#...
+  \[..\] .data.retain_var[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#pass
+
diff --git a/gas/testsuite/gas/elf/section23b.d b/gas/testsuite/gas/elf/section23b.d
new file mode 100644
index 0000000000..c85200e5ff
--- /dev/null
+++ b/gas/testsuite/gas/elf/section23b.d
@@ -0,0 +1,6 @@
+#name: SHF_GNU_RETAIN set with numeric flag value in .section for non-GNU OSABI target
+#source: section23.s
+#error_output: section23b.err
+#target: msp430-*-elf visium-*-elf
+
+# This test only runs for targets which set ELFOSABI_STANDALONE.
diff --git a/gas/testsuite/gas/elf/section23b.err b/gas/testsuite/gas/elf/section23b.err
new file mode 100644
index 0000000000..83de60c397
--- /dev/null
+++ b/gas/testsuite/gas/elf/section23b.err
@@ -0,0 +1,2 @@
+.*: Assembler messages:
+.*:1: Error: GNU_RETAIN section is supported only by GNU and FreeBSD targets
diff --git a/include/elf/common.h b/include/elf/common.h
index 571e21af29..c01e562c78 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/NEWS b/ld/NEWS
index e4ae43b257..72cdf0edd3 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -15,6 +15,10 @@
   unless you are working on a project that has its own analogue
   of symbol tables that are not reflected in the ELF symtabs.
 
+* Add support for the SHF_GNU_RETAIN ELF section flag.
+  This flag specifies that the section should not be garbage collected by the
+  linker if it is unused.
+
 Changes in 2.35:
 
 * X86 NaCl target support is removed.
diff --git a/ld/ld.texi b/ld/ld.texi
index ee592df6c2..526b642d78 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1787,6 +1787,10 @@ specified either by one of the options @samp{--entry},
 @samp{--undefined}, or @samp{--gc-keep-exported} or by a @code{ENTRY}
 command in the linker script.
 
+As a GNU extension, ELF input sections marked with the
+@code{SHF_GNU_RETAIN} flag will not be garbage collected if they are
+unused.
+
 @kindex --print-gc-sections
 @kindex --no-print-gc-sections
 @cindex garbage collection
@@ -5232,6 +5236,10 @@ The special output section name @samp{/DISCARD/} may be used to discard
 input sections.  Any input sections which are assigned to an output
 section named @samp{/DISCARD/} are not included in the output file.
 
+This can be used to discard input sections marked with the ELF flag
+@code{SHF_GNU_RETAIN}, which would otherwise have been saved from linker
+garbage collection when they are unused.
+
 Note, sections that match the @samp{/DISCARD/} output section will be
 discarded even if they are in an ELF section group which has other
 members which are not being discarded.  This is deliberate.
diff --git a/ld/testsuite/ld-elf/elf.exp b/ld/testsuite/ld-elf/elf.exp
index f2ff0397c7..bd06ab0d39 100644
--- a/ld/testsuite/ld-elf/elf.exp
+++ b/ld/testsuite/ld-elf/elf.exp
@@ -119,6 +119,17 @@ if { [istarget "i?86-*-*"] || [istarget "x86_64-*-*"] } {
     set ASFLAGS "$ASFLAGS -mx86-used-note=no"
 }
 
+# Build libraries required for SHF_GNU_RETAIN tests.
+if { [check_gc_sections_available] && [supports_gnu_osabi] } {
+    run_ld_link_tests [list \
+	[list "Build libretain5.a" "" "" "" \
+	    {retain5lib.s} {} "libretain5.a"] \
+	[list "Build libretain6.a" "" "" "" \
+	    {retain6lib.s} {} "libretain6.a"] \
+	]
+}
+
+
 set test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
 foreach t $test_list {
     # We need to strip the ".d", but can leave the dirname.
diff --git a/ld/testsuite/ld-elf/retain1.s b/ld/testsuite/ld-elf/retain1.s
new file mode 100644
index 0000000000..f7716faabe
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1.s
@@ -0,0 +1,104 @@
+	.global	discard0
+	.section	.bss.discard0,"aw"
+	.type	discard0, %object
+discard0:
+	.zero	2
+
+	.global	discard1
+	.section	.bss.discard1,"aw"
+	.type	discard1, %object
+discard1:
+	.zero	2
+
+	.global	discard2
+	.section	.data.discard2,"aw"
+	.type	discard2, %object
+discard2:
+	.word	1
+
+	.section	.bss.sdiscard0,"aw"
+	.type	sdiscard0, %object
+sdiscard0:
+	.zero	2
+
+	.section	.bss.sdiscard1,"aw"
+	.type	sdiscard1, %object
+sdiscard1:
+	.zero	2
+
+	.section	.data.sdiscard2,"aw"
+	.type	sdiscard2, %object
+sdiscard2:
+	.word	1
+
+	.section	.text.fndiscard0,"ax"
+	.global	fndiscard0
+	.type	fndiscard0, %function
+fndiscard0:
+	.word 0
+
+	.global	retain0
+	.section	.bss.retain0,"awR"
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.global	retain1
+	.section	.bss.retain1,"awR"
+	.type	retain1, %object
+retain1:
+	.zero	2
+
+	.global	retain2
+	.section	.data.retain2,"awR"
+	.type	retain2, %object
+retain2:
+	.word	1
+
+	.section	.bss.sretain0,"awR"
+	.type	sretain0, %object
+sretain0:
+	.zero	2
+
+	.section	.bss.sretain1,"awR"
+	.type	sretain1, %object
+sretain1:
+	.zero	2
+
+	.section	.data.sretain2,"aRw"
+	.type	sretain2, %object
+sretain2:
+	.word	1
+
+	.section	.text.fnretain1,"Rax"
+	.global	fnretain1
+	.type	fnretain1, %function
+fnretain1:
+	.word	0
+
+	.section	.text.fndiscard2,"ax"
+	.global	fndiscard2
+	.type	fndiscard2, %function
+fndiscard2:
+	.word	0
+
+	.section	.bss.lsretain0,"awR"
+	.type	lsretain0.2, %object
+lsretain0.2:
+	.zero	2
+
+	.section	.bss.lsretain1,"aRw"
+	.type	lsretain1.1, %object
+lsretain1.1:
+	.zero	2
+
+	.section	.data.lsretain2,"aRw"
+	.type	lsretain2.0, %object
+lsretain2.0:
+	.word	1
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain1a.d b/ld/testsuite/ld-elf/retain1a.d
new file mode 100644
index 0000000000..75abb9856c
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1a.d
@@ -0,0 +1,28 @@
+#name: SHF_GNU_RETAIN 1a
+#source: retain1.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . fnretain1
+#...
+[0-9a-f]+ . lsretain0.2
+#...
+[0-9a-f]+ . lsretain1.1
+#...
+[0-9a-f]+ . lsretain2.0
+#...
+[0-9a-f]+ . retain0
+#...
+[0-9a-f]+ . retain1
+#...
+[0-9a-f]+ . retain2
+#...
+[0-9a-f]+ . sretain0
+#...
+[0-9a-f]+ . sretain1
+#...
+[0-9a-f]+ . sretain2
+#pass
diff --git a/ld/testsuite/ld-elf/retain1b.d b/ld/testsuite/ld-elf/retain1b.d
new file mode 100644
index 0000000000..815c0150f5
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1b.d
@@ -0,0 +1,11 @@
+#name: SHF_GNU_RETAIN 1b
+#source: retain1.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#nm: -n
+
+#failif
+#...
+[0-9a-f]+ . .*discard.*
+#...
diff --git a/ld/testsuite/ld-elf/retain2.d b/ld/testsuite/ld-elf/retain2.d
new file mode 100644
index 0000000000..11efd6ddb8
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.d
@@ -0,0 +1,6 @@
+#name: SHF_GNU_RETAIN 2 (remove SHF_GNU_RETAIN sections by placing in /DISCARD/)
+#source: retain1.s
+#ld: -e _start -Map=retain2.map --gc-sections --script=retain2.ld
+#map: retain2.map
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
diff --git a/ld/testsuite/ld-elf/retain2.ld b/ld/testsuite/ld-elf/retain2.ld
new file mode 100644
index 0000000000..8ef982753c
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.ld
@@ -0,0 +1,7 @@
+SECTIONS
+{
+  /DISCARD/ :
+  {
+    *(.text.fnretain1)
+  }
+}
diff --git a/ld/testsuite/ld-elf/retain2.map b/ld/testsuite/ld-elf/retain2.map
new file mode 100644
index 0000000000..4028aa1f58
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.map
@@ -0,0 +1,32 @@
+# Test that .text.fnretain1, which has the SHF_GNU_RETAIN flag, can still be
+# explicitly discarded from the output file.
+
+#...
+Discarded input sections
+
+ .text.*
+#...
+ .data.*
+#...
+ .bss.*
+#...
+ .bss.discard0.*
+#...
+ .bss.discard1.*
+#...
+ .data.discard2.*
+#...
+ .bss.sdiscard0.*
+#...
+ .bss.sdiscard1.*
+#...
+ .data.sdiscard2.*
+#...
+ .text.fndiscard0.*
+#...
+ .text.fnretain1.*
+#...
+ .text.fndiscard2.*
+#...
+Memory Configuration
+#pass
diff --git a/ld/testsuite/ld-elf/retain3.d b/ld/testsuite/ld-elf/retain3.d
new file mode 100644
index 0000000000..911f5b7594
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain3.d
@@ -0,0 +1,12 @@
+#name: SHF_GNU_RETAIN 3 (keep sections referenced by retained sections)
+#source: retain3.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . bar
+#...
+[0-9a-f]+ . foo
+#pass
diff --git a/ld/testsuite/ld-elf/retain3.s b/ld/testsuite/ld-elf/retain3.s
new file mode 100644
index 0000000000..ce315cbaa6
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain3.s
@@ -0,0 +1,19 @@
+/* The retention of bar should also prevent foo from being gc'ed, since bar
+   references foo.  */
+	.section	.text.foo,"ax"
+	.global	foo
+	.type	foo, %function
+foo:
+	.word 0
+
+	.section	.text.bar,"axR"
+	.global	bar
+	.type	bar, %function
+bar:
+	.long foo
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain4.d b/ld/testsuite/ld-elf/retain4.d
new file mode 100644
index 0000000000..e94898d681
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain4.d
@@ -0,0 +1,10 @@
+#name: SHF_GNU_RETAIN 4 (keep orphaned sections when not discarding)
+#source: retain4.s
+#ld: -e _start --gc-sections --orphan-handling=place
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . orphaned_fn
+#pass
diff --git a/ld/testsuite/ld-elf/retain4.s b/ld/testsuite/ld-elf/retain4.s
new file mode 100644
index 0000000000..9f350cd3b2
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain4.s
@@ -0,0 +1,13 @@
+/* A section which doesn't match any linker script input section rules but
+   has SHF_GNU_RETAIN applied should not be garbage collected.  */
+	.section	.orphaned_section,"axR"
+	.global	orphaned_fn
+	.type	orphaned_fn, %function
+orphaned_fn:
+	.word 0
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain5.d b/ld/testsuite/ld-elf/retain5.d
new file mode 100644
index 0000000000..378799599e
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5.d
@@ -0,0 +1,12 @@
+#name: SHF_GNU_RETAIN 5 (don't pull SHF_GNU_RETAIN section out of lib)
+#source: retain5main.s
+#ld: --gc-sections -e _start --print-gc-sections -Ltmpdir -lretain5 -Map=retain5.map
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#map: retain5.map
+#DUMPPROG: nm
+
+#failif
+#...
+[0-9a-f]+ . foo
+#...
diff --git a/ld/testsuite/ld-elf/retain5.map b/ld/testsuite/ld-elf/retain5.map
new file mode 100644
index 0000000000..6b97c2a220
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5.map
@@ -0,0 +1,5 @@
+# Check that the library was actually loaded to catch any false PASS.
+
+#...
+LOAD tmpdir/libretain5.a
+#pass
diff --git a/ld/testsuite/ld-elf/retain5lib.s b/ld/testsuite/ld-elf/retain5lib.s
new file mode 100644
index 0000000000..4e83731719
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5lib.s
@@ -0,0 +1,6 @@
+/* The link will fail if foo is included because undefined_sym is not defined.  */
+	.section	.text.foo,"axR"
+	.global	foo
+	.type	foo, %function
+foo:
+	.long undefined_sym
diff --git a/ld/testsuite/ld-elf/retain5main.s b/ld/testsuite/ld-elf/retain5main.s
new file mode 100644
index 0000000000..89a7784d13
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5main.s
@@ -0,0 +1,5 @@
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain6a.d b/ld/testsuite/ld-elf/retain6a.d
new file mode 100644
index 0000000000..92872deffc
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6a.d
@@ -0,0 +1,14 @@
+#name: SHF_GNU_RETAIN 6a (pull section out of lib required by SHF_GNU_RETAIN section)
+#source: retain6main.s
+#ld: --gc-sections -e _start -u bar -Ltmpdir -lretain6
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . bar
+#...
+[0-9a-f]+ . retain_from_lib
+#...
+[0-9a-f]+ . retained_fn
+#pass
diff --git a/ld/testsuite/ld-elf/retain6b.d b/ld/testsuite/ld-elf/retain6b.d
new file mode 100644
index 0000000000..a797bf7837
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6b.d
@@ -0,0 +1,11 @@
+#name: SHF_GNU_RETAIN 6b (pull section out of lib required by SHF_GNU_RETAIN section)
+#source: retain6main.s
+#ld: --gc-sections -e _start -u bar -Ltmpdir -lretain6
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#failif
+#...
+[0-9a-f]+ . .*discard.*
+#...
diff --git a/ld/testsuite/ld-elf/retain6lib.s b/ld/testsuite/ld-elf/retain6lib.s
new file mode 100644
index 0000000000..a393dbac61
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6lib.s
@@ -0,0 +1,17 @@
+	.section	.text.bar,"ax"
+	.global	bar
+	.type	bar, %function
+bar:
+	.word 0
+
+	.section	.text.retain_from_lib,"axR"
+	.global	retain_from_lib
+	.type	retain_from_lib, %function
+retain_from_lib:
+	.word 0
+
+	.section	.text.discard_from_lib,"ax"
+	.global	discard_from_lib
+	.type	discard_from_lib, %function
+discard_from_lib:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain6main.s b/ld/testsuite/ld-elf/retain6main.s
new file mode 100644
index 0000000000..a66c5b3247
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6main.s
@@ -0,0 +1,13 @@
+/* Undefined symbol reference in retained section .text.retained_fn requires
+   symbol definition to be pulled out of library.  */
+	.section	.text.retained_fn,"axR"
+	.global	retained_fn
+	.type	retained_fn, %function
+retained_fn:
+	.long bar
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain7.s b/ld/testsuite/ld-elf/retain7.s
new file mode 100644
index 0000000000..2d80947fbd
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7.s
@@ -0,0 +1,104 @@
+	.section	.bss,"aw"
+	.global	discard0
+	.type	discard0, %object
+discard0:
+	.zero	2
+
+	.section	.bss,"aw"
+	.global	discard1
+	.type	discard1, %object
+discard1:
+	.zero	2
+
+	.section	.data,"aw"
+	.global	discard2
+	.type	discard2, %object
+discard2:
+	.word	1
+
+	.section	.bss,"aw"
+	.type	sdiscard0, %object
+sdiscard0:
+	.zero	2
+
+	.section	.bss,"aw"
+	.type	sdiscard1, %object
+sdiscard1:
+	.zero	2
+
+	.section	.data,"aw"
+	.type	sdiscard2, %object
+sdiscard2:
+	.word	1
+
+	.text
+	.global	fndiscard0
+	.type	fndiscard0, %function
+fndiscard0:
+	.word 0
+
+	.section	.bss,"awR"
+	.global	retain0
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.section	.bss,"awR"
+	.global	retain1
+	.type	retain1, %object
+retain1:
+	.zero	2
+
+	.section	.data,"awR"
+	.global	retain2
+	.type	retain2, %object
+retain2:
+	.word	1
+
+	.section	.bss,"awR"
+	.type	sretain0, %object
+sretain0:
+	.zero	2
+
+	.section	.bss,"awR"
+	.type	sretain1, %object
+sretain1:
+	.zero	2
+
+	.section	.data,"aRw"
+	.type	sretain2, %object
+sretain2:
+	.word	1
+
+	.section	.text,"Rax"
+	.global	fnretain1
+	.type	fnretain1, %function
+fnretain1:
+	.word	0
+
+	.section	.text,"ax"
+	.global	fndiscard2
+	.type	fndiscard2, %function
+fndiscard2:
+	.word	0
+
+	.section	.bss,"awR"
+	.type	lsretain0.2, %object
+lsretain0.2:
+	.zero	2
+
+	.section	.bss,"aRw"
+	.type	lsretain1.1, %object
+lsretain1.1:
+	.zero	2
+
+	.section	.data,"aRw"
+	.type	lsretain2.0, %object
+lsretain2.0:
+	.word	1
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain7a.d b/ld/testsuite/ld-elf/retain7a.d
new file mode 100644
index 0000000000..055bb74da9
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7a.d
@@ -0,0 +1,28 @@
+#name: SHF_GNU_RETAIN 7a (flag applied to default section names)
+#source: retain7.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . fnretain1
+#...
+[0-9a-f]+ . lsretain0.2
+#...
+[0-9a-f]+ . lsretain1.1
+#...
+[0-9a-f]+ . lsretain2.0
+#...
+[0-9a-f]+ . retain0
+#...
+[0-9a-f]+ . retain1
+#...
+[0-9a-f]+ . retain2
+#...
+[0-9a-f]+ . sretain0
+#...
+[0-9a-f]+ . sretain1
+#...
+[0-9a-f]+ . sretain2
+#pass
diff --git a/ld/testsuite/ld-elf/retain7b.d b/ld/testsuite/ld-elf/retain7b.d
new file mode 100644
index 0000000000..f268047c35
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7b.d
@@ -0,0 +1,11 @@
+#name: SHF_GNU_RETAIN 7b (flag applied to default section names)
+#source: retain7.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#nm: -n
+
+#failif
+#...
+[0-9a-f]+ . .*discard.*
+#...
-- 
2.28.0


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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-10-02 12:30       ` Jozef Lawrynowicz
@ 2020-10-02 12:33         ` H.J. Lu
  2020-10-02 12:41           ` H.J. Lu
  2020-10-02 14:11         ` Alan Modra
  1 sibling, 1 reply; 22+ messages in thread
From: H.J. Lu @ 2020-10-02 12:33 UTC (permalink / raw)
  To: Alan Modra, H.J. Lu, Binutils

On Fri, Oct 2, 2020 at 5:30 AM Jozef Lawrynowicz
<jozef.l@mittosystems.com> wrote:
>
> On Thu, Oct 01, 2020 at 09:09:07PM +0930, Alan Modra via Binutils wrote:
> > On Thu, Oct 01, 2020 at 11:50:33AM +0100, Jozef Lawrynowicz wrote:
> > > --- a/bfd/elflink.c
> > > +++ b/bfd/elflink.c
> > > @@ -14102,7 +14102,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)))
> >
> > Flag bits in SHF_MASKOS depend on OS, so this needs a test of OSABI.
> > That can be done by checking elf_tdata (sub)->has_gnu_osabi for the
> > appropriate bit.
> >
>
> Fixed the two OSABI issues in the attached patch.
>

Please rebase since this part has been changed on master branch.

-- 
H.J.

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-10-02 12:33         ` H.J. Lu
@ 2020-10-02 12:41           ` H.J. Lu
  2020-10-02 12:53             ` Jozef Lawrynowicz
  0 siblings, 1 reply; 22+ messages in thread
From: H.J. Lu @ 2020-10-02 12:41 UTC (permalink / raw)
  To: Alan Modra; +Cc: Binutils

On Fri, Oct 2, 2020 at 5:33 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Fri, Oct 2, 2020 at 5:30 AM Jozef Lawrynowicz
> <jozef.l@mittosystems.com> wrote:
> >
> > On Thu, Oct 01, 2020 at 09:09:07PM +0930, Alan Modra via Binutils wrote:
> > > On Thu, Oct 01, 2020 at 11:50:33AM +0100, Jozef Lawrynowicz wrote:
> > > > --- a/bfd/elflink.c
> > > > +++ b/bfd/elflink.c
> > > > @@ -14102,7 +14102,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)))
> > >
> > > Flag bits in SHF_MASKOS depend on OS, so this needs a test of OSABI.
> > > That can be done by checking elf_tdata (sub)->has_gnu_osabi for the
> > > appropriate bit.
> > >
> >
> > Fixed the two OSABI issues in the attached patch.
> >
>
> Please rebase since this part has been changed on master branch.
>

+ || (elf_tdata (sub)->has_gnu_osabi & elf_gnu_osabi_retain
+     && elf_section_flags (o) & SHF_GNU_RETAIN)))

Also please add () for elf_tdata (sub)->has_gnu_osabi & elf_gnu_osabi_retain
and elf_section_flags (o) & SHF_GNU_RETAIN.

-- 
H.J.

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-10-01 19:22             ` Fangrui Song
  2020-10-01 19:53               ` H.J. Lu
@ 2020-10-02 12:44               ` Jozef Lawrynowicz
  1 sibling, 0 replies; 22+ messages in thread
From: Jozef Lawrynowicz @ 2020-10-02 12:44 UTC (permalink / raw)
  To: Fangrui Song
  Cc: Roland McGrath, H.J. Lu, Binutils Development, gnu-gabi,
	Peter Smith, George Rimar, James Henderson, James Y Knight

On Thu, Oct 01, 2020 at 12:22:11PM -0700, Fangrui Song wrote:
> On 2020-09-30, Jozef Lawrynowicz wrote:
> > On Tue, Sep 29, 2020 at 05:10:09PM -0700, Roland McGrath wrote:
> > > Since group semantics mean that if any section in a group is retained the
> > > whole group must be retained, it seems to me that making the feature a
> > > group flag rather than a section flag makes sense. I don't think it really
> > > has any downside. It's a little bit more structure to generate a group but
> > > everything already knows how to do it so that should be no problem.  While
> > > it is true that multiple sections with the same name and different
> > > attributes should already be fine, the place where multiple different
> > > sections of the same name are usually seen today is when each different
> > > section reusing a name is in a different group from the other sections with
> > > the same name.
> > > 
> > 
> > Let's assume:
> >  GRP_RETAIN
> >    Sections in a group with this flag set should always be included in
> >    the linked object, even if they appear unused.
> > 
> > One issue I have with the group method is conceptual; groups are supposed
> > to be used to group related sections. They are related because of their
> > meaning from the application perspective, not because of their metadata
> > (i.e. sections to be retained are related by their metadata because they
> > all should be retained).
> > 
> > Just because groups have a side effect that can be leveraged to
> > get a section to be retained in the final link, why does that mean we
> > need to leverage that property when it it's not actually the simplest or
> > most obvious way to implement the new behavior?
> > 
> > SHF_GNU_RETAIN describes in the simplest possible way that the section
> > should be retained in the final link, without relying on other
> > constructs.
> > 
> > Just because groups are discarded or retained as a group, doesn't mean
> > we need to leverage groups to try and implement retention or discarding
> > functionality.
> > 
> > Why wasn't SHF_EXCLUDE implemented as a group flag? After all, groups
> > are included or excluded from the link together.
> >  GRP_EXCLUDE
> >    Sections in a group with GRP_EXCLUDE set should be discarded from
> >    the link.
> > 
> > I mean, you could kind of use groups for anything when you decide
> > grouping sections by metadata is OK.
> > Why define SHT_NOBITS when you can create:
> >  GRP_NOBITS
> >    Sections in this group occupy no space in the file. They must have
> >    type SHT_PROGBITS.
> > 
> > Retention of a section is a property of the section. We are misusing ELF
> > constructs by using groups to indicate an arbitrary section needs to be
> > retained.
> > 
> > Another issue (if more is needed) is about how to name the groups.
> > * If it is mandated that GRP_RETAIN groups have the same name e.g.
> >  "grp_retain", that means you can't put a section you want to
> >  retain in a different logical group that makes sense from the
> >  application perspective. So the other sections you would want to put
> >  in a group with the retained section need to all be put in a bundle
> >  with all the other GRP_RETAIN sections.
> > * If GRP_RETAIN groups can have any name, so you can have multiple
> >  GRP_RETAIN groups, how does the compiler decide how to name the
> >  groups? It seems like it would be a mess. "grp_retain0", "grp_retain2"
> >  ... "grp_retain10" from one object file, "grp_retain0"...
> >  "grp_retain5" from another. Extra processing in the
> >  linker to clean up these group names and keep them unique would be
> >  required when performing a relocatable link.
> > 
> > As a general point, what if I decide that there's enough pressure from
> > the anti-SHF_GNU_RETAIN side that I change the implementation to use
> > groups. But then those who already backed the flag prefer that method
> > over using groups think the implementation should not have been changed.
> > 
> > I feel like we already got enough backing for SHF_GNU_RETAIN between the
> > GNU gABI and Binutils discussions. I understand, and welcome, more
> > feedback, but I haven't been convinced any other method is obviously
> > better than SHF_GNU_RETAIN, so why change it?
> > 
> > I'm not saying it's possible to quantify which mechanism for "retain" is
> > best, but SHF_GNU_RETAIN is the simplest, most obvious, and easiest to
> > understand. Surely that gives it top marks?
> > 
> > I'm also yet to hear one convincing reason why SHF_GNU_RETAIN is bad.
> > As far as I can tell, the main argument against it stems from the fact
> > that you can have two input sections with the same name but different
> > SHF_GNU_RETAIN flag states. Not only is this a non-issue, groups have
> > exactly the same problem!
> > 
> > It would be great if a global maintainer to chime in on whether the
> > attached patch is acceptable, because otherwise we are going to go back
> > and forth forever.
> > 
> > Thanks,
> > Jozef
> 
> Hi Jozef,
> 
> I have checked with a few folks on the LLVM side. James Henderson and James Y
> Knight seem to prefer a section flag to other mechanism. I prefer a
> section flag, too (I was on the fence and wanted the alternatives to be considered).
> 
> About the section flag 'R' in assembly:
> 
> I'd still prefer an error to not add another exception to https://sourceware.org/pipermail/binutils/2020-February/109945.html
> (a consensus GNU as and LLVM's integrated assembler have reached)
> 
>   .section retain,"a",@progbits
>   .section retain,"aR",@progbits  # error for section flags change
> 
> If a separate section is desired, I'd prefer an explicit ,unique,0 or ,unique,1 or ...
> 
>   .section retain,"a",@progbits
>   .section retain,"aR",@progbits,unique,0   # 'unique' is a binutils 2.35 feature (available in LLVM for a while)
> 
> 
> About the use case in GCC (and probably Clang in the future):
> 
>   // a.h
>   __attribute__((section("sec"))) inline void bar() { ... }
> 
>   // a.c
>   #include "a.h"
>   __attribute__((section("sec"), retain))   // retain may be the pre-existing used.
>   void foo() { ... }
> 
> Perhaps there needs a function attribute to lower to ,unique,1 in assembly.

Hi Fangrui,

My revised implementation for the "retain" attribute in GCC is for
declarations with this attribute to always be placed in their own,
uniquely named section. This will leverage the same mechanism that the
-f{function,data}-sections options use. The "unique" option to the
.section directive will not be required.

I don't think there is any downside to doing this, compared to using the
default section name, and it solves the issue of having two sections
with the same name but different flags.

I therefore no longer have any specific need for
>   .section retain,"a",@progbits
>   .section retain,"aR",@progbits  # error for section flags change
to be supported by GAS, and could remove that support from my next
iteration of the Binutils patch.

Thanks,
Jozef

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-10-02 12:41           ` H.J. Lu
@ 2020-10-02 12:53             ` Jozef Lawrynowicz
  0 siblings, 0 replies; 22+ messages in thread
From: Jozef Lawrynowicz @ 2020-10-02 12:53 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Alan Modra, Binutils

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

On Fri, Oct 02, 2020 at 05:41:13AM -0700, H.J. Lu via Binutils wrote:
> On Fri, Oct 2, 2020 at 5:33 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > On Fri, Oct 2, 2020 at 5:30 AM Jozef Lawrynowicz
> > <jozef.l@mittosystems.com> wrote:
> > >
> > > On Thu, Oct 01, 2020 at 09:09:07PM +0930, Alan Modra via Binutils wrote:
> > > > On Thu, Oct 01, 2020 at 11:50:33AM +0100, Jozef Lawrynowicz wrote:
> > > > > --- a/bfd/elflink.c
> > > > > +++ b/bfd/elflink.c
> > > > > @@ -14102,7 +14102,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)))
> > > >
> > > > Flag bits in SHF_MASKOS depend on OS, so this needs a test of OSABI.
> > > > That can be done by checking elf_tdata (sub)->has_gnu_osabi for the
> > > > appropriate bit.
> > > >
> > >
> > > Fixed the two OSABI issues in the attached patch.
> > >
> >
> > Please rebase since this part has been changed on master branch.
> >
> 
> + || (elf_tdata (sub)->has_gnu_osabi & elf_gnu_osabi_retain
> +     && elf_section_flags (o) & SHF_GNU_RETAIN)))
> 
> Also please add () for elf_tdata (sub)->has_gnu_osabi & elf_gnu_osabi_retain
> and elf_section_flags (o) & SHF_GNU_RETAIN.

Fixed in the attached patch.

Thanks,
Jozef
> 
> -- 
> H.J.

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

From 896dc063edadde2dd5b01073b22a2052b430efd7 Mon Sep 17 00:00:00 2001
From: Jozef Lawrynowicz <jozef.l@mittosystems.com>
Date: Thu, 1 Oct 2020 11:49:04 +0100
Subject: [PATCH] Support SHF_GNU_RETAIN ELF section flag

The SHF_GNU_RETAIN section flag is an extension to the GNU ELF OSABI.
It is defined as follows:

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

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

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

Note that there is not a direct mapping of SHF_GNU_RETAIN to the BFD
section flag SEC_KEEP. This would prevent the user being able to
explicitly remove an SHF_GNU_RETAIN section by placing it in /DISCARD/.

bfd/ChangeLog:

2020-10-02  H.J. Lu  <hongjiu.lu@intel.com>
	Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* elf-bfd.h (enum elf_gnu_osabi): Add elf_gnu_osabi_retain.
	(struct elf_obj_tdata): Increase has_gnu_osabi to 4 bits.
	* elf.c (_bfd_elf_make_section_from_shdr): Set elf_gnu_osabi_retain
	for SHF_GNU_RETAIN.
	(_bfd_elf_final_write_processing): Report if SHF_GNU_RETAIN is
	not supported by the OSABI.
	Adjust error messages.
	* elflink.c (bfd_elf_gc_sections): gc_mark the section if
	SHF_GNU_RETAIN is set.

binutils/ChangeLog:

2020-10-02  Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* NEWS: Announce SHF_GNU_RETAIN.
	* readelf.c (get_elf_section_flags): Handle SHF_GNU_RETAIN.
	Recognize SHF_GNU_RETAIN and SHF_GNU_MBIND only for supported OSABIs.
	* testsuite/binutils-all/readelf.exp: Run new test.
	Don't run run_dump_test when there isn't an assembler available.
	* testsuite/lib/binutils-common.exp (supports_gnu_osabi): Adjust
	comment.
	* testsuite/binutils-all/retain1.d: New test.
	* testsuite/binutils-all/retain1.s: New test.

gas/ChangeLog:

2020-10-02  H.J. Lu  <hongjiu.lu@intel.com>
	Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* NEWS: Announce SHF_GNU_RETAIN.
	* config/obj-elf.c (SEC_ASSEMBLER_SHF_MASK): New.
	(get_section): Use SEC_ASSEMBLER_SHF_MASK.
	(obj_elf_change_section): Update struct member name.
	(obj_elf_parse_section_letters): Handle 'R' flag.
	Handle numeric flag values within the SHF_MASKOS range.
	(obj_elf_section): Set elf_gnu_osabi_retain
	for SHF_GNU_RETAIN.
	* config/obj-elf.h (struct elf_section_match): Adjust "info" member
	name to "sh_info".  Add "sh_flags" member.
	* doc/as.texi (Section): Document 'R' flag.
	* testsuite/gas/elf/elf.exp: Run new tests.
	* testsuite/gas/elf/section10.d: Don't test SHF_GNU_RETAIN bit of
	section flag.
	* testsuite/gas/elf/section10.s: Don't set SHF_GNU_RETAIN bit of
	section flag.
	* testsuite/gas/elf/section22.d: New test.
	* testsuite/gas/elf/section22.s: New test.
	* testsuite/gas/elf/section23.s: New test.
	* testsuite/gas/elf/section23a.d: New test.
	* testsuite/gas/elf/section23b.d: New test.
	* testsuite/gas/elf/section23b.err: New test.

include/ChangeLog:

2020-10-02  Jozef Lawrynowicz  <jozef.l@mittosystems.com>

	* elf/common.h (SHF_GNU_RETAIN): Define.

ld/ChangeLog:

2020-10-02  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
	H.J. Lu  <hongjiu.lu@intel.com>

	* NEWS: Announce SHF_GNU_RETAIN.
	* ld.texi (garbage collection): Document SHF_GNU_RETAIN.
	(Output Section Discarding): Likewise.
	* testsuite/ld-elf/elf.exp: Run new tests.
	* testsuite/ld-elf/retain1.s: New test.
	* testsuite/ld-elf/retain1a.d: New test.
	* testsuite/ld-elf/retain1b.d: New test.
	* testsuite/ld-elf/retain2.d: New test.
	* testsuite/ld-elf/retain2.ld: New test.
	* testsuite/ld-elf/retain2.map: New test.
	* testsuite/ld-elf/retain3.d: New test.
	* testsuite/ld-elf/retain3.s: New test.
	* testsuite/ld-elf/retain4.d: New test.
	* testsuite/ld-elf/retain4.s: New test.
	* testsuite/ld-elf/retain5.d: New test.
	* testsuite/ld-elf/retain5.map: New test.
	* testsuite/ld-elf/retain5lib.s: New test.
	* testsuite/ld-elf/retain5main.s: New test.
	* testsuite/ld-elf/retain6a.d: New test.
	* testsuite/ld-elf/retain6b.d: New test.
	* testsuite/ld-elf/retain6lib.s: New test.
	* testsuite/ld-elf/retain6main.s: New test.
	* testsuite/ld-elf/retain7.s: New test.
	* testsuite/ld-elf/retain7a.d: New test.
	* testsuite/ld-elf/retain7b.d: New test.
---
 bfd/elf-bfd.h                               |   9 +-
 bfd/elf.c                                   |  17 +++-
 bfd/elflink.c                               |   4 +-
 binutils/NEWS                               |   4 +
 binutils/readelf.c                          |  21 +++-
 binutils/testsuite/binutils-all/readelf.exp |   6 +-
 binutils/testsuite/binutils-all/retain1.d   |  18 ++++
 binutils/testsuite/binutils-all/retain1.s   | 104 ++++++++++++++++++++
 binutils/testsuite/lib/binutils-common.exp  |   5 +-
 gas/NEWS                                    |   6 ++
 gas/config/obj-elf.c                        |  65 +++++++++---
 gas/config/obj-elf.h                        |   3 +-
 gas/doc/as.texi                             |   3 +
 gas/testsuite/gas/elf/elf.exp               |   3 +
 gas/testsuite/gas/elf/section10.d           |   4 +-
 gas/testsuite/gas/elf/section10.s           |   4 +-
 gas/testsuite/gas/elf/section22.d           |  19 ++++
 gas/testsuite/gas/elf/section22.s           |  34 +++++++
 gas/testsuite/gas/elf/section23.s           |  11 +++
 gas/testsuite/gas/elf/section23a.d          |  11 +++
 gas/testsuite/gas/elf/section23b.d          |   6 ++
 gas/testsuite/gas/elf/section23b.err        |   2 +
 include/elf/common.h                        |   1 +
 ld/NEWS                                     |   4 +
 ld/ld.texi                                  |   8 ++
 ld/testsuite/ld-elf/elf.exp                 |  11 +++
 ld/testsuite/ld-elf/retain1.s               | 104 ++++++++++++++++++++
 ld/testsuite/ld-elf/retain1a.d              |  28 ++++++
 ld/testsuite/ld-elf/retain1b.d              |  11 +++
 ld/testsuite/ld-elf/retain2.d               |   6 ++
 ld/testsuite/ld-elf/retain2.ld              |   7 ++
 ld/testsuite/ld-elf/retain2.map             |  32 ++++++
 ld/testsuite/ld-elf/retain3.d               |  12 +++
 ld/testsuite/ld-elf/retain3.s               |  19 ++++
 ld/testsuite/ld-elf/retain4.d               |  10 ++
 ld/testsuite/ld-elf/retain4.s               |  13 +++
 ld/testsuite/ld-elf/retain5.d               |  12 +++
 ld/testsuite/ld-elf/retain5.map             |   5 +
 ld/testsuite/ld-elf/retain5lib.s            |   6 ++
 ld/testsuite/ld-elf/retain5main.s           |   5 +
 ld/testsuite/ld-elf/retain6a.d              |  14 +++
 ld/testsuite/ld-elf/retain6b.d              |  11 +++
 ld/testsuite/ld-elf/retain6lib.s            |  17 ++++
 ld/testsuite/ld-elf/retain6main.s           |  13 +++
 ld/testsuite/ld-elf/retain7.s               | 104 ++++++++++++++++++++
 ld/testsuite/ld-elf/retain7a.d              |  28 ++++++
 ld/testsuite/ld-elf/retain7b.d              |  11 +++
 47 files changed, 822 insertions(+), 29 deletions(-)
 create mode 100644 binutils/testsuite/binutils-all/retain1.d
 create mode 100644 binutils/testsuite/binutils-all/retain1.s
 create mode 100644 gas/testsuite/gas/elf/section22.d
 create mode 100644 gas/testsuite/gas/elf/section22.s
 create mode 100644 gas/testsuite/gas/elf/section23.s
 create mode 100644 gas/testsuite/gas/elf/section23a.d
 create mode 100644 gas/testsuite/gas/elf/section23b.d
 create mode 100644 gas/testsuite/gas/elf/section23b.err
 create mode 100644 ld/testsuite/ld-elf/retain1.s
 create mode 100644 ld/testsuite/ld-elf/retain1a.d
 create mode 100644 ld/testsuite/ld-elf/retain1b.d
 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.d
 create mode 100644 ld/testsuite/ld-elf/retain3.s
 create mode 100644 ld/testsuite/ld-elf/retain4.d
 create mode 100644 ld/testsuite/ld-elf/retain4.s
 create mode 100644 ld/testsuite/ld-elf/retain5.d
 create mode 100644 ld/testsuite/ld-elf/retain5.map
 create mode 100644 ld/testsuite/ld-elf/retain5lib.s
 create mode 100644 ld/testsuite/ld-elf/retain5main.s
 create mode 100644 ld/testsuite/ld-elf/retain6a.d
 create mode 100644 ld/testsuite/ld-elf/retain6b.d
 create mode 100644 ld/testsuite/ld-elf/retain6lib.s
 create mode 100644 ld/testsuite/ld-elf/retain6main.s
 create mode 100644 ld/testsuite/ld-elf/retain7.s
 create mode 100644 ld/testsuite/ld-elf/retain7a.d
 create mode 100644 ld/testsuite/ld-elf/retain7b.d

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 140a98594d..ffb75f7919 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1897,14 +1897,15 @@ struct output_elf_obj_tdata
   bfd_boolean flags_init;
 };
 
-/* Indicate if the bfd contains SHF_GNU_MBIND sections or symbols that
-   have the STT_GNU_IFUNC symbol type or STB_GNU_UNIQUE binding.  Used
-   to set the osabi field in the ELF header structure.  */
+/* Indicate if the bfd contains SHF_GNU_MBIND/SHF_GNU_RETAIN sections or
+   symbols that have the STT_GNU_IFUNC symbol type or STB_GNU_UNIQUE
+   binding.  Used to set the osabi field in the ELF header structure.  */
 enum elf_gnu_osabi
 {
   elf_gnu_osabi_mbind = 1 << 0,
   elf_gnu_osabi_ifunc = 1 << 1,
   elf_gnu_osabi_unique = 1 << 2,
+  elf_gnu_osabi_retain = 1 << 3,
 };
 
 typedef struct elf_section_list
@@ -2034,7 +2035,7 @@ struct elf_obj_tdata
   ENUM_BITFIELD (dynamic_lib_link_class) dyn_lib_class : 4;
 
   /* Whether the bfd uses OS specific bits that require ELFOSABI_GNU.  */
-  ENUM_BITFIELD (elf_gnu_osabi) has_gnu_osabi : 3;
+  ENUM_BITFIELD (elf_gnu_osabi) has_gnu_osabi : 4;
 
   /* Whether if the bfd contains the GNU_PROPERTY_NO_COPY_ON_PROTECTED
      property.  */
diff --git a/bfd/elf.c b/bfd/elf.c
index 00594020c9..5daf8ec0f5 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1068,9 +1068,12 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
       /* FIXME: We should not recognize SHF_GNU_MBIND for ELFOSABI_NONE,
 	 but binutils as of 2019-07-23 did not set the EI_OSABI header
 	 byte.  */
-    case ELFOSABI_NONE:
     case ELFOSABI_GNU:
     case ELFOSABI_FREEBSD:
+      if ((hdr->sh_flags & SHF_GNU_RETAIN) != 0)
+	elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_retain;
+      /* Fall through */
+    case ELFOSABI_NONE:
       if ((hdr->sh_flags & SHF_GNU_MBIND) != 0)
 	elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_mbind;
       break;
@@ -12476,11 +12479,17 @@ _bfd_elf_final_write_processing (bfd *abfd)
 	       && i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_FREEBSD)
 	{
 	  if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_mbind)
-	    _bfd_error_handler (_("GNU_MBIND section is unsupported"));
+	    _bfd_error_handler (_("GNU_MBIND section is supported only by GNU "
+				  "and FreeBSD targets"));
 	  if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_ifunc)
-	    _bfd_error_handler (_("symbol type STT_GNU_IFUNC is unsupported"));
+	    _bfd_error_handler (_("symbol type STT_GNU_IFUNC is supported "
+				  "only by GNU and FreeBSD targets"));
 	  if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_unique)
-	    _bfd_error_handler (_("symbol binding STB_GNU_UNIQUE is unsupported"));
+	    _bfd_error_handler (_("symbol binding STB_GNU_UNIQUE is supported "
+				  "only by GNU and FreeBSD targets"));
+	  if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_retain)
+	    _bfd_error_handler (_("GNU_RETAIN section is supported "
+				  "only by GNU and FreeBSD targets"));
 	  bfd_set_error (bfd_error_sorry);
 	  return FALSE;
 	}
diff --git a/bfd/elflink.c b/bfd/elflink.c
index e23d189b98..742254055c 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -14103,7 +14103,9 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
 			    == SHT_FINI_ARRAY)))
 		|| (elf_section_data (o)->this_hdr.sh_type == SHT_NOTE
 		    && elf_next_in_group (o) == NULL
-		    && elf_linked_to_section (o) == NULL)))
+		    && elf_linked_to_section (o) == NULL)
+		|| ((elf_tdata (sub)->has_gnu_osabi & elf_gnu_osabi_retain)
+		    && (elf_section_flags (o) & SHF_GNU_RETAIN))))
 	  {
 	    if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
 	      return FALSE;
diff --git a/binutils/NEWS b/binutils/NEWS
index c0dc73d7d8..6c7d3f3953 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -4,6 +4,10 @@
   symbol names.  In addition the --demangle=<style>, --no-demangle,
   --recurse-limit and --no-recurse-limit options are also now availale.
 
+* Add support for the SHF_GNU_RETAIN ELF section flag.
+  This flag specifies that the section should not be garbage collected by the
+  linker if it is unused.
+
 Changes in 2.35:
 
 * Changed readelf's display of symbol names when wide mode is not enabled.
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 9ba4e29a65..5b3e508aef 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)
@@ -6009,7 +6011,6 @@ get_elf_section_flags (Filedata * filedata, bfd_vma sh_flags)
 	    case SHF_TLS:		sindex = 9; break;
 	    case SHF_EXCLUDE:		sindex = 18; break;
 	    case SHF_COMPRESSED:	sindex = 20; break;
-	    case SHF_GNU_MBIND:		sindex = 24; break;
 
 	    default:
 	      sindex = -1;
@@ -6063,6 +6064,23 @@ get_elf_section_flags (Filedata * filedata, bfd_vma sh_flags)
 		  break;
 
 		default:
+		  switch (filedata->file_header.e_ident[EI_OSABI])
+		    {
+		    case ELFOSABI_GNU:
+		    case ELFOSABI_FREEBSD:
+		      if (flag == SHF_GNU_RETAIN)
+			sindex = 26;
+		      /* Fall through */
+		    case ELFOSABI_NONE:
+		      if (flag == SHF_GNU_MBIND)
+			/* We should not recognize SHF_GNU_MBIND for
+			   ELFOSABI_NONE, but binutils as of 2019-07-23 did
+			   not set the EI_OSABI header byte.  */
+			sindex = 24;
+		      break;
+		    default:
+		      break;
+		    }
 		  break;
 		}
 	    }
@@ -6108,6 +6126,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/binutils/testsuite/binutils-all/readelf.exp b/binutils/testsuite/binutils-all/readelf.exp
index 1fb36ae5c4..6dea09e305 100644
--- a/binutils/testsuite/binutils-all/readelf.exp
+++ b/binutils/testsuite/binutils-all/readelf.exp
@@ -364,8 +364,12 @@ readelf_wi_test
 readelf_compressed_wa_test
 
 readelf_dump_test
-run_dump_test "pr25543"
 
+# These dump tests require an assembler.
+if {[which $AS] != 0} then {
+    run_dump_test "pr25543"
+    run_dump_test "retain1"
+}
 
 # PR 13482 - Check for off-by-one errors when dumping .note sections.
 if {![binutils_assemble $srcdir/$subdir/version.s tmpdir/version.o]} then {
diff --git a/binutils/testsuite/binutils-all/retain1.d b/binutils/testsuite/binutils-all/retain1.d
new file mode 100644
index 0000000000..01cd32a475
--- /dev/null
+++ b/binutils/testsuite/binutils-all/retain1.d
@@ -0,0 +1,18 @@
+#source: retain1.s
+#readelf: -S --wide
+#name: readelf SHF_GNU_RETAIN
+#notarget: ![supports_gnu_osabi]
+
+#...
+  \[[ 0-9]+\] .bss.retain0.*WAR.*
+  \[[ 0-9]+\] .bss.retain1.*WAR.*
+  \[[ 0-9]+\] .data.retain2.*WAR.*
+  \[[ 0-9]+\] .bss.sretain0.*WAR.*
+  \[[ 0-9]+\] .bss.sretain1.*WAR.*
+  \[[ 0-9]+\] .data.sretain2.*WAR.*
+  \[[ 0-9]+\] .text.fnretain1.*AXR.*
+#...
+  \[[ 0-9]+\] .bss.lsretain0.*WAR.*
+  \[[ 0-9]+\] .bss.lsretain1.*WAR.*
+  \[[ 0-9]+\] .data.lsretain2.*WAR.*
+#pass
diff --git a/binutils/testsuite/binutils-all/retain1.s b/binutils/testsuite/binutils-all/retain1.s
new file mode 100644
index 0000000000..f7716faabe
--- /dev/null
+++ b/binutils/testsuite/binutils-all/retain1.s
@@ -0,0 +1,104 @@
+	.global	discard0
+	.section	.bss.discard0,"aw"
+	.type	discard0, %object
+discard0:
+	.zero	2
+
+	.global	discard1
+	.section	.bss.discard1,"aw"
+	.type	discard1, %object
+discard1:
+	.zero	2
+
+	.global	discard2
+	.section	.data.discard2,"aw"
+	.type	discard2, %object
+discard2:
+	.word	1
+
+	.section	.bss.sdiscard0,"aw"
+	.type	sdiscard0, %object
+sdiscard0:
+	.zero	2
+
+	.section	.bss.sdiscard1,"aw"
+	.type	sdiscard1, %object
+sdiscard1:
+	.zero	2
+
+	.section	.data.sdiscard2,"aw"
+	.type	sdiscard2, %object
+sdiscard2:
+	.word	1
+
+	.section	.text.fndiscard0,"ax"
+	.global	fndiscard0
+	.type	fndiscard0, %function
+fndiscard0:
+	.word 0
+
+	.global	retain0
+	.section	.bss.retain0,"awR"
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.global	retain1
+	.section	.bss.retain1,"awR"
+	.type	retain1, %object
+retain1:
+	.zero	2
+
+	.global	retain2
+	.section	.data.retain2,"awR"
+	.type	retain2, %object
+retain2:
+	.word	1
+
+	.section	.bss.sretain0,"awR"
+	.type	sretain0, %object
+sretain0:
+	.zero	2
+
+	.section	.bss.sretain1,"awR"
+	.type	sretain1, %object
+sretain1:
+	.zero	2
+
+	.section	.data.sretain2,"aRw"
+	.type	sretain2, %object
+sretain2:
+	.word	1
+
+	.section	.text.fnretain1,"Rax"
+	.global	fnretain1
+	.type	fnretain1, %function
+fnretain1:
+	.word	0
+
+	.section	.text.fndiscard2,"ax"
+	.global	fndiscard2
+	.type	fndiscard2, %function
+fndiscard2:
+	.word	0
+
+	.section	.bss.lsretain0,"awR"
+	.type	lsretain0.2, %object
+lsretain0.2:
+	.zero	2
+
+	.section	.bss.lsretain1,"aRw"
+	.type	lsretain1.1, %object
+lsretain1.1:
+	.zero	2
+
+	.section	.data.lsretain2,"aRw"
+	.type	lsretain2.0, %object
+lsretain2.0:
+	.word	1
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/binutils/testsuite/lib/binutils-common.exp b/binutils/testsuite/lib/binutils-common.exp
index b9a1e6e4bc..a43639bafb 100644
--- a/binutils/testsuite/lib/binutils-common.exp
+++ b/binutils/testsuite/lib/binutils-common.exp
@@ -195,13 +195,15 @@ proc match_target { target } {
 
 # True if the ELF target supports setting the ELF header OSABI field
 # to ELFOSABI_GNU or ELFOSABI_FREEBSD, a requirement for STT_GNU_IFUNC
-# symbol and SHF_GNU_MBIND section support.
+# symbol and SHF_GNU_MBIND or SHF_GNU_RETAIN section support.
 #
 # This generally depends on the target OS only, however there are a
 # number of exceptions for bare metal targets as follows.  The MSP430
 # and Visium targets set OSABI to ELFOSABI_STANDALONE.  Likewise
 # non-EABI ARM targets set OSABI to ELFOSABI_ARM
 #
+# Non-Linux HPPA defaults to ELFOSABI_HPUX.
+#
 # Note that some TI C6X targets use ELFOSABI_C6000_* but one doesn't,
 # so we don't try to sort out tic6x here.  (The effect is that linker
 # testcases will generally need to exclude tic6x or use a -m option.)
@@ -227,6 +229,7 @@ proc supports_gnu_osabi {} {
     }
     if { [istarget "arm*-*-*"]
 	 || [istarget "msp430-*-*"]
+	 || [istarget "hppa-unknown-elf"]
 	 || [istarget "visium-*-*"] } {
 	return 0
     }
diff --git a/gas/NEWS b/gas/NEWS
index 12f5f4baae..479a26a1c6 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -34,6 +34,12 @@
 
 * Configure with --enable-x86-used-note by default for Linux/x86.
 
+* Add support for the "R" flag in the .section directive.
+  This flag requires ELFOSABI_GNU or ELFOSABI_FREEBSD, and applies the
+  ELF SHF_GNU_RETAIN flag to the specified section.  This flag specifies
+  the section should not be garbage collected by the linker if it is
+  unused.
+
 Changes in 2.35:
 
 * X86 NaCl target support is removed.
diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index 45de821495..44de02a912 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -519,6 +519,10 @@ struct section_stack
 
 static struct section_stack *section_stack;
 
+/* Create unique input sections for sections with the same name, but different
+   values for the flags in this mask.  */
+#define SEC_ASSEMBLER_SHF_MASK SHF_GNU_RETAIN
+
 static bfd_boolean
 get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
 {
@@ -527,9 +531,12 @@ get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
   const char *group_name = elf_group_name (sec);
   const char *linked_to_symbol_name
     = sec->map_head.linked_to_symbol_name;
-  unsigned int info = elf_section_data (sec)->this_hdr.sh_info;
+  unsigned int sh_info = elf_section_data (sec)->this_hdr.sh_info;
+  bfd_vma sh_flags = (elf_section_data (sec)->this_hdr.sh_flags
+		      & SEC_ASSEMBLER_SHF_MASK);
 
-  return (info == match->info
+  return (sh_info == match->sh_info
+	  && sh_flags == match->sh_flags
 	  && ((bfd_section_flags (sec) & SEC_ASSEMBLER_SECTION_ID)
 	       == (match->flags & SEC_ASSEMBLER_SECTION_ID))
 	  && sec->section_id == match->section_id
@@ -738,7 +745,7 @@ obj_elf_change_section (const char *name,
 	type = bfd_elf_get_default_section_type (flags);
       elf_section_type (sec) = type;
       elf_section_flags (sec) = attr;
-      elf_section_data (sec)->this_hdr.sh_info = match_p->info;
+      elf_section_data (sec)->this_hdr.sh_info = match_p->sh_info;
 
       /* Prevent SEC_HAS_CONTENTS from being inadvertently set.  */
       if (type == SHT_NOBITS)
@@ -859,6 +866,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;
@@ -888,8 +898,32 @@ obj_elf_parse_section_letters (char *str, size_t len,
 	      if (ISDIGIT (*str))
 		{
 		  char * end;
+		  struct elf_backend_data *bed;
+		  bfd_vma numeric_flags = strtoul (str, &end, 0);
+
+		  attr |= numeric_flags;
+
+		  bed = (struct elf_backend_data *)
+		    get_elf_backend_data (stdoutput);
+
+		  if (bed->elf_osabi == ELFOSABI_NONE
+		      || bed->elf_osabi == ELFOSABI_STANDALONE
+		      || bed->elf_osabi == ELFOSABI_GNU
+		      || bed->elf_osabi == ELFOSABI_FREEBSD)
+		    {
+		      /* Add flags in the SHF_MASKOS range to gnu_attr for
+			 OSABIs that support those flags.
+			 Also adding the flags for ELFOSABI_{NONE,STANDALONE}
+			 allows them to be validated later in obj_elf_section.
+			 We can't just always set these bits in gnu_attr for
+			 all OSABIs, since Binutils does not recognize all
+			 SHF_MASKOS bits for non-GNU OSABIs.  It's therefore
+			 possible that numeric flags are being used to set bits
+			 in the SHF_MASKOS range for those targets, and we
+			 don't want assembly to fail in those situations.  */
+		      *gnu_attr |= (numeric_flags & SHF_MASKOS);
+		    }
 
-		  attr |= strtoul (str, & end, 0);
 		  /* Update str and len, allowing for the fact that
 		     we will execute str++ and len-- below.  */
 		  end --;
@@ -1274,18 +1308,21 @@ obj_elf_section (int push)
 	      if (ISDIGIT (* input_line_pointer))
 		{
 		  char *t = input_line_pointer;
-		  match.info = strtoul (input_line_pointer,
+		  match.sh_info = strtoul (input_line_pointer,
 					&input_line_pointer, 0);
-		  if (match.info == (unsigned int) -1)
+		  if (match.sh_info == (unsigned int) -1)
 		    {
 		      as_warn (_("unsupported mbind section info: %s"), t);
-		      match.info = 0;
+		      match.sh_info = 0;
 		    }
 		}
 	      else
 		input_line_pointer = save;
 	    }
 
+	  if ((gnu_attr & SHF_GNU_RETAIN) != 0)
+	    match.sh_flags |= SHF_GNU_RETAIN;
+
 	  if (*input_line_pointer == ',')
 	    {
 	      char *save = input_line_pointer;
@@ -1376,11 +1413,12 @@ obj_elf_section (int push)
   obj_elf_change_section (name, type, attr, entsize, &match, linkonce,
 			  push);
 
-  if ((gnu_attr & SHF_GNU_MBIND) != 0)
+  if ((gnu_attr & (SHF_GNU_MBIND | SHF_GNU_RETAIN)) != 0)
     {
       struct elf_backend_data *bed;
+      bfd_boolean mbind_p = (gnu_attr & SHF_GNU_MBIND) != 0;
 
-      if ((attr & SHF_ALLOC) == 0)
+      if (mbind_p && (attr & SHF_ALLOC) == 0)
 	as_bad (_("SHF_ALLOC isn't set for GNU_MBIND section: %s"), name);
 
       bed = (struct elf_backend_data *) get_elf_backend_data (stdoutput);
@@ -1388,9 +1426,12 @@ obj_elf_section (int push)
 	bed->elf_osabi = ELFOSABI_GNU;
       else if (bed->elf_osabi != ELFOSABI_GNU
 	       && bed->elf_osabi != ELFOSABI_FREEBSD)
-	as_bad (_("GNU_MBIND section is supported only by GNU "
-		  "and FreeBSD targets"));
-      elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_mbind;
+	as_bad (_("%s section is supported only by GNU and FreeBSD targets"),
+		mbind_p ? "GNU_MBIND" : "GNU_RETAIN");
+      if (mbind_p)
+	elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_mbind;
+      if ((gnu_attr & SHF_GNU_RETAIN) != 0)
+	elf_tdata (stdoutput)->has_gnu_osabi |= elf_gnu_osabi_retain;
     }
   elf_section_flags (now_seg) |= gnu_attr;
 
diff --git a/gas/config/obj-elf.h b/gas/config/obj-elf.h
index b39a1a1ab6..6eb0a8ede4 100644
--- a/gas/config/obj-elf.h
+++ b/gas/config/obj-elf.h
@@ -106,8 +106,9 @@ struct elf_section_match
 {
   const char *group_name;
   const char *linked_to_symbol_name;
-  unsigned int info;
   unsigned int section_id;
+  unsigned int sh_info;		/* ELF section information.  */
+  bfd_vma sh_flags;		/* ELF section flags.  */
   flagword flags;
 };
 
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index c0baa94536..dbe9bd4ff1 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -6657,6 +6657,9 @@ section is a member of a section group
 section is used for thread-local-storage
 @item ?
 section is a member of the previously-current section's group, if any
+@item R
+retained section (apply SHF_GNU_RETAIN to prevent linker garbage
+collection, GNU ELF extension)
 @item @code{<number>}
 a numeric value indicating the bits to be set in the ELF section header's flags
 field.  Note - if one or more of the alphabetic characters described above is
diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
index 5ce9691b38..556af433b5 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -261,6 +261,9 @@ if { [is_elf_format] } then {
     run_dump_test "section19"
     run_dump_test "section20"
     run_dump_test "section21"
+    run_dump_test "section22"
+    run_dump_test "section23a"
+    run_dump_test "section23b"
     run_dump_test "dwarf2-1" $dump_opts
     run_dump_test "dwarf2-2" $dump_opts
     run_dump_test "dwarf2-3" $dump_opts
diff --git a/gas/testsuite/gas/elf/section10.d b/gas/testsuite/gas/elf/section10.d
index 554a791f1d..6aa7b088b1 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\)
+[ 	]*\[.*fedff030\]: 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\)
+[ 	]*\[.*fedf0000\]:.* EXCLUDE, OS \(.*ed00000\), PROC \(.*[3467]0000000\), UNKNOWN \(.*f0000\)
 [ 	]*\[.*\][ 	]+.data.foo
 [ 	]*LOUSER\+0x7f000000[ 	].*
 [ 	]*\[0+003\]: WRITE, ALLOC
diff --git a/gas/testsuite/gas/elf/section10.s b/gas/testsuite/gas/elf/section10.s
index 29f1184523..d52b3458fb 100644
--- a/gas/testsuite/gas/elf/section10.s
+++ b/gas/testsuite/gas/elf/section10.s
@@ -7,7 +7,7 @@
 	.word 2
 
 	# Make sure that specifying further arguments to .sections is still supported
-	.section sec3, "0xfefff000MS", %progbits, 32
+	.section sec3, "0xfedff000MS", %progbits, 32
 	.word 3
 
 	# Make sure that extra flags can be set for well known sections as well.
@@ -19,7 +19,7 @@
 	.word 5
 
 	# Test both together, with a quoted type value.
-	.section sec5, "0xfeff0000", "0x80000009"
+	.section sec5, "0xfedf0000", "0x80000009"
 	.word 6
 
 	# Test that declaring an extended version of a known special section works.
diff --git a/gas/testsuite/gas/elf/section22.d b/gas/testsuite/gas/elf/section22.d
new file mode 100644
index 0000000000..27d9127745
--- /dev/null
+++ b/gas/testsuite/gas/elf/section22.d
@@ -0,0 +1,19 @@
+#readelf: -h -S --wide
+#name: SHF_GNU_RETAIN sections 22
+#notarget: ![supports_gnu_osabi]
+
+#...
+ +OS/ABI: +UNIX - GNU
+#...
+  \[..\] .text[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  AX.*
+#...
+  \[..\] .data[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+#...
+  \[..\] .bss[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00  WA.*
+#...
+  \[..\] .bss[ 	]+NOBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#...
+  \[..\] .data[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#...
+  \[..\] .text[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXR.*
+#pass
diff --git a/gas/testsuite/gas/elf/section22.s b/gas/testsuite/gas/elf/section22.s
new file mode 100644
index 0000000000..6e2b95c1e8
--- /dev/null
+++ b/gas/testsuite/gas/elf/section22.s
@@ -0,0 +1,34 @@
+	.section	.text,"ax",%progbits
+	.global	discard0
+	.type	discard0, %function
+discard0:
+	.word	0
+
+	.section	.data,"aw"
+	.global	discard1
+	.type	discard1, %object
+discard1:
+	.word	1
+
+	.section	.bss,"aw"
+	.global	discard2
+	.type	discard2, %object
+discard2:
+	.zero	2
+
+	.section	.bss,"awR",%nobits
+	.global	retain0
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.section	.data,"awR",%progbits
+	.type	retain1, %object
+retain1:
+	.word	1
+
+	.section	.text,"axR",%progbits
+	.global	retain2
+	.type	retain2, %function
+retain2:
+	.word	0
diff --git a/gas/testsuite/gas/elf/section23.s b/gas/testsuite/gas/elf/section23.s
new file mode 100644
index 0000000000..d671119bca
--- /dev/null
+++ b/gas/testsuite/gas/elf/section23.s
@@ -0,0 +1,11 @@
+  .section	.data.retain_var,"0x200003"
+	.global	retain_var
+	.type	retain_var, %object
+retain_var:
+	.long	2
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/gas/testsuite/gas/elf/section23a.d b/gas/testsuite/gas/elf/section23a.d
new file mode 100644
index 0000000000..1d850d9e8e
--- /dev/null
+++ b/gas/testsuite/gas/elf/section23a.d
@@ -0,0 +1,11 @@
+#name: SHF_GNU_RETAIN set with numeric flag value in .section
+#source: section23.s
+#target: [supports_gnu_osabi]
+#readelf: -h -S --wide
+
+#...
+ +OS/ABI: +UNIX - GNU
+#...
+  \[..\] .data.retain_var[ 	]+PROGBITS[ 	]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#pass
+
diff --git a/gas/testsuite/gas/elf/section23b.d b/gas/testsuite/gas/elf/section23b.d
new file mode 100644
index 0000000000..c85200e5ff
--- /dev/null
+++ b/gas/testsuite/gas/elf/section23b.d
@@ -0,0 +1,6 @@
+#name: SHF_GNU_RETAIN set with numeric flag value in .section for non-GNU OSABI target
+#source: section23.s
+#error_output: section23b.err
+#target: msp430-*-elf visium-*-elf
+
+# This test only runs for targets which set ELFOSABI_STANDALONE.
diff --git a/gas/testsuite/gas/elf/section23b.err b/gas/testsuite/gas/elf/section23b.err
new file mode 100644
index 0000000000..83de60c397
--- /dev/null
+++ b/gas/testsuite/gas/elf/section23b.err
@@ -0,0 +1,2 @@
+.*: Assembler messages:
+.*:1: Error: GNU_RETAIN section is supported only by GNU and FreeBSD targets
diff --git a/include/elf/common.h b/include/elf/common.h
index 571e21af29..c01e562c78 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/NEWS b/ld/NEWS
index e4ae43b257..72cdf0edd3 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -15,6 +15,10 @@
   unless you are working on a project that has its own analogue
   of symbol tables that are not reflected in the ELF symtabs.
 
+* Add support for the SHF_GNU_RETAIN ELF section flag.
+  This flag specifies that the section should not be garbage collected by the
+  linker if it is unused.
+
 Changes in 2.35:
 
 * X86 NaCl target support is removed.
diff --git a/ld/ld.texi b/ld/ld.texi
index ee592df6c2..526b642d78 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1787,6 +1787,10 @@ specified either by one of the options @samp{--entry},
 @samp{--undefined}, or @samp{--gc-keep-exported} or by a @code{ENTRY}
 command in the linker script.
 
+As a GNU extension, ELF input sections marked with the
+@code{SHF_GNU_RETAIN} flag will not be garbage collected if they are
+unused.
+
 @kindex --print-gc-sections
 @kindex --no-print-gc-sections
 @cindex garbage collection
@@ -5232,6 +5236,10 @@ The special output section name @samp{/DISCARD/} may be used to discard
 input sections.  Any input sections which are assigned to an output
 section named @samp{/DISCARD/} are not included in the output file.
 
+This can be used to discard input sections marked with the ELF flag
+@code{SHF_GNU_RETAIN}, which would otherwise have been saved from linker
+garbage collection when they are unused.
+
 Note, sections that match the @samp{/DISCARD/} output section will be
 discarded even if they are in an ELF section group which has other
 members which are not being discarded.  This is deliberate.
diff --git a/ld/testsuite/ld-elf/elf.exp b/ld/testsuite/ld-elf/elf.exp
index f2ff0397c7..bd06ab0d39 100644
--- a/ld/testsuite/ld-elf/elf.exp
+++ b/ld/testsuite/ld-elf/elf.exp
@@ -119,6 +119,17 @@ if { [istarget "i?86-*-*"] || [istarget "x86_64-*-*"] } {
     set ASFLAGS "$ASFLAGS -mx86-used-note=no"
 }
 
+# Build libraries required for SHF_GNU_RETAIN tests.
+if { [check_gc_sections_available] && [supports_gnu_osabi] } {
+    run_ld_link_tests [list \
+	[list "Build libretain5.a" "" "" "" \
+	    {retain5lib.s} {} "libretain5.a"] \
+	[list "Build libretain6.a" "" "" "" \
+	    {retain6lib.s} {} "libretain6.a"] \
+	]
+}
+
+
 set test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
 foreach t $test_list {
     # We need to strip the ".d", but can leave the dirname.
diff --git a/ld/testsuite/ld-elf/retain1.s b/ld/testsuite/ld-elf/retain1.s
new file mode 100644
index 0000000000..f7716faabe
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1.s
@@ -0,0 +1,104 @@
+	.global	discard0
+	.section	.bss.discard0,"aw"
+	.type	discard0, %object
+discard0:
+	.zero	2
+
+	.global	discard1
+	.section	.bss.discard1,"aw"
+	.type	discard1, %object
+discard1:
+	.zero	2
+
+	.global	discard2
+	.section	.data.discard2,"aw"
+	.type	discard2, %object
+discard2:
+	.word	1
+
+	.section	.bss.sdiscard0,"aw"
+	.type	sdiscard0, %object
+sdiscard0:
+	.zero	2
+
+	.section	.bss.sdiscard1,"aw"
+	.type	sdiscard1, %object
+sdiscard1:
+	.zero	2
+
+	.section	.data.sdiscard2,"aw"
+	.type	sdiscard2, %object
+sdiscard2:
+	.word	1
+
+	.section	.text.fndiscard0,"ax"
+	.global	fndiscard0
+	.type	fndiscard0, %function
+fndiscard0:
+	.word 0
+
+	.global	retain0
+	.section	.bss.retain0,"awR"
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.global	retain1
+	.section	.bss.retain1,"awR"
+	.type	retain1, %object
+retain1:
+	.zero	2
+
+	.global	retain2
+	.section	.data.retain2,"awR"
+	.type	retain2, %object
+retain2:
+	.word	1
+
+	.section	.bss.sretain0,"awR"
+	.type	sretain0, %object
+sretain0:
+	.zero	2
+
+	.section	.bss.sretain1,"awR"
+	.type	sretain1, %object
+sretain1:
+	.zero	2
+
+	.section	.data.sretain2,"aRw"
+	.type	sretain2, %object
+sretain2:
+	.word	1
+
+	.section	.text.fnretain1,"Rax"
+	.global	fnretain1
+	.type	fnretain1, %function
+fnretain1:
+	.word	0
+
+	.section	.text.fndiscard2,"ax"
+	.global	fndiscard2
+	.type	fndiscard2, %function
+fndiscard2:
+	.word	0
+
+	.section	.bss.lsretain0,"awR"
+	.type	lsretain0.2, %object
+lsretain0.2:
+	.zero	2
+
+	.section	.bss.lsretain1,"aRw"
+	.type	lsretain1.1, %object
+lsretain1.1:
+	.zero	2
+
+	.section	.data.lsretain2,"aRw"
+	.type	lsretain2.0, %object
+lsretain2.0:
+	.word	1
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain1a.d b/ld/testsuite/ld-elf/retain1a.d
new file mode 100644
index 0000000000..75abb9856c
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1a.d
@@ -0,0 +1,28 @@
+#name: SHF_GNU_RETAIN 1a
+#source: retain1.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . fnretain1
+#...
+[0-9a-f]+ . lsretain0.2
+#...
+[0-9a-f]+ . lsretain1.1
+#...
+[0-9a-f]+ . lsretain2.0
+#...
+[0-9a-f]+ . retain0
+#...
+[0-9a-f]+ . retain1
+#...
+[0-9a-f]+ . retain2
+#...
+[0-9a-f]+ . sretain0
+#...
+[0-9a-f]+ . sretain1
+#...
+[0-9a-f]+ . sretain2
+#pass
diff --git a/ld/testsuite/ld-elf/retain1b.d b/ld/testsuite/ld-elf/retain1b.d
new file mode 100644
index 0000000000..815c0150f5
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1b.d
@@ -0,0 +1,11 @@
+#name: SHF_GNU_RETAIN 1b
+#source: retain1.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#nm: -n
+
+#failif
+#...
+[0-9a-f]+ . .*discard.*
+#...
diff --git a/ld/testsuite/ld-elf/retain2.d b/ld/testsuite/ld-elf/retain2.d
new file mode 100644
index 0000000000..11efd6ddb8
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.d
@@ -0,0 +1,6 @@
+#name: SHF_GNU_RETAIN 2 (remove SHF_GNU_RETAIN sections by placing in /DISCARD/)
+#source: retain1.s
+#ld: -e _start -Map=retain2.map --gc-sections --script=retain2.ld
+#map: retain2.map
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
diff --git a/ld/testsuite/ld-elf/retain2.ld b/ld/testsuite/ld-elf/retain2.ld
new file mode 100644
index 0000000000..8ef982753c
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.ld
@@ -0,0 +1,7 @@
+SECTIONS
+{
+  /DISCARD/ :
+  {
+    *(.text.fnretain1)
+  }
+}
diff --git a/ld/testsuite/ld-elf/retain2.map b/ld/testsuite/ld-elf/retain2.map
new file mode 100644
index 0000000000..4028aa1f58
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.map
@@ -0,0 +1,32 @@
+# Test that .text.fnretain1, which has the SHF_GNU_RETAIN flag, can still be
+# explicitly discarded from the output file.
+
+#...
+Discarded input sections
+
+ .text.*
+#...
+ .data.*
+#...
+ .bss.*
+#...
+ .bss.discard0.*
+#...
+ .bss.discard1.*
+#...
+ .data.discard2.*
+#...
+ .bss.sdiscard0.*
+#...
+ .bss.sdiscard1.*
+#...
+ .data.sdiscard2.*
+#...
+ .text.fndiscard0.*
+#...
+ .text.fnretain1.*
+#...
+ .text.fndiscard2.*
+#...
+Memory Configuration
+#pass
diff --git a/ld/testsuite/ld-elf/retain3.d b/ld/testsuite/ld-elf/retain3.d
new file mode 100644
index 0000000000..911f5b7594
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain3.d
@@ -0,0 +1,12 @@
+#name: SHF_GNU_RETAIN 3 (keep sections referenced by retained sections)
+#source: retain3.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . bar
+#...
+[0-9a-f]+ . foo
+#pass
diff --git a/ld/testsuite/ld-elf/retain3.s b/ld/testsuite/ld-elf/retain3.s
new file mode 100644
index 0000000000..ce315cbaa6
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain3.s
@@ -0,0 +1,19 @@
+/* The retention of bar should also prevent foo from being gc'ed, since bar
+   references foo.  */
+	.section	.text.foo,"ax"
+	.global	foo
+	.type	foo, %function
+foo:
+	.word 0
+
+	.section	.text.bar,"axR"
+	.global	bar
+	.type	bar, %function
+bar:
+	.long foo
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain4.d b/ld/testsuite/ld-elf/retain4.d
new file mode 100644
index 0000000000..e94898d681
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain4.d
@@ -0,0 +1,10 @@
+#name: SHF_GNU_RETAIN 4 (keep orphaned sections when not discarding)
+#source: retain4.s
+#ld: -e _start --gc-sections --orphan-handling=place
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . orphaned_fn
+#pass
diff --git a/ld/testsuite/ld-elf/retain4.s b/ld/testsuite/ld-elf/retain4.s
new file mode 100644
index 0000000000..9f350cd3b2
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain4.s
@@ -0,0 +1,13 @@
+/* A section which doesn't match any linker script input section rules but
+   has SHF_GNU_RETAIN applied should not be garbage collected.  */
+	.section	.orphaned_section,"axR"
+	.global	orphaned_fn
+	.type	orphaned_fn, %function
+orphaned_fn:
+	.word 0
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain5.d b/ld/testsuite/ld-elf/retain5.d
new file mode 100644
index 0000000000..378799599e
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5.d
@@ -0,0 +1,12 @@
+#name: SHF_GNU_RETAIN 5 (don't pull SHF_GNU_RETAIN section out of lib)
+#source: retain5main.s
+#ld: --gc-sections -e _start --print-gc-sections -Ltmpdir -lretain5 -Map=retain5.map
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#map: retain5.map
+#DUMPPROG: nm
+
+#failif
+#...
+[0-9a-f]+ . foo
+#...
diff --git a/ld/testsuite/ld-elf/retain5.map b/ld/testsuite/ld-elf/retain5.map
new file mode 100644
index 0000000000..6b97c2a220
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5.map
@@ -0,0 +1,5 @@
+# Check that the library was actually loaded to catch any false PASS.
+
+#...
+LOAD tmpdir/libretain5.a
+#pass
diff --git a/ld/testsuite/ld-elf/retain5lib.s b/ld/testsuite/ld-elf/retain5lib.s
new file mode 100644
index 0000000000..4e83731719
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5lib.s
@@ -0,0 +1,6 @@
+/* The link will fail if foo is included because undefined_sym is not defined.  */
+	.section	.text.foo,"axR"
+	.global	foo
+	.type	foo, %function
+foo:
+	.long undefined_sym
diff --git a/ld/testsuite/ld-elf/retain5main.s b/ld/testsuite/ld-elf/retain5main.s
new file mode 100644
index 0000000000..89a7784d13
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5main.s
@@ -0,0 +1,5 @@
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain6a.d b/ld/testsuite/ld-elf/retain6a.d
new file mode 100644
index 0000000000..92872deffc
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6a.d
@@ -0,0 +1,14 @@
+#name: SHF_GNU_RETAIN 6a (pull section out of lib required by SHF_GNU_RETAIN section)
+#source: retain6main.s
+#ld: --gc-sections -e _start -u bar -Ltmpdir -lretain6
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . bar
+#...
+[0-9a-f]+ . retain_from_lib
+#...
+[0-9a-f]+ . retained_fn
+#pass
diff --git a/ld/testsuite/ld-elf/retain6b.d b/ld/testsuite/ld-elf/retain6b.d
new file mode 100644
index 0000000000..a797bf7837
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6b.d
@@ -0,0 +1,11 @@
+#name: SHF_GNU_RETAIN 6b (pull section out of lib required by SHF_GNU_RETAIN section)
+#source: retain6main.s
+#ld: --gc-sections -e _start -u bar -Ltmpdir -lretain6
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#failif
+#...
+[0-9a-f]+ . .*discard.*
+#...
diff --git a/ld/testsuite/ld-elf/retain6lib.s b/ld/testsuite/ld-elf/retain6lib.s
new file mode 100644
index 0000000000..a393dbac61
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6lib.s
@@ -0,0 +1,17 @@
+	.section	.text.bar,"ax"
+	.global	bar
+	.type	bar, %function
+bar:
+	.word 0
+
+	.section	.text.retain_from_lib,"axR"
+	.global	retain_from_lib
+	.type	retain_from_lib, %function
+retain_from_lib:
+	.word 0
+
+	.section	.text.discard_from_lib,"ax"
+	.global	discard_from_lib
+	.type	discard_from_lib, %function
+discard_from_lib:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain6main.s b/ld/testsuite/ld-elf/retain6main.s
new file mode 100644
index 0000000000..a66c5b3247
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6main.s
@@ -0,0 +1,13 @@
+/* Undefined symbol reference in retained section .text.retained_fn requires
+   symbol definition to be pulled out of library.  */
+	.section	.text.retained_fn,"axR"
+	.global	retained_fn
+	.type	retained_fn, %function
+retained_fn:
+	.long bar
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain7.s b/ld/testsuite/ld-elf/retain7.s
new file mode 100644
index 0000000000..2d80947fbd
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7.s
@@ -0,0 +1,104 @@
+	.section	.bss,"aw"
+	.global	discard0
+	.type	discard0, %object
+discard0:
+	.zero	2
+
+	.section	.bss,"aw"
+	.global	discard1
+	.type	discard1, %object
+discard1:
+	.zero	2
+
+	.section	.data,"aw"
+	.global	discard2
+	.type	discard2, %object
+discard2:
+	.word	1
+
+	.section	.bss,"aw"
+	.type	sdiscard0, %object
+sdiscard0:
+	.zero	2
+
+	.section	.bss,"aw"
+	.type	sdiscard1, %object
+sdiscard1:
+	.zero	2
+
+	.section	.data,"aw"
+	.type	sdiscard2, %object
+sdiscard2:
+	.word	1
+
+	.text
+	.global	fndiscard0
+	.type	fndiscard0, %function
+fndiscard0:
+	.word 0
+
+	.section	.bss,"awR"
+	.global	retain0
+	.type	retain0, %object
+retain0:
+	.zero	2
+
+	.section	.bss,"awR"
+	.global	retain1
+	.type	retain1, %object
+retain1:
+	.zero	2
+
+	.section	.data,"awR"
+	.global	retain2
+	.type	retain2, %object
+retain2:
+	.word	1
+
+	.section	.bss,"awR"
+	.type	sretain0, %object
+sretain0:
+	.zero	2
+
+	.section	.bss,"awR"
+	.type	sretain1, %object
+sretain1:
+	.zero	2
+
+	.section	.data,"aRw"
+	.type	sretain2, %object
+sretain2:
+	.word	1
+
+	.section	.text,"Rax"
+	.global	fnretain1
+	.type	fnretain1, %function
+fnretain1:
+	.word	0
+
+	.section	.text,"ax"
+	.global	fndiscard2
+	.type	fndiscard2, %function
+fndiscard2:
+	.word	0
+
+	.section	.bss,"awR"
+	.type	lsretain0.2, %object
+lsretain0.2:
+	.zero	2
+
+	.section	.bss,"aRw"
+	.type	lsretain1.1, %object
+lsretain1.1:
+	.zero	2
+
+	.section	.data,"aRw"
+	.type	lsretain2.0, %object
+lsretain2.0:
+	.word	1
+
+	.section	.text._start,"ax"
+	.global	_start
+	.type	_start, %function
+_start:
+	.word 0
diff --git a/ld/testsuite/ld-elf/retain7a.d b/ld/testsuite/ld-elf/retain7a.d
new file mode 100644
index 0000000000..055bb74da9
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7a.d
@@ -0,0 +1,28 @@
+#name: SHF_GNU_RETAIN 7a (flag applied to default section names)
+#source: retain7.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . fnretain1
+#...
+[0-9a-f]+ . lsretain0.2
+#...
+[0-9a-f]+ . lsretain1.1
+#...
+[0-9a-f]+ . lsretain2.0
+#...
+[0-9a-f]+ . retain0
+#...
+[0-9a-f]+ . retain1
+#...
+[0-9a-f]+ . retain2
+#...
+[0-9a-f]+ . sretain0
+#...
+[0-9a-f]+ . sretain1
+#...
+[0-9a-f]+ . sretain2
+#pass
diff --git a/ld/testsuite/ld-elf/retain7b.d b/ld/testsuite/ld-elf/retain7b.d
new file mode 100644
index 0000000000..f268047c35
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7b.d
@@ -0,0 +1,11 @@
+#name: SHF_GNU_RETAIN 7b (flag applied to default section names)
+#source: retain7.s
+#ld: -e _start --gc-sections
+#skip: mep-*-* dlx-*-* d30v-*-* pj-*-* pru-*-* xgate-*-* s12z-*-*
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#nm: -n
+
+#failif
+#...
+[0-9a-f]+ . .*discard.*
+#...
-- 
2.28.0


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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-10-02 12:30       ` Jozef Lawrynowicz
  2020-10-02 12:33         ` H.J. Lu
@ 2020-10-02 14:11         ` Alan Modra
  2020-10-02 15:45           ` Jozef Lawrynowicz
  1 sibling, 1 reply; 22+ messages in thread
From: Alan Modra @ 2020-10-02 14:11 UTC (permalink / raw)
  To: H.J. Lu, Binutils

On Fri, Oct 02, 2020 at 01:30:23PM +0100, Jozef Lawrynowicz wrote:
> On Thu, Oct 01, 2020 at 09:09:07PM +0930, Alan Modra via Binutils wrote:
> > On Thu, Oct 01, 2020 at 11:50:33AM +0100, Jozef Lawrynowicz wrote:
> > > --- a/bfd/elflink.c
> > > +++ b/bfd/elflink.c
> > > @@ -14102,7 +14102,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)))
> > 
> > Flag bits in SHF_MASKOS depend on OS, so this needs a test of OSABI.
> > That can be done by checking elf_tdata (sub)->has_gnu_osabi for the
> > appropriate bit.
> > 
> 
> Fixed the two OSABI issues in the attached patch.

I didn't mention it, but readelf has two occurrences of decoding
SHF_GNU_UNIQUE.  They both need fixing, not just the first one.

> > > +* Add support for the SHF_GNU_RETAIN ELF section flag.
> > > +  This flag specifies that the section should not be garbage collected by the
> > > +  linker if it is unused.
> > 
> > I would drop "if it is unused".  The phrase doesn't really add
> > anything to a user's understanding.
> > 
> 
> I don't really have a strong opinion either way, but I thought "if it is
> unused" might be helpful to add to the description since "garbage
> collection" is not precisely defined in ELF.

The reason I don't particularly like "if it is unused" is that it
sounds like something said by someone who doesn't really understand
linker garbage collection.  "used" and "referenced by a relocation
from a kept section" are only loosely related.  And indeed the whole
purpose of SHF_GNU_RETAIN is surely to keep needed sections, ones that
are used for some purpose.

-- 
Alan Modra
Australia Development Lab, IBM

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

* Re: [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag
  2020-10-02 14:11         ` Alan Modra
@ 2020-10-02 15:45           ` Jozef Lawrynowicz
  0 siblings, 0 replies; 22+ messages in thread
From: Jozef Lawrynowicz @ 2020-10-02 15:45 UTC (permalink / raw)
  To: Alan Modra; +Cc: H.J. Lu, Binutils

On Fri, Oct 02, 2020 at 11:41:10PM +0930, Alan Modra via Binutils wrote:
> On Fri, Oct 02, 2020 at 01:30:23PM +0100, Jozef Lawrynowicz wrote:
> > On Thu, Oct 01, 2020 at 09:09:07PM +0930, Alan Modra via Binutils wrote:
> > > On Thu, Oct 01, 2020 at 11:50:33AM +0100, Jozef Lawrynowicz wrote:
> > > > --- a/bfd/elflink.c
> > > > +++ b/bfd/elflink.c
> > > > @@ -14102,7 +14102,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)))
> > > 
> > > Flag bits in SHF_MASKOS depend on OS, so this needs a test of OSABI.
> > > That can be done by checking elf_tdata (sub)->has_gnu_osabi for the
> > > appropriate bit.
> > > 
> > 
> > Fixed the two OSABI issues in the attached patch.
> 
> I didn't mention it, but readelf has two occurrences of decoding
> SHF_GNU_UNIQUE.  They both need fixing, not just the first one.

Well in fact, the part I added OSABI handling to already in readelf
wasn't correct anyway, those nested switch/if-else/switch statements
caught me out ;)
Cleaning that up is a task for some other time, however.

I started adding tests to validate the readelf output with/without "-N",
when the numeric values for SHF_GNU_{RETAIN,MBIND} are set, for targets
which neither error when these bits are set (ELFOSABI_STANDALONE) nor
handle them as their GNU OSABI values (ELFOSABI_{NONE,GNU,FREEBSD}).

However, hppa-unknown-elf is the only target I've been testing that
satisfies these constraints (ELFOSABI_HPUX), so I'm going to find some
others to validate the changes and finish this off next week.

> 
> > > > +* Add support for the SHF_GNU_RETAIN ELF section flag.
> > > > +  This flag specifies that the section should not be garbage collected by the
> > > > +  linker if it is unused.
> > > 
> > > I would drop "if it is unused".  The phrase doesn't really add
> > > anything to a user's understanding.
> > > 
> > 
> > I don't really have a strong opinion either way, but I thought "if it is
> > unused" might be helpful to add to the description since "garbage
> > collection" is not precisely defined in ELF.
> 
> The reason I don't particularly like "if it is unused" is that it
> sounds like something said by someone who doesn't really understand
> linker garbage collection.  "used" and "referenced by a relocation
> from a kept section" are only loosely related.  And indeed the whole
> purpose of SHF_GNU_RETAIN is surely to keep needed sections, ones that
> are used for some purpose.

Sounds fair to me. The precise ELF definition is targeting technical
users after all.

Thanks,
Jozef

> 
> -- 
> Alan Modra
> Australia Development Lab, IBM

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

end of thread, other threads:[~2020-10-02 15:45 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-28 13:26 [PATCH v2] Support for SHF_GNU_RETAIN ELF Section Flag Jozef Lawrynowicz
2020-09-29  4:43 ` Fangrui Song
2020-09-29 10:04   ` Jozef Lawrynowicz
2020-09-29 19:38     ` Fangrui Song
2020-09-29 19:54       ` H.J. Lu
2020-09-29 21:37       ` Jozef Lawrynowicz
2020-09-30  0:10         ` Roland McGrath
2020-09-30 10:18           ` Jozef Lawrynowicz
2020-09-30 14:01             ` H.J. Lu
2020-10-01 19:22             ` Fangrui Song
2020-10-01 19:53               ` H.J. Lu
2020-10-02 12:44               ` Jozef Lawrynowicz
2020-09-30 14:13           ` Michael Matz
2020-09-30 22:13 ` H.J. Lu
2020-10-01 10:50   ` Jozef Lawrynowicz
2020-10-01 11:39     ` Alan Modra
2020-10-02 12:30       ` Jozef Lawrynowicz
2020-10-02 12:33         ` H.J. Lu
2020-10-02 12:41           ` H.J. Lu
2020-10-02 12:53             ` Jozef Lawrynowicz
2020-10-02 14:11         ` Alan Modra
2020-10-02 15:45           ` 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).