[PATCH] Support SHF_GNU_RETAIN ELF section flag
Jozef Lawrynowicz
jozef.l@mittosystems.com
Tue Sep 22 20:29:33 GMT 2020
The attached patch adds support for the new SHF_GNU_RETAIN ELF section
flag, which was discussed on the GNU gABI mailing list here:
https://sourceware.org/pipermail/gnu-gabi/2020q3/000429.html
The flag is GNU-specific so uses a bit in the SHF_MASKOS mask.
Its precise definition is 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.
=======================================================================
The overall intention for this new flag is to enable a new "retain"
attribute to be applied to declarations of functions and data in the
source code. This attribute can be used to ensure the definition
associated with the declaration is present in the linked output file,
even if linker garbage collection would normally remove the containing
section because it is unused.
The new ".retain" assembler directive can be used to apply
SHF_GNU_RETAIN to a section. GCC will emit this directive when
assembling definitions of functions and data that have had the "retain"
attribute applied.
Note that there is *not* a direct mapping of SHF_GNU_RETAIN to the BFD
section flag SEC_KEEP. SEC_KEEP would prevent the user being able to
explicitly remove an SHF_GNU_RETAIN section by placing it in /DISCARD/,
which could be necessary in some situations.
I successfully regtested the patch for the Binutils, GAS and LD
testsuites for the following CPUs, applying the "-elf" suffix when
configuring:
aarch64 alpha arc arm avr bfin bpf cr16 cris crx csky d10v d30v dlx
epiphany fr30 frv ft32 h8300 hppa i386 ia64 ia64-vms ip2k iq2000 lm32
m32c m32r m68hc11 m68hc12 m68k mcore mep metag microblaze mips mmix
moxie msp430 mt nds32 nfp nios2 or1k pj ppc pru riscv rl78 rx s12z
s390 score sh sparc spu tic6x tilegx tilepro v850 vax visium wasm32
x86-64 x86 xc16x xgate xstormy16 xtensa z80
The new tests are passing for all targets except mmix-elf. This target
has a lot of LD failures, particularly --gc-sections doesn't appear to
have any effect. I don't know anything about the target, but I wonder if
it should be added to the hard-coded list of targets that doesn't
support --gc-sections. I have therefore XFAIL'd the new LD tests for
this target.
I also regtested for i386-pe, to ensure there was no spill-over of the
new functionality into any non-ELF areas.
Ok to apply?
Thanks,
Jozef
-------------- next part --------------
>From d7f92cd05883567cf07cb8878aa60b666894197d 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.
=======================================================================
The new ".retain" assembler directive can be used to apply
SHF_GNU_RETAIN to a section.
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-22 Jozef Lawrynowicz <jozef.l@mittosystems.com>
* elflink.c (bfd_elf_gc_sections): gc_mark the section if
SHF_GNU_RETAIN is set.
binutils/ChangeLog:
2020-09-22 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/binutils-all/retain1.d: New test.
* testsuite/binutils-all/retain1.s: New test.
gas/ChangeLog:
2020-09-22 Jozef Lawrynowicz <jozef.l@mittosystems.com>
* NEWS: Announce .retain directive and SHF_GNU_RETAIN.
* config/obj-elf.c (elf_pseudo_table): Add "retain".
(obj_elf_retain): New.
(obj_elf_parse_section_letters): Handle 'R' flag.
* doc/as.texi: Document .retain directive.
(Section): Document 'R' flag.
* testsuite/gas/elf/elf.exp: Run new tests.
* testsuite/gas/elf/retain1.d: New test.
* testsuite/gas/elf/retain1.s: New test.
* testsuite/gas/elf/retain2.d: New test.
* testsuite/gas/elf/retain2.l: New test.
* testsuite/gas/elf/retain2.s: New test.
* testsuite/gas/elf/retain3.d: New test.
* testsuite/gas/elf/retain3.s: New test.
* testsuite/gas/elf/section10.d: Adjust test.
include/ChangeLog:
2020-09-22 Jozef Lawrynowicz <jozef.l@mittosystems.com>
* elf/common.h (SHF_GNU_RETAIN): Define.
ld/ChangeLog:
2020-09-22 Jozef Lawrynowicz <jozef.l@mittosystems.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.msg: New test.
* testsuite/ld-elf/retain3.s: New test.
* testsuite/ld-elf/retain4.s: New test.
* testsuite/ld-elf/retain5.s: New test.
* testsuite/ld-elf/retain6lib.s: New test.
* testsuite/ld-elf/retain6main.s: New test.
* testsuite/ld-elf/retain7.msg: New test.
* testsuite/ld-elf/retain7lib.s: New test.
* testsuite/ld-elf/retain7main.s: New test.
---
bfd/elflink.c | 3 +-
binutils/NEWS | 4 +
binutils/readelf.c | 4 +
binutils/testsuite/binutils-all/readelf.exp | 6 +-
binutils/testsuite/binutils-all/retain1.d | 17 +++
binutils/testsuite/binutils-all/retain1.s | 114 ++++++++++++++++++++
gas/NEWS | 4 +
gas/config/obj-elf.c | 59 ++++++++++
gas/doc/as.texi | 20 ++++
gas/testsuite/gas/elf/elf.exp | 5 +
gas/testsuite/gas/elf/retain1.d | 24 +++++
gas/testsuite/gas/elf/retain1.s | 114 ++++++++++++++++++++
gas/testsuite/gas/elf/retain2.d | 3 +
gas/testsuite/gas/elf/retain2.l | 3 +
gas/testsuite/gas/elf/retain2.s | 7 ++
gas/testsuite/gas/elf/retain3.d | 24 +++++
gas/testsuite/gas/elf/retain3.s | 104 ++++++++++++++++++
gas/testsuite/gas/elf/section10.d | 4 +-
include/elf/common.h | 1 +
ld/NEWS | 4 +
ld/ld.texi | 8 ++
ld/testsuite/ld-elf/elf.exp | 38 ++++++-
ld/testsuite/ld-elf/retain1.msg | 9 ++
ld/testsuite/ld-elf/retain1.s | 114 ++++++++++++++++++++
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.msg | 9 ++
ld/testsuite/ld-elf/retain3.s | 104 ++++++++++++++++++
ld/testsuite/ld-elf/retain4.s | 19 ++++
ld/testsuite/ld-elf/retain5.s | 13 +++
ld/testsuite/ld-elf/retain6lib.s | 6 ++
ld/testsuite/ld-elf/retain6main.s | 5 +
ld/testsuite/ld-elf/retain7.msg | 1 +
ld/testsuite/ld-elf/retain7lib.s | 17 +++
ld/testsuite/ld-elf/retain7main.s | 13 +++
36 files changed, 921 insertions(+), 5 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/retain1.d
create mode 100644 gas/testsuite/gas/elf/retain1.s
create mode 100644 gas/testsuite/gas/elf/retain2.d
create mode 100644 gas/testsuite/gas/elf/retain2.l
create mode 100644 gas/testsuite/gas/elf/retain2.s
create mode 100644 gas/testsuite/gas/elf/retain3.d
create mode 100644 gas/testsuite/gas/elf/retain3.s
create mode 100644 ld/testsuite/ld-elf/retain1.msg
create mode 100644 ld/testsuite/ld-elf/retain1.s
create mode 100644 ld/testsuite/ld-elf/retain2.d
create mode 100644 ld/testsuite/ld-elf/retain2.ld
create mode 100644 ld/testsuite/ld-elf/retain2.map
create mode 100644 ld/testsuite/ld-elf/retain3.msg
create mode 100644 ld/testsuite/ld-elf/retain3.s
create mode 100644 ld/testsuite/ld-elf/retain4.s
create mode 100644 ld/testsuite/ld-elf/retain5.s
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.msg
create mode 100644 ld/testsuite/ld-elf/retain7lib.s
create mode 100644 ld/testsuite/ld-elf/retain7main.s
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 0e339f3c1e..6d1a1c5105 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -13977,7 +13977,8 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
|| (elf_section_data (o)->this_hdr.sh_type
== SHT_FINI_ARRAY)))
|| (elf_section_data (o)->this_hdr.sh_type == SHT_NOTE
- && elf_next_in_group (o) == NULL )))
+ && elf_next_in_group (o) == NULL)
+ || (elf_section_flags (o) & SHF_GNU_RETAIN)))
{
if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
return FALSE;
diff --git a/binutils/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 cb4208f7b9..00502f7058 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -5977,6 +5977,8 @@ get_elf_section_flags (Filedata * filedata, bfd_vma sh_flags)
/* 24 */ { STRING_COMMA_LEN ("GNU_MBIND") },
/* VLE specific. */
/* 25 */ { STRING_COMMA_LEN ("VLE") },
+ /* GNU specific. */
+ /* 26 */ { STRING_COMMA_LEN ("GNU_RETAIN") },
};
if (do_section_details)
@@ -6010,6 +6012,7 @@ get_elf_section_flags (Filedata * filedata, bfd_vma sh_flags)
case SHF_EXCLUDE: sindex = 18; break;
case SHF_COMPRESSED: sindex = 20; break;
case SHF_GNU_MBIND: sindex = 24; break;
+ case SHF_GNU_RETAIN: sindex = 26; break;
default:
sindex = -1;
@@ -6108,6 +6111,7 @@ get_elf_section_flags (Filedata * filedata, bfd_vma sh_flags)
case SHF_EXCLUDE: *p = 'E'; break;
case SHF_COMPRESSED: *p = 'C'; break;
case SHF_GNU_MBIND: *p = 'D'; break;
+ case SHF_GNU_RETAIN: *p = 'R'; break;
default:
if ((filedata->file_header.e_machine == EM_X86_64
diff --git a/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..35d7373cc1
--- /dev/null
+++ b/binutils/testsuite/binutils-all/retain1.d
@@ -0,0 +1,17 @@
+#source: retain1.s
+#readelf: -S --wide
+#name: readelf SHF_GNU_RETAIN
+
+#...
+ \[[ 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..e799ff72ec
--- /dev/null
+++ b/binutils/testsuite/binutils-all/retain1.s
@@ -0,0 +1,114 @@
+ .global discard0
+ .section .bss.discard0,"aw"
+ .type discard0, STT_OBJECT
+discard0:
+ .zero 2
+
+ .global discard1
+ .section .bss.discard1,"aw"
+ .type discard1, STT_OBJECT
+discard1:
+ .zero 2
+
+ .global discard2
+ .section .data.discard2,"aw"
+ .type discard2, STT_OBJECT
+discard2:
+ .word 1
+
+ .section .bss.sdiscard0,"aw"
+ .type sdiscard0, STT_OBJECT
+sdiscard0:
+ .zero 2
+
+ .section .bss.sdiscard1,"aw"
+ .type sdiscard1, STT_OBJECT
+sdiscard1:
+ .zero 2
+
+ .section .data.sdiscard2,"aw"
+ .type sdiscard2, STT_OBJECT
+sdiscard2:
+ .word 1
+
+ .section .text.fndiscard0,"ax"
+ .global fndiscard0
+ .type fndiscard0, STT_FUNC
+fndiscard0:
+ .word 0
+
+ .global retain0
+ .section .bss.retain0,"aw"
+ .type retain0, STT_OBJECT
+ .retain .bss.retain0
+retain0:
+ .zero 2
+
+ .global retain1
+ .section .bss.retain1,"aw"
+ .type retain1, STT_OBJECT
+ .retain .bss.retain1
+retain1:
+ .zero 2
+
+ .global retain2
+ .section .data.retain2,"aw"
+ .type retain2, STT_OBJECT
+ .retain .data.retain2
+retain2:
+ .word 1
+
+ .section .bss.sretain0,"aw"
+ .type sretain0, STT_OBJECT
+ .retain .bss.sretain0
+sretain0:
+ .zero 2
+
+ .section .bss.sretain1,"aw"
+ .type sretain1, STT_OBJECT
+ .retain .bss.sretain1
+sretain1:
+ .zero 2
+
+ .section .data.sretain2,"aw"
+ .type sretain2, STT_OBJECT
+ .retain .data.sretain2
+sretain2:
+ .word 1
+
+ .section .text.fnretain1,"ax"
+ .global fnretain1
+ .type fnretain1, STT_FUNC
+ .retain .text.fnretain1
+fnretain1:
+ .word 0
+
+ .section .text.fndiscard2,"ax"
+ .global fndiscard2
+ .type fndiscard2, STT_FUNC
+fndiscard2:
+ .word 0
+
+ .section .bss.lsretain0,"aw"
+ .type lsretain0.2, STT_OBJECT
+ .retain .bss.lsretain0
+lsretain0.2:
+ .zero 2
+
+ .section .bss.lsretain1,"aw"
+ .type lsretain1.1, STT_OBJECT
+ .retain .bss.lsretain1
+lsretain1.1:
+ .zero 2
+
+ .section .data.lsretain2,"aw"
+ .type lsretain2.0, STT_OBJECT
+ .retain .data.lsretain2
+lsretain2.0:
+ .word 1
+
+ .section .text._start,"ax"
+ .global _start
+ .type _start, STT_FUNC
+_start:
+ .word 0
diff --git a/gas/NEWS b/gas/NEWS
index 66afd0357b..0d63fad7b3 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -9,6 +9,10 @@
* Configure with --enable-x86-used-note by default for Linux/x86.
+* Add support for the .retain directive, which 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 9e39707801..1469a46039 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -78,6 +78,7 @@ static void obj_elf_gnu_attribute (int);
static void obj_elf_tls_common (int);
static void obj_elf_lcomm (int);
static void obj_elf_struct (int);
+static void obj_elf_retain (int);
static const pseudo_typeS elf_pseudo_table[] =
{
@@ -119,6 +120,9 @@ static const pseudo_typeS elf_pseudo_table[] =
/* A GNU extension for object attributes. */
{"gnu_attribute", obj_elf_gnu_attribute, 0},
+ /* A GNU extension for preventing linker garbage collection of sections. */
+ {"retain", obj_elf_retain, 0},
+
/* These are used for dwarf. */
{"2byte", cons, 2},
{"4byte", cons, 4},
@@ -857,6 +861,9 @@ obj_elf_parse_section_letters (char *str, size_t len,
case 'd':
*gnu_attr |= SHF_GNU_MBIND;
break;
+ case 'R':
+ *gnu_attr |= SHF_GNU_RETAIN;
+ break;
case '?':
*is_clone = TRUE;
break;
@@ -1986,6 +1993,58 @@ obj_elf_gnu_attribute (int ignored ATTRIBUTE_UNUSED)
obj_elf_vendor_attribute (OBJ_ATTR_GNU);
}
+/* Parse a ".retain [name]" directive.
+ The SHF_GNU_RETAIN flag should be applied to the section named "name".
+ If "name" is omitted, apply the flag to the current section being
+ assembled. */
+static void
+obj_elf_retain (int ignored ATTRIBUTE_UNUSED)
+{
+ const char *name;
+ symbolS *secsym;
+ asection *bfdsec;
+
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == '\n')
+ {
+ /* Handle the case when "name" isn't specified. */
+ name = now_seg->name;
+ if (name == NULL)
+ {
+ as_bad (_("\".retain\" directive not within a section"));
+ ignore_rest_of_line ();
+ return;
+ }
+ }
+ else
+ {
+ /* The "name" argument has been given, validate it. */
+ name = obj_elf_section_name ();
+ secsym = symbol_find (name);
+ if (secsym == NULL)
+ {
+ as_bad (_("section '%s' has not been declared"), name);
+ ignore_rest_of_line ();
+ return;
+ }
+ else if (secsym != NULL
+ && !symbol_section_p (secsym))
+ {
+ as_bad (_("'%s' is not a section name, expected "
+ "\".retain [name]\""), name);
+ ignore_rest_of_line ();
+ return;
+ }
+ }
+ demand_empty_rest_of_line ();
+
+ bfdsec = bfd_get_section_by_name (stdoutput, name);
+ if (bfdsec != NULL)
+ elf_section_flags (bfdsec) |= SHF_GNU_RETAIN;
+ else
+ as_bad (_("Couldn't find BFD section for %s\n"), name);
+}
+
void
elf_obj_read_begin_hook (void)
{
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index 112eaf810c..68afaa6aae 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -4468,6 +4468,7 @@ Some machine configurations provide additional directives.
* Quad:: @code{.quad @var{bignums}}
* Reloc:: @code{.reloc @var{offset}, @var{reloc_name}[, @var{expression}]}
* Rept:: @code{.rept @var{count}}
+* Retain:: @code{.retain [@var{name}]}
* Sbttl:: @code{.sbttl "@var{subheading}"}
@ifset COFF
* Scl:: @code{.scl @var{class}}
@@ -6468,6 +6469,22 @@ is equivalent to assembling
A count of zero is allowed, but nothing is generated. Negative counts are not
allowed and if encountered will be treated as if they were zero.
+@ifset ELF
+@node Retain
+@section @code{.retain [@var{name}]}
+
+@cindex @code{retain} directive
+@cindex SHF_GNU_RETAIN
+
+Apply the @code{SHF_GNU_RETAIN} flag to the section named @var{name}.
+If @var{name} is omitted, apply the flag to the current section being
+assembled.
+
+The @code{SHF_GNU_RETAIN} flag specifies that the section should not be
+garbage collected by the linker if it is unused.
+
+@end ifset
+
@node Sbttl
@section @code{.sbttl "@var{subheading}"}
@@ -6546,6 +6563,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 8520421ba3..3a4879e348 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -307,6 +307,11 @@ if { [is_elf_format] } then {
run_dump_test "strtab"
+ # Tests for the .retain directive/SHF_GNU_RETAIN.
+ run_dump_test "retain1"
+ run_dump_test "retain2"
+ run_dump_test "retain3"
+
run_dump_test "bignums"
run_dump_test "section-symbol-redef"
diff --git a/gas/testsuite/gas/elf/retain1.d b/gas/testsuite/gas/elf/retain1.d
new file mode 100644
index 0000000000..439a60ca21
--- /dev/null
+++ b/gas/testsuite/gas/elf/retain1.d
@@ -0,0 +1,24 @@
+#readelf: -S --wide
+#name: SHF_GNU_RETAIN 1
+
+#...
+ \[..\] .bss.discard0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.*
+ \[..\] .bss.discard1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.*
+ \[..\] .data.discard2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.*
+ \[..\] .bss.sdiscard0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.*
+ \[..\] .bss.sdiscard1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.*
+ \[..\] .data.sdiscard2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.*
+ \[..\] .text.fndiscard0[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AX.*
+ \[..\] .bss.retain0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .bss.retain1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .data.retain2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .bss.sretain0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .bss.sretain1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .data.sretain2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .text.fnretain1[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXR.*
+ \[..\] .text.fndiscard2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AX.*
+#...
+ \[..\] .bss.lsretain0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .bss.lsretain1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .data.lsretain2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#pass
diff --git a/gas/testsuite/gas/elf/retain1.s b/gas/testsuite/gas/elf/retain1.s
new file mode 100644
index 0000000000..e799ff72ec
--- /dev/null
+++ b/gas/testsuite/gas/elf/retain1.s
@@ -0,0 +1,114 @@
+ .global discard0
+ .section .bss.discard0,"aw"
+ .type discard0, STT_OBJECT
+discard0:
+ .zero 2
+
+ .global discard1
+ .section .bss.discard1,"aw"
+ .type discard1, STT_OBJECT
+discard1:
+ .zero 2
+
+ .global discard2
+ .section .data.discard2,"aw"
+ .type discard2, STT_OBJECT
+discard2:
+ .word 1
+
+ .section .bss.sdiscard0,"aw"
+ .type sdiscard0, STT_OBJECT
+sdiscard0:
+ .zero 2
+
+ .section .bss.sdiscard1,"aw"
+ .type sdiscard1, STT_OBJECT
+sdiscard1:
+ .zero 2
+
+ .section .data.sdiscard2,"aw"
+ .type sdiscard2, STT_OBJECT
+sdiscard2:
+ .word 1
+
+ .section .text.fndiscard0,"ax"
+ .global fndiscard0
+ .type fndiscard0, STT_FUNC
+fndiscard0:
+ .word 0
+
+ .global retain0
+ .section .bss.retain0,"aw"
+ .type retain0, STT_OBJECT
+ .retain .bss.retain0
+retain0:
+ .zero 2
+
+ .global retain1
+ .section .bss.retain1,"aw"
+ .type retain1, STT_OBJECT
+ .retain .bss.retain1
+retain1:
+ .zero 2
+
+ .global retain2
+ .section .data.retain2,"aw"
+ .type retain2, STT_OBJECT
+ .retain .data.retain2
+retain2:
+ .word 1
+
+ .section .bss.sretain0,"aw"
+ .type sretain0, STT_OBJECT
+ .retain .bss.sretain0
+sretain0:
+ .zero 2
+
+ .section .bss.sretain1,"aw"
+ .type sretain1, STT_OBJECT
+ .retain .bss.sretain1
+sretain1:
+ .zero 2
+
+ .section .data.sretain2,"aw"
+ .type sretain2, STT_OBJECT
+ .retain .data.sretain2
+sretain2:
+ .word 1
+
+ .section .text.fnretain1,"ax"
+ .global fnretain1
+ .type fnretain1, STT_FUNC
+ .retain .text.fnretain1
+fnretain1:
+ .word 0
+
+ .section .text.fndiscard2,"ax"
+ .global fndiscard2
+ .type fndiscard2, STT_FUNC
+fndiscard2:
+ .word 0
+
+ .section .bss.lsretain0,"aw"
+ .type lsretain0.2, STT_OBJECT
+ .retain .bss.lsretain0
+lsretain0.2:
+ .zero 2
+
+ .section .bss.lsretain1,"aw"
+ .type lsretain1.1, STT_OBJECT
+ .retain .bss.lsretain1
+lsretain1.1:
+ .zero 2
+
+ .section .data.lsretain2,"aw"
+ .type lsretain2.0, STT_OBJECT
+ .retain .data.lsretain2
+lsretain2.0:
+ .word 1
+
+ .section .text._start,"ax"
+ .global _start
+ .type _start, STT_FUNC
+_start:
+ .word 0
diff --git a/gas/testsuite/gas/elf/retain2.d b/gas/testsuite/gas/elf/retain2.d
new file mode 100644
index 0000000000..ca58b250b6
--- /dev/null
+++ b/gas/testsuite/gas/elf/retain2.d
@@ -0,0 +1,3 @@
+#name: SHF_GNU_RETAIN 2
+#error_output: retain2.l
+#skip: hppa-*-*
diff --git a/gas/testsuite/gas/elf/retain2.l b/gas/testsuite/gas/elf/retain2.l
new file mode 100644
index 0000000000..5a44012567
--- /dev/null
+++ b/gas/testsuite/gas/elf/retain2.l
@@ -0,0 +1,3 @@
+[^:]*: Assembler messages:
+[^:]*:1: Error: section '.data.foo' has not been declared
+[^:]*:7: Error: 'myvar' is not a section name, expected ".retain \[name\]"
diff --git a/gas/testsuite/gas/elf/retain2.s b/gas/testsuite/gas/elf/retain2.s
new file mode 100644
index 0000000000..75eb26d7f7
--- /dev/null
+++ b/gas/testsuite/gas/elf/retain2.s
@@ -0,0 +1,7 @@
+.retain ".data.foo"
+.section .data,"aw"
+.global myvar
+.type myvar, STT_OBJECT
+myvar:
+ .byte 2
+.retain "myvar"
diff --git a/gas/testsuite/gas/elf/retain3.d b/gas/testsuite/gas/elf/retain3.d
new file mode 100644
index 0000000000..2d5ca68086
--- /dev/null
+++ b/gas/testsuite/gas/elf/retain3.d
@@ -0,0 +1,24 @@
+#readelf: -S --wide
+#name: SHF_GNU_RETAIN 3 (use flags set on .section directive)
+
+#...
+ \[..\] .bss.discard0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.*
+ \[..\] .bss.discard1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.*
+ \[..\] .data.discard2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.*
+ \[..\] .bss.sdiscard0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.*
+ \[..\] .bss.sdiscard1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.*
+ \[..\] .data.sdiscard2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.*
+ \[..\] .text.fndiscard0[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AX.*
+ \[..\] .bss.retain0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .bss.retain1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .data.retain2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .bss.sretain0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .bss.sretain1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .data.sretain2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .text.fnretain1[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXR.*
+ \[..\] .text.fndiscard2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AX.*
+#...
+ \[..\] .bss.lsretain0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .bss.lsretain1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+ \[..\] .data.lsretain2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#pass
diff --git a/gas/testsuite/gas/elf/retain3.s b/gas/testsuite/gas/elf/retain3.s
new file mode 100644
index 0000000000..065399ec6f
--- /dev/null
+++ b/gas/testsuite/gas/elf/retain3.s
@@ -0,0 +1,104 @@
+ .global discard0
+ .section .bss.discard0,"aw"
+ .type discard0, STT_OBJECT
+discard0:
+ .zero 2
+
+ .global discard1
+ .section .bss.discard1,"aw"
+ .type discard1, STT_OBJECT
+discard1:
+ .zero 2
+
+ .global discard2
+ .section .data.discard2,"aw"
+ .type discard2, STT_OBJECT
+discard2:
+ .word 1
+
+ .section .bss.sdiscard0,"aw"
+ .type sdiscard0, STT_OBJECT
+sdiscard0:
+ .zero 2
+
+ .section .bss.sdiscard1,"aw"
+ .type sdiscard1, STT_OBJECT
+sdiscard1:
+ .zero 2
+
+ .section .data.sdiscard2,"aw"
+ .type sdiscard2, STT_OBJECT
+sdiscard2:
+ .word 1
+
+ .section .text.fndiscard0,"ax"
+ .global fndiscard0
+ .type fndiscard0, STT_FUNC
+fndiscard0:
+ .word 0
+
+ .global retain0
+ .section .bss.retain0,"awR"
+ .type retain0, STT_OBJECT
+retain0:
+ .zero 2
+
+ .global retain1
+ .section .bss.retain1,"awR"
+ .type retain1, STT_OBJECT
+retain1:
+ .zero 2
+
+ .global retain2
+ .section .data.retain2,"awR"
+ .type retain2, STT_OBJECT
+retain2:
+ .word 1
+
+ .section .bss.sretain0,"awR"
+ .type sretain0, STT_OBJECT
+sretain0:
+ .zero 2
+
+ .section .bss.sretain1,"awR"
+ .type sretain1, STT_OBJECT
+sretain1:
+ .zero 2
+
+ .section .data.sretain2,"aRw"
+ .type sretain2, STT_OBJECT
+sretain2:
+ .word 1
+
+ .section .text.fnretain1,"Rax"
+ .global fnretain1
+ .type fnretain1, STT_FUNC
+fnretain1:
+ .word 0
+
+ .section .text.fndiscard2,"ax"
+ .global fndiscard2
+ .type fndiscard2, STT_FUNC
+fndiscard2:
+ .word 0
+
+ .section .bss.lsretain0,"awR"
+ .type lsretain0.2, STT_OBJECT
+lsretain0.2:
+ .zero 2
+
+ .section .bss.lsretain1,"aRw"
+ .type lsretain1.1, STT_OBJECT
+lsretain1.1:
+ .zero 2
+
+ .section .data.lsretain2,"aRw"
+ .type lsretain2.0, STT_OBJECT
+lsretain2.0:
+ .word 1
+
+ .section .text._start,"ax"
+ .global _start
+ .type _start, STT_FUNC
+_start:
+ .word 0
diff --git a/gas/testsuite/gas/elf/section10.d b/gas/testsuite/gas/elf/section10.d
index 554a791f1d..ef91d7d086 100644
--- a/gas/testsuite/gas/elf/section10.d
+++ b/gas/testsuite/gas/elf/section10.d
@@ -18,7 +18,7 @@
#...
[ ]*\[.*\][ ]+sec3
[ ]*PROGBITS.*
-[ ]*\[.*fefff030\]: MERGE, STRINGS,.* EXCLUDE, OS \(.*ef00000\), PROC \(.*[3467]0000000\), UNKNOWN \(0+0ff000\)
+[ ]*\[.*fefff030\]: MERGE, STRINGS,.* EXCLUDE, OS \(.*ed00000\), PROC \(.*[3467]0000000\), UNKNOWN \(0+0ff000\)
#...
[ ]*\[.*\][ ]+sec4
[ ]*LOOS\+0x11[ ].*
@@ -26,7 +26,7 @@
#...
[ ]*\[.*\][ ]+sec5
[ ]*LOUSER\+0x9[ ].*
-[ ]*\[.*feff0000\]:.* EXCLUDE, OS \(.*ef00000\), PROC \(.*[3467]0000000\), UNKNOWN \(.*f0000\)
+[ ]*\[.*feff0000\]:.* EXCLUDE, OS \(.*ed00000\), PROC \(.*[3467]0000000\), UNKNOWN \(.*f0000\)
[ ]*\[.*\][ ]+.data.foo
[ ]*LOUSER\+0x7f000000[ ].*
[ ]*\[0+003\]: WRITE, ALLOC
diff --git a/include/elf/common.h b/include/elf/common.h
index 805058146a..364c58a7de 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -554,6 +554,7 @@
/* #define SHF_MASKOS 0x0F000000 *//* OS-specific semantics */
#define SHF_MASKOS 0x0FF00000 /* New value, Oct 4, 1999 Draft */
#define SHF_GNU_BUILD_NOTE (1 << 20) /* Section contains GNU BUILD ATTRIBUTE notes. */
+#define SHF_GNU_RETAIN (1 << 21) /* Section should not be garbage collected by the linker. */
#define SHF_MASKPROC 0xF0000000 /* Processor-specific semantics */
/* This used to be implemented as a processor specific section flag.
diff --git a/ld/NEWS b/ld/NEWS
index 695348141b..1c3cc9d20a 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -13,6 +13,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 7d961c3bb8..5daffbeb5f 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1781,6 +1781,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
@@ -5226,6 +5230,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 c0d67d80d2..bf39e0a586 100644
--- a/ld/testsuite/ld-elf/elf.exp
+++ b/ld/testsuite/ld-elf/elf.exp
@@ -188,6 +188,8 @@ if { [istarget *-*-*linux*]
]
}
+# mmix is supposed to support --gc-sections, but the option has no effect,
+# so these tests are XFAIL'd for the target.
if [check_gc_sections_available] {
run_ld_link_tests [list \
[list "__patchable_function_entries section 2" \
@@ -225,7 +227,41 @@ if [check_gc_sections_available] {
{pr25490-6.s} \
[list [list "readelf" {-SW} $pr25490_6_exp]] \
"pr25490-6.exe"] \
- ]
+ [list "SHF_GNU_RETAIN 1" \
+ "--gc-sections -e _start --print-gc-sections" "" "" \
+ {retain1.s} \
+ {{ ld retain1.msg }} \
+ "retain1.exe"] \
+ [list "SHF_GNU_RETAIN 3 (use flags set on .section directive)" \
+ "--gc-sections -e _start --print-gc-sections" "" "" \
+ {retain3.s} \
+ {{ ld retain3.msg }} \
+ "retain3.exe"] \
+ [list "SHF_GNU_RETAIN 4 (keep sections referenced by retained sections)" \
+ "--gc-sections -e _start --print-gc-sections" "" "" \
+ {retain4.s} {} \
+ "retain4.exe"] \
+ [list "SHF_GNU_RETAIN 5 (keep orphaned sections when not discarding)" \
+ "--gc-sections -e _start --print-gc-sections --orphan-handling=place" "" "" \
+ {retain5.s} {} \
+ "retain5.exe"] \
+ [list "Build libretain6.a" \
+ "" "" "" \
+ {retain6lib.s} {} "libretain6.a"] \
+ [list "SHF_GNU_RETAIN 6 (don't pull SHF_GNU_RETAIN section out of lib)" \
+ "--gc-sections -e _start --print-gc-sections" "-Ltmpdir -lretain6" "" \
+ {retain6main.s} {} \
+ "retain6.exe"] \
+ [list "Build libretain7.a" \
+ "" "" "" \
+ {retain7lib.s} {} "libretain7.a"] \
+ [list "SHF_GNU_RETAIN 7 (pull section out of lib required by SHF_GNU_RETAIN section)" \
+ "--gc-sections -e _start --print-gc-sections" "-Ltmpdir -lretain7" "" \
+ {retain7main.s} \
+ {{ ld retain7.msg }} \
+ "retain7.exe"] \
+ ] \
+ "mmix-*-*"
}
set LDFLAGS $old_ldflags
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..e799ff72ec
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1.s
@@ -0,0 +1,114 @@
+ .global discard0
+ .section .bss.discard0,"aw"
+ .type discard0, STT_OBJECT
+discard0:
+ .zero 2
+
+ .global discard1
+ .section .bss.discard1,"aw"
+ .type discard1, STT_OBJECT
+discard1:
+ .zero 2
+
+ .global discard2
+ .section .data.discard2,"aw"
+ .type discard2, STT_OBJECT
+discard2:
+ .word 1
+
+ .section .bss.sdiscard0,"aw"
+ .type sdiscard0, STT_OBJECT
+sdiscard0:
+ .zero 2
+
+ .section .bss.sdiscard1,"aw"
+ .type sdiscard1, STT_OBJECT
+sdiscard1:
+ .zero 2
+
+ .section .data.sdiscard2,"aw"
+ .type sdiscard2, STT_OBJECT
+sdiscard2:
+ .word 1
+
+ .section .text.fndiscard0,"ax"
+ .global fndiscard0
+ .type fndiscard0, STT_FUNC
+fndiscard0:
+ .word 0
+
+ .global retain0
+ .section .bss.retain0,"aw"
+ .type retain0, STT_OBJECT
+ .retain .bss.retain0
+retain0:
+ .zero 2
+
+ .global retain1
+ .section .bss.retain1,"aw"
+ .type retain1, STT_OBJECT
+ .retain .bss.retain1
+retain1:
+ .zero 2
+
+ .global retain2
+ .section .data.retain2,"aw"
+ .type retain2, STT_OBJECT
+ .retain .data.retain2
+retain2:
+ .word 1
+
+ .section .bss.sretain0,"aw"
+ .type sretain0, STT_OBJECT
+ .retain .bss.sretain0
+sretain0:
+ .zero 2
+
+ .section .bss.sretain1,"aw"
+ .type sretain1, STT_OBJECT
+ .retain .bss.sretain1
+sretain1:
+ .zero 2
+
+ .section .data.sretain2,"aw"
+ .type sretain2, STT_OBJECT
+ .retain .data.sretain2
+sretain2:
+ .word 1
+
+ .section .text.fnretain1,"ax"
+ .global fnretain1
+ .type fnretain1, STT_FUNC
+ .retain .text.fnretain1
+fnretain1:
+ .word 0
+
+ .section .text.fndiscard2,"ax"
+ .global fndiscard2
+ .type fndiscard2, STT_FUNC
+fndiscard2:
+ .word 0
+
+ .section .bss.lsretain0,"aw"
+ .type lsretain0.2, STT_OBJECT
+ .retain .bss.lsretain0
+lsretain0.2:
+ .zero 2
+
+ .section .bss.lsretain1,"aw"
+ .type lsretain1.1, STT_OBJECT
+ .retain .bss.lsretain1
+lsretain1.1:
+ .zero 2
+
+ .section .data.lsretain2,"aw"
+ .type lsretain2.0, STT_OBJECT
+ .retain .data.lsretain2
+lsretain2.0:
+ .word 1
+
+ .section .text._start,"ax"
+ .global _start
+ .type _start, STT_FUNC
+_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..941b002948
--- /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-*-*
+# xfail: mmix-*-*
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.msg b/ld/testsuite/ld-elf/retain3.msg
new file mode 100644
index 0000000000..9a265c980f
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain3.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/retain3.s b/ld/testsuite/ld-elf/retain3.s
new file mode 100644
index 0000000000..065399ec6f
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain3.s
@@ -0,0 +1,104 @@
+ .global discard0
+ .section .bss.discard0,"aw"
+ .type discard0, STT_OBJECT
+discard0:
+ .zero 2
+
+ .global discard1
+ .section .bss.discard1,"aw"
+ .type discard1, STT_OBJECT
+discard1:
+ .zero 2
+
+ .global discard2
+ .section .data.discard2,"aw"
+ .type discard2, STT_OBJECT
+discard2:
+ .word 1
+
+ .section .bss.sdiscard0,"aw"
+ .type sdiscard0, STT_OBJECT
+sdiscard0:
+ .zero 2
+
+ .section .bss.sdiscard1,"aw"
+ .type sdiscard1, STT_OBJECT
+sdiscard1:
+ .zero 2
+
+ .section .data.sdiscard2,"aw"
+ .type sdiscard2, STT_OBJECT
+sdiscard2:
+ .word 1
+
+ .section .text.fndiscard0,"ax"
+ .global fndiscard0
+ .type fndiscard0, STT_FUNC
+fndiscard0:
+ .word 0
+
+ .global retain0
+ .section .bss.retain0,"awR"
+ .type retain0, STT_OBJECT
+retain0:
+ .zero 2
+
+ .global retain1
+ .section .bss.retain1,"awR"
+ .type retain1, STT_OBJECT
+retain1:
+ .zero 2
+
+ .global retain2
+ .section .data.retain2,"awR"
+ .type retain2, STT_OBJECT
+retain2:
+ .word 1
+
+ .section .bss.sretain0,"awR"
+ .type sretain0, STT_OBJECT
+sretain0:
+ .zero 2
+
+ .section .bss.sretain1,"awR"
+ .type sretain1, STT_OBJECT
+sretain1:
+ .zero 2
+
+ .section .data.sretain2,"aRw"
+ .type sretain2, STT_OBJECT
+sretain2:
+ .word 1
+
+ .section .text.fnretain1,"Rax"
+ .global fnretain1
+ .type fnretain1, STT_FUNC
+fnretain1:
+ .word 0
+
+ .section .text.fndiscard2,"ax"
+ .global fndiscard2
+ .type fndiscard2, STT_FUNC
+fndiscard2:
+ .word 0
+
+ .section .bss.lsretain0,"awR"
+ .type lsretain0.2, STT_OBJECT
+lsretain0.2:
+ .zero 2
+
+ .section .bss.lsretain1,"aRw"
+ .type lsretain1.1, STT_OBJECT
+lsretain1.1:
+ .zero 2
+
+ .section .data.lsretain2,"aRw"
+ .type lsretain2.0, STT_OBJECT
+lsretain2.0:
+ .word 1
+
+ .section .text._start,"ax"
+ .global _start
+ .type _start, STT_FUNC
+_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..080a5dfc2e
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain4.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, STT_FUNC
+foo:
+ .word 0
+
+ .section .text.bar,"axR"
+ .global bar
+ .type bar, STT_FUNC
+bar:
+ .long foo
+
+ .section .text._start,"ax"
+ .global _start
+ .type _start, STT_FUNC
+_start:
+ .word 0
diff --git a/ld/testsuite/ld-elf/retain5.s b/ld/testsuite/ld-elf/retain5.s
new file mode 100644
index 0000000000..5ffadad694
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5.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, STT_FUNC
+foo:
+ .word 0
+
+ .section .text._start,"ax"
+ .global _start
+ .type _start, STT_FUNC
+_start:
+ .word 0
diff --git a/ld/testsuite/ld-elf/retain6lib.s b/ld/testsuite/ld-elf/retain6lib.s
new file mode 100644
index 0000000000..4de7adea3d
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6lib.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, STT_FUNC
+foo:
+ .long undefined_sym
diff --git a/ld/testsuite/ld-elf/retain6main.s b/ld/testsuite/ld-elf/retain6main.s
new file mode 100644
index 0000000000..7c722481e8
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6main.s
@@ -0,0 +1,5 @@
+ .section .text._start,"ax"
+ .global _start
+ .type _start, STT_FUNC
+_start:
+ .word 0
diff --git a/ld/testsuite/ld-elf/retain7.msg b/ld/testsuite/ld-elf/retain7.msg
new file mode 100644
index 0000000000..c21e3b9d75
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7.msg
@@ -0,0 +1 @@
+.*: removing unused section '.text.discard_from_lib' in file.*
diff --git a/ld/testsuite/ld-elf/retain7lib.s b/ld/testsuite/ld-elf/retain7lib.s
new file mode 100644
index 0000000000..2aebf32bd0
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7lib.s
@@ -0,0 +1,17 @@
+ .section .text.bar,"ax"
+ .global bar
+ .type bar, STT_FUNC
+bar:
+ .word 0
+
+ .section .text.retain_from_lib,"axR"
+ .global retain_from_lib
+ .type retain_from_lib, STT_FUNC
+retain_from_lib:
+ .word 0
+
+ .section .text.discard_from_lib,"ax"
+ .global discard_from_lib
+ .type discard_from_lib, STT_FUNC
+discard_from_lib:
+ .word 0
diff --git a/ld/testsuite/ld-elf/retain7main.s b/ld/testsuite/ld-elf/retain7main.s
new file mode 100644
index 0000000000..d8ce70e718
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain7main.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, STT_FUNC
+foo:
+ .long bar
+
+ .section .text._start,"ax"
+ .global _start
+ .type _start, STT_FUNC
+_start:
+ .word 0
--
2.28.0
More information about the Binutils
mailing list