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.
=========================================================
The .section directive accepts the "R" flag, which indicates
SHF_GNU_RETAIN should be applied to the section.
There is not a direct mapping of SHF_GNU_RETAIN to the BFD
section flag SEC_KEEP. Keeping these flags distinct allows
SHF_GNU_RETAIN sections to be explicitly removed by placing them in
/DISCARD/.
bfd/ChangeLog:
* 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 (elf_link_input_bfd): Copy enabled has_gnu_osabi bits from
input BFD to output BFD.
(bfd_elf_gc_sections): gc_mark the section if SHF_GNU_RETAIN is set.
binutils/ChangeLog:
* NEWS: Announce SHF_GNU_RETAIN support.
* 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 tests.
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/readelf-maskos-1a.d: New test.
* testsuite/binutils-all/readelf-maskos-1b.d: New test.
* testsuite/binutils-all/readelf-maskos.s: New test.
* testsuite/binutils-all/retain1.s: New test.
* testsuite/binutils-all/retain1a.d: New test.
* testsuite/binutils-all/retain1b.d: New test.
gas/ChangeLog:
* NEWS: Announce SHF_GNU_RETAIN support.
* config/obj-elf.c (obj_elf_change_section): Merge SHF_GNU_RETAIN bit
between section declarations.
(obj_elf_parse_section_letters): Handle 'R' flag.
Handle numeric flag values within the SHF_MASKOS range.
(obj_elf_section): Validate SHF_GNU_RETAIN usage.
* doc/as.texi: Document 'R' flag to .section directive.
* testsuite/gas/elf/elf.exp: Run new tests.
* testsuite/gas/elf/section10.d: Unset SHF_GNU_RETAIN bit.
* testsuite/gas/elf/section10.s: Likewise.
* 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.
* testsuite/gas/elf/section24.l: New test.
* testsuite/gas/elf/section24.s: New test.
* testsuite/gas/elf/section24a.d: New test.
* testsuite/gas/elf/section24b.d: New test.
include/ChangeLog:
* elf/common.h (SHF_GNU_RETAIN): Define.
ld/ChangeLog:
* NEWS: Announce support for 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.
+2020-11-18 Jozef Lawrynowicz <jozef.l@mittosystems.com>
+ H.J. Lu <hongjiu.lu@intel.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 (elf_link_input_bfd): Copy enabled has_gnu_osabi bits from
+ input BFD to output BFD.
+ (bfd_elf_gc_sections): gc_mark the section if SHF_GNU_RETAIN is set.
+
2020-11-16 Przemyslaw Wirkus <przemyslaw.wirkus@arm.com>
* cpu-arm.c (processors): Add Cortex-A78C.
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
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. */
/* 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;
i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
/* Set the osabi field to ELFOSABI_GNU if the binary contains
- SHF_GNU_MBIND sections or symbols of STT_GNU_IFUNC type or
- STB_GNU_UNIQUE binding. */
+ SHF_GNU_MBIND or SHF_GNU_RETAIN sections or symbols of STT_GNU_IFUNC type
+ or STB_GNU_UNIQUE binding. */
if (elf_tdata (abfd)->has_gnu_osabi != 0)
{
if (i_ehdrp->e_ident[EI_OSABI] == ELFOSABI_NONE)
&& 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;
}
extsymoff = symtab_hdr->sh_info;
}
+ /* Enable GNU OSABI features in the output BFD that are used in the input
+ BFD. */
+ if (bed->elf_osabi == ELFOSABI_NONE
+ || bed->elf_osabi == ELFOSABI_GNU
+ || bed->elf_osabi == ELFOSABI_FREEBSD)
+ elf_tdata (output_bfd)->has_gnu_osabi
+ |= elf_tdata (input_bfd)->has_gnu_osabi;
+
/* Read the local symbols. */
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
if (isymbuf == NULL && locsymcount != 0)
== 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;
+2020-11-18 Jozef Lawrynowicz <jozef.l@mittosystems.com>
+
+ * NEWS: Announce SHF_GNU_RETAIN support.
+ * 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 tests.
+ 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/readelf-maskos-1a.d: New test.
+ * testsuite/binutils-all/readelf-maskos-1b.d: New test.
+ * testsuite/binutils-all/readelf-maskos.s: New test.
+ * testsuite/binutils-all/retain1.s: New test.
+ * testsuite/binutils-all/retain1a.d: New test.
+ * testsuite/binutils-all/retain1b.d: New test.
+
2020-11-17 Howard Chu <hyc@symas.com>
* ar.c (main): Place the libdeps record in the second archive
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.
+
Changes in 2.35:
* Changed readelf's display of symbol names when wide mode is not enabled.
/* 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)
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;
if (flag == SHF_PPC_VLE)
sindex = 25;
break;
+ default:
+ break;
+ }
+ 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;
}
if (sindex != -1)
case SHF_TLS: *p = 'T'; break;
case SHF_EXCLUDE: *p = 'E'; break;
case SHF_COMPRESSED: *p = 'C'; break;
- case SHF_GNU_MBIND: *p = 'D'; break;
default:
if ((filedata->file_header.e_machine == EM_X86_64
*p = 'l';
else if (filedata->file_header.e_machine == EM_ARM
&& flag == SHF_ARM_PURECODE)
- *p = 'y';
+ *p = 'y';
else if (filedata->file_header.e_machine == EM_PPC
&& flag == SHF_PPC_VLE)
- *p = 'v';
+ *p = 'v';
else if (flag & SHF_MASKOS)
{
- *p = 'o';
- sh_flags &= ~ SHF_MASKOS;
+ switch (filedata->file_header.e_ident[EI_OSABI])
+ {
+ case ELFOSABI_GNU:
+ case ELFOSABI_FREEBSD:
+ if (flag == SHF_GNU_RETAIN)
+ {
+ *p = 'R';
+ break;
+ }
+ /* 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. */
+ *p = 'D';
+ break;
+ }
+ /* Fall through */
+ default:
+ *p = 'o';
+ sh_flags &= ~SHF_MASKOS;
+ break;
+ }
}
else if (flag & SHF_MASKPROC)
{
--- /dev/null
+#name: Unknown SHF_MASKOS value in section
+#source: readelf-maskos.s
+#notarget: [supports_gnu_osabi] msp430-*-elf visium-*-elf
+#xfail: arm-*-elf
+#readelf: -S --wide
+# PR26722 for the arm-*-elf XFAIL
+
+#...
+ \[[ 0-9]+\] .data.retain_var.*WAo.*
+#pass
--- /dev/null
+#name: -t (section details) for unknown SHF_MASKOS value in section
+#source: readelf-maskos.s
+#notarget: [supports_gnu_osabi] msp430-*-elf visium-*-elf
+#xfail: arm-*-elf
+#readelf: -S -t --wide
+# PR26722 for the arm-*-elf XFAIL
+
+#...
+ \[[ 0-9]+\] .data.retain_var
+ PROGBITS +0+ +[0-9a-f]+ +[0-9a-f]+ +[0-9a-f]+ +0 +0 +(1|2|4|8)
+ \[00200003\]: WRITE, ALLOC, OS \(00200000\)
+#pass
--- /dev/null
+ .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
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 "retain1a"
+ run_dump_test "retain1b"
+ run_dump_test "readelf-maskos-1a"
+ run_dump_test "readelf-maskos-1b"
+}
# PR 13482 - Check for off-by-one errors when dumping .note sections.
if {![binutils_assemble $srcdir/$subdir/version.s tmpdir/version.o]} then {
--- /dev/null
+ .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
--- /dev/null
+#name: readelf SHF_GNU_RETAIN
+#source: retain1.s
+#target: [supports_gnu_osabi]
+#readelf: -S --wide
+
+#...
+ \[[ 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
--- /dev/null
+#name: -t (section details) for readelf SHF_GNU_RETAIN
+#source: retain1.s
+#target: [supports_gnu_osabi]
+#readelf: -S -t --wide
+
+#...
+ \[[ 0-9]+\] .bss.retain0
+#...
+ \[0+200003\]: WRITE, ALLOC, GNU_RETAIN
+#...
+ \[[ 0-9]+\] .bss.retain1
+#...
+ \[0+200003\]: WRITE, ALLOC, GNU_RETAIN
+#...
+ \[[ 0-9]+\] .data.retain2
+#...
+ \[0+200003\]: WRITE, ALLOC, GNU_RETAIN
+#...
+ \[[ 0-9]+\] .bss.sretain0
+#...
+ \[0+200003\]: WRITE, ALLOC, GNU_RETAIN
+#...
+ \[[ 0-9]+\] .bss.sretain1
+#...
+ \[0+200003\]: WRITE, ALLOC, GNU_RETAIN
+#...
+ \[[ 0-9]+\] .data.sretain2
+#...
+ \[0+200003\]: WRITE, ALLOC, GNU_RETAIN
+#...
+ \[[ 0-9]+\] .text.fnretain1
+#...
+ \[0+200006\]: ALLOC, EXEC, GNU_RETAIN
+#...
+ \[[ 0-9]+\] .bss.lsretain0
+#...
+ \[0+200003\]: WRITE, ALLOC, GNU_RETAIN
+#...
+ \[[ 0-9]+\] .bss.lsretain1
+#...
+ \[0+200003\]: WRITE, ALLOC, GNU_RETAIN
+#...
+ \[[ 0-9]+\] .data.lsretain2
+#...
+ \[0+200003\]: WRITE, ALLOC, GNU_RETAIN
+#pass
# 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.)
}
if { [istarget "arm*-*-*"]
|| [istarget "msp430-*-*"]
+ || [istarget "hppa-unknown-elf"]
|| [istarget "visium-*-*"] } {
return 0
}
+2020-11-18 Jozef Lawrynowicz <jozef.l@mittosystems.com>
+ H.J. Lu <hongjiu.lu@intel.com>
+
+ * NEWS: Announce SHF_GNU_RETAIN support.
+ * config/obj-elf.c (obj_elf_change_section): Merge SHF_GNU_RETAIN bit
+ between section declarations.
+ (obj_elf_parse_section_letters): Handle 'R' flag.
+ Handle numeric flag values within the SHF_MASKOS range.
+ (obj_elf_section): Validate SHF_GNU_RETAIN usage.
+ * doc/as.texi: Document 'R' flag to .section directive.
+ * testsuite/gas/elf/elf.exp: Run new tests.
+ * testsuite/gas/elf/section10.d: Unset SHF_GNU_RETAIN bit.
+ * testsuite/gas/elf/section10.s: Likewise.
+ * 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.
+ * testsuite/gas/elf/section24.s: New test.
+ * testsuite/gas/elf/section24a.d: New test.
+ * testsuite/gas/elf/section24b.d: New test.
+
2020-11-13 Przemyslaw Wirkus <przemyslaw.wirkus@arm.com>
* NEWS: Update news.
* Configure with --enable-x86-used-note by default for Linux/x86.
+* Add support for the SHF_GNU_RETAIN flag, which can be applied to
+ sections using the 'R' flag in the .section directive.
+ SHF_GNU_RETAIN specifies that the section should not be garbage
+ collected by the linker. It requires the GNU or FreeBSD ELF OSABIs.
+
Changes in 2.35:
* X86 NaCl target support is removed.
as_bad (_("changed section attributes for %s"), name);
}
else
- /* FIXME: Maybe we should consider removing a previously set
- processor or application specific attribute as suspicious ? */
- elf_section_flags (sec) = attr;
+ {
+ /* Don't overwrite a previously set SHF_GNU_RETAIN flag for the
+ section. The entire section must be marked retained. */
+ if ((elf_tdata (stdoutput)->has_gnu_osabi & elf_gnu_osabi_retain)
+ && ((elf_section_flags (old_sec) & SHF_GNU_RETAIN)))
+ attr |= SHF_GNU_RETAIN;
+
+ /* FIXME: Maybe we should consider removing a previously set
+ processor or application specific attribute as suspicious ? */
+ elf_section_flags (sec) = attr;
+ }
if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
as_bad (_("changed section entity size for %s"), name);
case 'd':
*gnu_attr |= SHF_GNU_MBIND;
break;
+ case 'R':
+ *gnu_attr |= SHF_GNU_RETAIN;
+ break;
case '?':
*is_clone = TRUE;
break;
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 --;
done:
demand_empty_rest_of_line ();
- 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);
- if (bed->elf_osabi == ELFOSABI_NONE)
- 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;
+
+ if (bed->elf_osabi != ELFOSABI_GNU
+ && bed->elf_osabi != ELFOSABI_FREEBSD
+ && bed->elf_osabi != ELFOSABI_NONE)
+ as_bad (_("%s section is supported only by GNU and FreeBSD targets"),
+ mbind_p ? "GNU_MBIND" : "GNU_RETAIN");
+ else
+ {
+ if (bed->elf_osabi == ELFOSABI_NONE)
+ bed->elf_osabi = ELFOSABI_GNU;
+
+ 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;
+
+ attr |= gnu_attr;
+ }
}
- elf_section_flags (now_seg) |= gnu_attr;
+
+ obj_elf_change_section (name, type, attr, entsize, &match, linkonce,
+ push);
if (linked_to_section_index != -1UL)
{
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
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 "section24a"
+ run_dump_test "section24b"
run_dump_test "sh-link-zero"
-
run_dump_test "dwarf2-1" $dump_opts
run_dump_test "dwarf2-2" $dump_opts
run_dump_test "dwarf2-3" $dump_opts
#...
[ ]*\[.*\][ ]+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[ ].*
#...
[ ]*\[.*\][ ]+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
.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.
.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.
--- /dev/null
+#readelf: -h -S --wide
+#name: SHF_GNU_RETAIN sections 22
+#notarget: ![supports_gnu_osabi]
+
+#...
+ +OS/ABI: +UNIX - GNU
+#...
+ \[..\] .text.discard0[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AX.*
+#...
+ \[..\] .data.discard1[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.*
+#...
+ \[..\] .bss.discard2[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.*
+#...
+ \[..\] .bss.retain0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#...
+ \[..\] .data.retain1[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.*
+#...
+ \[..\] .text.retain2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXR.*
+#pass
--- /dev/null
+ .section .text.discard0,"ax",%progbits
+ .global discard0
+ .type discard0, %function
+discard0:
+ .word 0
+
+ .section .data.discard1,"aw"
+ .global discard1
+ .type discard1, %object
+discard1:
+ .word 1
+
+ .section .bss.discard2,"aw"
+ .global discard2
+ .type discard2, %object
+discard2:
+ .zero 2
+
+ .section .bss.retain0,"awR",%nobits
+ .global retain0
+ .type retain0, %object
+retain0:
+ .zero 2
+
+ .section .data.retain1,"awR",%progbits
+ .type retain1, %object
+retain1:
+ .word 1
+
+ .section .text.retain2,"axR",%progbits
+ .global retain2
+ .type retain2, %function
+retain2:
+ .word 0
--- /dev/null
+ .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
--- /dev/null
+#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
--- /dev/null
+#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.
--- /dev/null
+.*: Assembler messages:
+.*:1: Error: GNU_RETAIN section is supported only by GNU and FreeBSD targets
--- /dev/null
+ .section .text,"ax",%progbits
+ .word 0
+ .section .data,"aw"
+ .word 0
+ .section .bss,"aw",%nobits
+ .word 0
+ .section .rodata,"a"
+ .word 0
+
+/* Test that we can set the 'R' flag on an existing section. */
+ .section .text,"axR",%progbits
+ .word 0
+ .section .data,"awR"
+ .word 0
+ .section .bss,"awR",%nobits
+ .word 0
+ .section .rodata,"aR"
+ .word 0
+
+/* Test that the 'R' flag does not get clobbered when the section is switched
+ back to. */
+ .section .text,"ax",%progbits
+ .word 0
+ .section .data,"aw"
+ .word 0
+ .section .bss,"aw",%nobits
+ .word 0
+ .section .rodata,"a"
+ .word 0
+
+ .section .text
+ .word 0
+ .section .data
+ .word 0
+ .section .bss
+ .word 0
+ .section .rodata
+ .word 0
--- /dev/null
+#name: Merge SHF_GNU_RETAIN for non-unique sections
+#notarget: ![supports_gnu_osabi]
+#source: section24.s
+#readelf: -h -S --wide
+
+#...
+ +OS/ABI: +UNIX - GNU
+#...
+ \[..\] .text[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXR .*
+#...
+ \[..\] .data[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR .*
+#...
+ \[..\] .bss[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR .*
+#...
+ \[..\] .rodata[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AR .*
+#pass
+
--- /dev/null
+#name: Merge SHF_GNU_RETAIN for non-unique sections (check no unmerged)
+#notarget: ![supports_gnu_osabi]
+#source: section24.s
+#readelf: -S --wide
+
+#failif
+#...
+ \[..\] .(text|data|bss|rodata)[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 [^R] .*
+#pass
+
+2020-11-18 Jozef Lawrynowicz <jozef.l@mittosystems.com>
+
+ * elf/common.h (SHF_GNU_RETAIN): Define.
+
2020-11-16 Przemyslaw Wirkus <przemyslaw.wirkus@arm.com>
* opcode/aarch64.h (AARCH64_FEATURE_FLAGM): Add new feature.
/* #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.
+2020-11-18 Jozef Lawrynowicz <jozef.l@mittosystems.com>
+
+ * NEWS: Announce support for 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.
+
2020-11-17 Alan Modra <amodra@gmail.com>
PR 26882
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.
+
Changes in 2.35:
* X86 NaCl target support is removed.
@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.
+
@kindex --print-gc-sections
@kindex --no-print-gc-sections
@cindex garbage collection
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.
+
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.
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.
--- /dev/null
+ .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
--- /dev/null
+#name: SHF_GNU_RETAIN 1a
+#source: retain1.s
+#ld: -e _start --gc-sections
+#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
--- /dev/null
+#name: SHF_GNU_RETAIN 1b
+#source: retain1.s
+#ld: -e _start --gc-sections
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#nm: -n
+
+#failif
+#...
+[0-9a-f]+ . .*discard.*
+#...
--- /dev/null
+#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
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
--- /dev/null
+SECTIONS
+{
+ /DISCARD/ :
+ {
+ *(.text.fnretain1)
+ }
+}
--- /dev/null
+# 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
--- /dev/null
+#name: SHF_GNU_RETAIN 3 (keep sections referenced by retained sections)
+#source: retain3.s
+#ld: -e _start --gc-sections
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . bar
+#...
+[0-9a-f]+ . foo
+#pass
--- /dev/null
+/* 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
--- /dev/null
+#name: SHF_GNU_RETAIN 4 (keep orphaned sections when not discarding)
+#source: retain4.s
+#ld: -e _start --gc-sections --orphan-handling=place
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#...
+[0-9a-f]+ . orphaned_fn
+#pass
--- /dev/null
+/* A section that 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
--- /dev/null
+#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
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#map: retain5.map
+#DUMPPROG: nm
+
+#failif
+#...
+[0-9a-f]+ . foo
+#...
--- /dev/null
+# Check that the library was actually loaded to catch any false PASS.
+
+#...
+LOAD tmpdir/libretain5.a
+#pass
--- /dev/null
+/* 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
--- /dev/null
+ .section .text._start,"ax"
+ .global _start
+ .type _start, %function
+_start:
+ .word 0
--- /dev/null
+#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
+#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
--- /dev/null
+#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
+#notarget: ![supports_gnu_osabi] ![check_gc_sections_available]
+#DUMPPROG: nm
+
+#failif
+#...
+[0-9a-f]+ . .*discard.*
+#...
--- /dev/null
+ .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
--- /dev/null
+/* 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