aboutsummaryrefslogtreecommitdiff
path: root/ld
diff options
context:
space:
mode:
authorJozef Lawrynowicz <jozef.l@mittosystems.com>2020-11-18 11:51:13 +0000
committerJozef Lawrynowicz <jozef.l@mittosystems.com>2020-11-18 11:51:13 +0000
commit99fabbc9739a87ba3433e66792e93b773896790e (patch)
tree6a52b12cc648532f3b38fd102cec221a207188ba /ld
parent40d9d2fd796a184f04a83ca4442fd78034b5e00b (diff)
downloadfsf-binutils-gdb-99fabbc9739a87ba3433e66792e93b773896790e.zip
fsf-binutils-gdb-99fabbc9739a87ba3433e66792e93b773896790e.tar.gz
fsf-binutils-gdb-99fabbc9739a87ba3433e66792e93b773896790e.tar.bz2
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. ========================================================= 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.
Diffstat (limited to 'ld')
-rw-r--r--ld/ChangeLog25
-rw-r--r--ld/NEWS4
-rw-r--r--ld/ld.texi7
-rw-r--r--ld/testsuite/ld-elf/elf.exp10
-rw-r--r--ld/testsuite/ld-elf/retain1.s104
-rw-r--r--ld/testsuite/ld-elf/retain1a.d27
-rw-r--r--ld/testsuite/ld-elf/retain1b.d10
-rw-r--r--ld/testsuite/ld-elf/retain2.d5
-rw-r--r--ld/testsuite/ld-elf/retain2.ld7
-rw-r--r--ld/testsuite/ld-elf/retain2.map32
-rw-r--r--ld/testsuite/ld-elf/retain3.d11
-rw-r--r--ld/testsuite/ld-elf/retain3.s19
-rw-r--r--ld/testsuite/ld-elf/retain4.d9
-rw-r--r--ld/testsuite/ld-elf/retain4.s13
-rw-r--r--ld/testsuite/ld-elf/retain5.d11
-rw-r--r--ld/testsuite/ld-elf/retain5.map5
-rw-r--r--ld/testsuite/ld-elf/retain5lib.s6
-rw-r--r--ld/testsuite/ld-elf/retain5main.s5
-rw-r--r--ld/testsuite/ld-elf/retain6a.d13
-rw-r--r--ld/testsuite/ld-elf/retain6b.d10
-rw-r--r--ld/testsuite/ld-elf/retain6lib.s17
-rw-r--r--ld/testsuite/ld-elf/retain6main.s13
22 files changed, 363 insertions, 0 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 7141182..0e2ddee 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,28 @@
+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
diff --git a/ld/NEWS b/ld/NEWS
index 02fc93b..607030b 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -23,6 +23,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.
+
Changes in 2.35:
* X86 NaCl target support is removed.
diff --git a/ld/ld.texi b/ld/ld.texi
index 9b74b89..8e3c7da 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1807,6 +1807,9 @@ 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.
+
@kindex --print-gc-sections
@kindex --no-print-gc-sections
@cindex garbage collection
@@ -5291,6 +5294,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.
+
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 f2ff039..6e61c7f 100644
--- a/ld/testsuite/ld-elf/elf.exp
+++ b/ld/testsuite/ld-elf/elf.exp
@@ -119,6 +119,16 @@ 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 0000000..f7716fa
--- /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 0000000..29adb5d
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1a.d
@@ -0,0 +1,27 @@
+#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
diff --git a/ld/testsuite/ld-elf/retain1b.d b/ld/testsuite/ld-elf/retain1b.d
new file mode 100644
index 0000000..b1cafc9
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain1b.d
@@ -0,0 +1,10 @@
+#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.*
+#...
diff --git a/ld/testsuite/ld-elf/retain2.d b/ld/testsuite/ld-elf/retain2.d
new file mode 100644
index 0000000..1a63f51
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain2.d
@@ -0,0 +1,5 @@
+#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]
diff --git a/ld/testsuite/ld-elf/retain2.ld b/ld/testsuite/ld-elf/retain2.ld
new file mode 100644
index 0000000..8ef9827
--- /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 0000000..4028aa1
--- /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 0000000..3c81a88
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain3.d
@@ -0,0 +1,11 @@
+#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
diff --git a/ld/testsuite/ld-elf/retain3.s b/ld/testsuite/ld-elf/retain3.s
new file mode 100644
index 0000000..ce315cb
--- /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 0000000..b423fb9
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain4.d
@@ -0,0 +1,9 @@
+#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
diff --git a/ld/testsuite/ld-elf/retain4.s b/ld/testsuite/ld-elf/retain4.s
new file mode 100644
index 0000000..f30f121
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain4.s
@@ -0,0 +1,13 @@
+/* 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
diff --git a/ld/testsuite/ld-elf/retain5.d b/ld/testsuite/ld-elf/retain5.d
new file mode 100644
index 0000000..86e85f8
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain5.d
@@ -0,0 +1,11 @@
+#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
+#...
diff --git a/ld/testsuite/ld-elf/retain5.map b/ld/testsuite/ld-elf/retain5.map
new file mode 100644
index 0000000..6b97c2a
--- /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 0000000..4e83731
--- /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 0000000..89a7784
--- /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 0000000..aa93117
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6a.d
@@ -0,0 +1,13 @@
+#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
diff --git a/ld/testsuite/ld-elf/retain6b.d b/ld/testsuite/ld-elf/retain6b.d
new file mode 100644
index 0000000..f29ba71
--- /dev/null
+++ b/ld/testsuite/ld-elf/retain6b.d
@@ -0,0 +1,10 @@
+#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.*
+#...
diff --git a/ld/testsuite/ld-elf/retain6lib.s b/ld/testsuite/ld-elf/retain6lib.s
new file mode 100644
index 0000000..a393dba
--- /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 0000000..a66c5b3
--- /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