Index: lld/ELF/Driver.cpp =================================================================== --- lld/ELF/Driver.cpp +++ lld/ELF/Driver.cpp @@ -1212,6 +1212,24 @@ Symtab->fetchLazy(Sym); } +template static void handleLibcall(StringRef Name) { + Symbol *Sym = Symtab->find(Name); + if (!Sym) + return; + Sym->IsUsedInRegularObj = true; + + MemoryBufferRef MB; + if (auto *LO = dyn_cast(Sym)) + MB = LO->File->MB; + else if (auto *LA = dyn_cast(Sym)) + MB = LA->getMemberBuffer(); + else + return; + + if (isBitcode(MB)) + Symtab->fetchLazy(Sym); +} + template static bool shouldDemote(Symbol &Sym) { // If all references to a DSO happen to be weak, the DSO is not added to // DT_NEEDED. If that happens, we need to eliminate shared symbols created @@ -1388,11 +1406,20 @@ // in a bitcode file in an archive member, we need to arrange to use LTO to // compile those archive members by adding them to the link beforehand. // - // With this the symbol table should be complete. After this, no new names - // except a few linker-synthesized ones will be added to the symbol table. + // However, adding all libcall symbols to the link can have undesired + // consequences. For example, the libgcc implementation of + // __sync_val_compare_and_swap_8 on 32-bit ARM pulls in an .init_array entry + // that aborts the program if the Linux kernel does not support 64-bit + // atomics, which would prevent the program from running even if it does not + // use 64-bit atomics. + // + // Therefore, we only add libcall symbols to the link before LTO if we have + // to, i.e. if the symbol's definition is in bitcode. Any other required + // libcall symbols will be added to the link after LTO when we add the LTO + // object file to the link. if (!BitcodeFiles.empty()) for (const char *S : LibcallRoutineNames) - handleUndefined(S); + handleLibcall(S); // Return if there were name resolution errors. if (errorCount()) @@ -1434,6 +1461,9 @@ // Do link-time optimization if given files are LLVM bitcode files. // This compiles bitcode files into real object files. + // + // With this the symbol table should be complete. After this, no new names + // except a few linker-synthesized ones will be added to the symbol table. Symtab->addCombinedLTOObject(); if (errorCount()) return; Index: lld/ELF/Symbols.h =================================================================== --- lld/ELF/Symbols.h +++ lld/ELF/Symbols.h @@ -286,6 +286,7 @@ static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; } InputFile *fetch(); + MemoryBufferRef getMemberBuffer(); private: const llvm::object::Archive::Symbol Sym; Index: lld/ELF/Symbols.cpp =================================================================== --- lld/ELF/Symbols.cpp +++ lld/ELF/Symbols.cpp @@ -204,6 +204,15 @@ InputFile *LazyArchive::fetch() { return cast(File)->fetch(Sym); } +MemoryBufferRef LazyArchive::getMemberBuffer() { + Archive::Child C = CHECK( + Sym.getMember(), "could not get the member for symbol " + Sym.getName()); + + return CHECK(C.getMemoryBufferRef(), + "could not get the buffer for the member defining symbol " + + Sym.getName()); +} + uint8_t Symbol::computeBinding() const { if (Config->Relocatable) return Binding; Index: lld/test/ELF/lto/Inputs/libcall-archive.s =================================================================== --- /dev/null +++ lld/test/ELF/lto/Inputs/libcall-archive.s @@ -0,0 +1,2 @@ +.globl __sync_val_compare_and_swap_8 +__sync_val_compare_and_swap_8: Index: lld/test/ELF/lto/libcall-archive.ll =================================================================== --- lld/test/ELF/lto/libcall-archive.ll +++ lld/test/ELF/lto/libcall-archive.ll @@ -1,10 +1,14 @@ ; RUN: rm -f %t.a ; RUN: llvm-as -o %t.o %s ; RUN: llvm-as -o %t2.o %S/Inputs/libcall-archive.ll -; RUN: llvm-ar rcs %t.a %t2.o +; RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux -o %t3.o %S/Inputs/libcall-archive.s +; RUN: llvm-ar rcs %t.a %t2.o %t3.o ; RUN: ld.lld -o %t %t.o %t.a ; RUN: llvm-nm %t | FileCheck %s +; RUN: ld.lld -o %t2 %t.o --start-lib %t2.o %t3.o --end-lib +; RUN: llvm-nm %t2 | FileCheck %s +; CHECK-NOT: T __sync_val_compare_and_swap_8 ; CHECK: T _start ; CHECK: T memcpy