https://sourceware.org/bugzilla/show_bug.cgi?id=26314
Bug ID: 26314 Summary: Linking LTO objects with conflicting symbol definitions from static and shared libraries fails Product: binutils Version: 2.35 Status: NEW Severity: normal Priority: P2 Component: ld Assignee: unassigned at sourceware dot org Reporter: nickc at redhat dot com Target Milestone: --- 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. -- You are receiving this mail because: You are on the CC list for the bug.