Summary: | ld -r --gc-section does not KEEP .init_array/.fini_array | ||
---|---|---|---|
Product: | binutils | Reporter: | David Leonard <d+sourceware> |
Component: | ld | Assignee: | Not yet assigned to anyone <unassigned> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | jeremip11, nickc |
Priority: | P2 | ||
Version: | 2.30 | ||
Target Milestone: | 2.30 | ||
Host: | Target: | ||
Build: | Last reconfirmed: | ||
Attachments: | Proposed patch |
Description
David Leonard
2018-01-05 09:38:38 UTC
Submitted too early, sorry. I mean --gc-section not --gc-collect. Example $ cat L.c int L4var = 4; int L5var; int L5init() { L5var = 5; } __attribute__((constructor)) static void Lconstructor() { L5init(); } $ gcc -ffunction-sections -fdata-sections -c -o L.o L.c $ ld -r --gc-section L.o -u L4var -o libL.o $ nm libL.o 0000000000000000 D L4var With workaround: $ ld -r --gc-section L.o -u L4var -o libL.o fixup.ldscript ld: warning: fixup.ldscript contains output sections; did you forget -T? $ nm libL.o 0000000000000000 D L4var 0000000000000000 T L5init 0000000000000004 C L5var 0000000000000000 t Lconstructor (In reply to David Leonard from comment #0) Hi David, > "ld -r --gc-collect" drops the .init_array/.fini_array sections, although it > preserves .init, .fini and the .preinit_array sections. It should probably > KEEP() the .init_array/.fini_array sections too? (And others?) Indeed it should. > There doesn't seem to be a clean indirect way to make --gc-collect keep the > .{init,fini}_array sections. A (noisy) workaround is to add this linker > script as an argument: > > SECTIONS { > .init_array : { KEEP (*(.init_array)) } > .fini_array : { KEEP (*(.fini_array)) } > } This appears to be an artifact of the linker that you are using. If you build an x86_64 linker using the FSF sources and run "ld --verbose" you should see this as part of the output: .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) PROVIDE_HIDDEN (__init_array_end = .); } So the input sections should survive garbage collection. I think however that the ubuntu version of the linker that you are using may have its own, different built-in linker script, without the KEEP statements. Please could you check ? If I am right, then you need to complain to Ubuntu and not us... Cheers Nick Hi Nick, > This appears to be an artifact of the linker that you are using. If you > build an x86_64 linker using the FSF sources and run "ld --verbose" you > should see this as part of the output You are right that KEEPs for init_array/fini_array are present when -r is not supplied. But they are lost with -r. > I think however that the ubuntu version of the linker that you are using may > have its own, different built-in linker script, without the KEEP statements. > Please could you check ? Checked. I found the same issue with a build from clean sources: $ wget http://mirror.aarnet.edu.au/pub/gnu/binutils/binutils-2.29.1.tar.xz $ tar xf binutils-2.29.1.tar.xz $ mkdir build-clean /tmp/usr $ cd build-clean $ ../binutils-2.29.1/configure --prefix=/tmp/usr && make && make install checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking target system type... x86_64-pc-linux-gnu [...] $ /tmp/usr/bin/ld -r --verbose GNU ld (GNU Binutils) 2.29.1 Supported emulations: elf_x86_64 elf32_x86_64 elf_i386 elf_iamcu i386linux elf_l1om elf_k1om using internal linker script: ================================================== /* Script for ld -r: link without relocation */ /* Copyright (C) 2014-2017 Free Software Foundation, Inc. Copying and distribution of this script, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. */ OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") OUTPUT_ARCH(i386:x86-64) [...] $ /tmp/usr/bin/ld -r --verbose | grep -C1 KEEP { KEEP (*(SORT_NONE(.init))) } -- { KEEP (*(SORT_NONE(.fini))) } -- .eh_frame_hdr : { *(.eh_frame_hdr) } .eh_frame 0 : ONLY_IF_RO { KEEP (*(.eh_frame)) } .gcc_except_table 0 : ONLY_IF_RO { *(.gcc_except_table -- /* Exception handling */ .eh_frame 0 : ONLY_IF_RW { KEEP (*(.eh_frame)) } .gnu_extab 0 : ONLY_IF_RW { *(.gnu_extab) } -- { KEEP (*(.preinit_array)) } .jcr 0 : { KEEP (*(.jcr)) } .dynamic 0 : { *(.dynamic) } -- .debug_addr 0 : { *(.debug_addr) } .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } } Re-verified that gc closure over .init_array still fails until explicit KEEPs added. mklibs$ gcc -ffunction-sections -fdata-sections -c -o L.o L.c mklibs$ /tmp/usr/bin/ld -r --gc-section L.o -u L4var -o libL.o mklibs$ nm libL.o 0000000000000000 D L4var mklibs$ cat fixup.ldscript SECTIONS { .init_array : { KEEP (*(.init_array)) } .fini_array : { KEEP (*(.fini_array)) } } mklibs$ /tmp/usr/bin/ld -r --gc-section L.o -u L4var -o libL.o fixup.ldscript /tmp/usr/bin/ld: warning: fixup.ldscript contains output sections; did you forget -T? mklibs$ nm libL.o 0000000000000000 D L4var 0000000000000000 T L5init 0000000000000004 C L5var 0000000000000000 t Lconstructor Created attachment 10728 [details]
Proposed patch
Hi David,
Sorry - I missed the "-r" option in your initial bug report.
This does pose an interesting problem however as your linker script
fragment is only a partial solution. The .init_array and .fini_array
sections can have a priority value as a suffix to their name, and this
suffix must be preserved when linking with -r. (See
ld/testsuite/ld-elf/init-fini-arrays.[sd] for an example of this). Hence
using:
.init_array { KEEP (.init_array.*) }
will not work as it looses the section suffixes. So instead I am proposing
the attached patch which adds a special case for init and fini arrays to
the garbage collection code in the BFD library. Please could you try it
out and let me know if it works for you.
Cheers
Nick
The master branch has been updated by H.J. Lu <hjl@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=8b6f4cd34fdde524ea035c65f7d48aaa3fb449b5 commit 8b6f4cd34fdde524ea035c65f7d48aaa3fb449b5 Author: H.J. Lu <hjl.tools@gmail.com> Date: Thu Jan 11 09:42:12 2018 -0800 ld: Keep PREINIT_ARRAY/INIT_ARRAY/FINI_ARRAY sections for -r --gc-sections We must keep all PREINIT_ARRAY, INIT_ARRAY as well as FINI_ARRAY sections for ld -r --gc-sections. bfd/ PR ld/22677 * elflink.c (bfd_elf_gc_sections): Keep all PREINIT_ARRAY, INIT_ARRAY as well as FINI_ARRAY sections for ld -r --gc-sections. ld/ PR ld/22677 * scripttempl/elf.sc (PREINIT_ARRAY): New. Don't add .preinit_array for ld -r. * testsuite/ld-elf/pr22677.d: New file. * testsuite/ld-elf/pr22677.s: Likewise. Fixed for 2.30. > Please could you try it out and let me know if it works for you.
Confirmed. My tests pass without workaround. I used current master ld (89a7f793f1). Thanks!
|