In simplest terms, if we use LTO to build binutils the resultant binaries will fault all over the place. If you look at it in the debugger we'll have jumped to 0x0 via an indirect jump out of the PLT. The problem is the GOT entries are zero'd out. It looks like the preconditions are: First, we need to have a DSO which provides a symbol definition (libbfd). Second, we need to have an executable which links against that DSO (ar). The components of that executable are LTO objects and in one or more of those LTO'd objects there must be another definition of the symbol in question (-liberty and libiberty.a referenced on the command line to link ar). The when linking the executable the linker has to merge the two definitions. In general we'll prefer the version from the executable over the version from the DSO. However, in the case of an LTO link, the symbol's input section is marked as SEC_EXCLUDE for the main executable (that seems to be an artifact of LTO and the section flags it uses). In that scenario the output section will be reset to the ABS section. The net result is we create a dynamic symbol with an absolute type. When the dynamic linker performs its symbol resolution that absolute dynamic symbol will take precedence over the symbol in the DSO and the dynamic linker will slam a new value into the GOT entry for the symbol. This is fairly abstract, so here is a reproducer in the form of binutils itself that you can examine in a debugger. It uses the Fedora rawhide (f33) binutils sources: 1. fedpkg clone binutils 2. sed -i -e 's/%define _lto_cflags/#define _lto_cflags/' binutils.spec [This step disables a workaround currently in the binutils.spec. The workaround disables building the binutils with LTO enabled]. 3. fedpkg srpm 4. fedpkg mock-config > my.cfg 5. mock -r my.cfg --without=testsuite *.src.rpm 6. mock --uniqueext=xxx --dnf -r my.cfg shell 7. nm --dynamic /builddir/build/BUILD/binutils-2.35/binutils/.libs/ar This will show lots of entries, including: 0000000000000000 A lrealpath Attempts to run the ar binary will fail, as will all the other newly built binutils tools. [I am attempting to create a simpler, stand alone reproducer for this problem. I will add an update to this PR when/if I find one]. Jeff Law has come up with a hack which appears to fix the problem, but we are not sure if it is the correct solution: diff --git a/bfd/elflink.c b/bfd/elflink.c index 998b72f228..2f06e835c1 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -1633,7 +1633,8 @@ _bfd_elf_merge_symbol (bfd *abfd, && newdef && (olddef || (h->root.type == bfd_link_hash_common - && (newweak || newfunc)))) + && (newweak || newfunc))) + && (oldsec->flags & SEC_EXCLUDE) == 0) { *override = TRUE; newdef = FALSE; THe effect here is the symbol will be resolved via the libbfd.so DSO. That doesn't seem entirely correct since we have a definition of lrealpath in libiberty, which is referenced twice on the link line.
Created attachment 12732 [details] A patch Please try this.
A patch is posted at https://sourceware.org/pipermail/binutils/2020-July/112629.html
I'm having trouble reproducing this problem using my own x86_64-linux gcc-10, and trying to guess the flags used to compile binutils.
(In reply to Alan Modra from comment #3) > I'm having trouble reproducing this problem using my own x86_64-linux > gcc-10, and trying to guess the flags used to compile binutils. A testcase is on pr96385 branch at: https://gitlab.com/x86-gcc/gcc-bugs
> https://gitlab.com/x86-gcc/gcc-bugs Thanks for that. Here are my observations about the link: gcc -O2 -g -o ar -Wl,--as-needed arparse.o arlex.o ar.o not-ranlib.o arsup.o rename.o binemul.o emul_vanilla.o bucomm.o version.o filemode.o libbfd-2.35-3.fc33.so libiberty.a -Wl,-R,. All of the above .o files are lto, leading to libbfd-2.35-3.fc33.so not being found needed when loading the IR objects. That's problem number one: We exclude IR references when deciding a shared library is needed. See PR15146. Thus none of the libbfd.so symbols are loaded before libiberty.a is scanned, and libbfd.so contains copies of libiberty.a functions. We ought to be using the libbfd.so copies rather than extracting them from the archive (an object is extracted even to satisfy IR symbols). After lto recompilation, libbfd.so is of course found to be needed and loaded. But that causes more problems. The lto recompilation didn't see symbol references from libbfd.so and variables like _xexit_cleanup are made local in the recompiled objects. Oops, two copies of them. Finally, those silly undefined symbols in the lto output debug files, combined with definitions in both libbfd.so and IR objects result in IR symbols being made dynamic.
The master branch has been updated by Alan Modra <amodra@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=a896df97b952d4f3feed8068eaa70147d12e0e28 commit a896df97b952d4f3feed8068eaa70147d12e0e28 Author: Alan Modra <amodra@gmail.com> Date: Fri Jul 31 16:37:17 2020 +0930 PR26314, Linking LTO objects with symbols from static and shared libraries gcc -O2 -g -o ar -Wl,--as-needed arparse.o arlex.o ar.o not-ranlib.o arsup.o rename.o binemul.o emul_vanilla.o bucomm.o version.o filemode.o libbfd-2.35-3.fc33.so libiberty.a -Wl,-R,. All of the above .o files are lto, leading to libbfd-2.35-3.fc33.so not being found needed when loading the IR objects. That's problem number one: We exclude IR references when deciding a shared library is needed. See PR15146. Thus none of the libbfd.so symbols are loaded before libiberty.a is scanned, and libbfd.so contains copies of libiberty.a functions. We ought to be using the libbfd.so copies rather than extracting them from the archive (an object is extracted even to satisfy IR symbols). After lto recompilation, libbfd.so is of course found to be needed and loaded. But that causes more problems. The lto recompilation didn't see symbol references from libbfd.so and variables like _xexit_cleanup are made local in the recompiled objects. Oops, two copies of them. Finally, those silly undefined symbols in the lto output debug files, combined with definitions in both libbfd.so and IR objects result in IR symbols being made dynamic. The main fix here is to revert the PR15146 change to elf_link_add_object_symbols. PR 26314 * elflink.c (bfd_elf_link_record_dynamic_symbol): Don't allow IR symbols to become dynamic. (elf_link_add_object_symbols): Don't exclude IR symbols when deciding whether an as-needed shared library is needed.
The master branch has been updated by Alan Modra <amodra@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=1e3b96fd6cf0c7d018083994ad951ccf92aba582 commit 1e3b96fd6cf0c7d018083994ad951ccf92aba582 Author: Alan Modra <amodra@gmail.com> Date: Fri Sep 4 13:54:21 2020 +0930 Allow plugin syms to mark as-needed shared libs needed We must tell LTO about symbols in all shared libraries loaded. That means we can't load extra shared libraries after LTO recompilation, at least, not those that affect the set of symbols that LTO cares about, the IR symbols. This change will likely result in complaints about --as-needed libraries being loaded unnecessarily, but being correct is more important than being optimal. One of the PR15146 tests regresses, and while that could be hidden by disabling the missing dso message by making it conditional on h->root.non_ir_ref_regular, that would just be sweeping a problem under the rug. bfd/ PR 15146 PR 26314 PR 26530 * elflink.c (elf_link_add_object_symbols): Do set def_regular and ref_regular for IR symbols. Don't clear dynsym, allowing IR symbols to load --as-needed shared libraries, but prevent IR symbols from becoming dynamic. ld/ * testsuite/ld-plugin/lto.exp: Don't run pr15146 tests. * testsuite/ld-plugin/pr15146.d: Delete. * testsuite/ld-plugin/pr15146a.c: Delete. * testsuite/ld-plugin/pr15146b.c: Delete. * testsuite/ld-plugin/pr15146c.c: Delete. * testsuite/ld-plugin/pr15146d.c: Delete.
The master branch has been updated by Alan Modra <amodra@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=b1a92c635c1ec10fd703302ce1fc4ab3a8515a04 commit b1a92c635c1ec10fd703302ce1fc4ab3a8515a04 Author: Alan Modra <amodra@gmail.com> Date: Fri Oct 30 14:56:35 2020 +1030 PR26806, Suspected linker bug with LTO This patch reverts most of git commit 1e3b96fd6cf, so IR symbols are again not marked def_regular or ref_regular. That should be enough to stop IR symbols from becoming dynamic. To mark as-needed shared libraries referenced by IR symbols, use the referencing BFD rather than the ref flags. bfd/ PR 15146 PR 26314 PR 26530 PR 26806 * elflink.c (elf_link_add_object_symbols): Don't set def/ref flags for plugin syms. Do allow plugin syms to mark as-needed libs. ld/ PR 26806 * testsuite/ld-plugin/lto-19.h, * testsuite/ld-plugin/lto-19a.c, * testsuite/ld-plugin/lto-19b.c, * testsuite/ld-plugin/lto-19c.c: New test. * testsuite/ld-plugin/pr26806.c, * testsuite/ld-plugin/pr26806.d: New test. * testsuite/ld-plugin/lto.exp: Run them.
Fixed.