From 98930115ea666ed457e45dbdda4530675688d7cb Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Wed, 8 Aug 2018 23:48:12 +0000 Subject: [PATCH] ELF: Only add libcall symbols to the link if defined in bitcode. 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. This change makes it so that 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. Differential Revision: https://reviews.llvm.org/D50475 llvm-svn: 339301 --- lld/ELF/Driver.cpp | 33 ++++++++++++++++++++--- lld/ELF/Symbols.cpp | 9 +++++++ lld/ELF/Symbols.h | 1 + lld/test/ELF/lto/Inputs/libcall-archive.s | 2 ++ lld/test/ELF/lto/libcall-archive.ll | 6 ++++- 5 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 lld/test/ELF/lto/Inputs/libcall-archive.s diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 814c7fe84915..1ed52914de14 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1212,6 +1212,21 @@ template static void handleUndefined(StringRef Name) { Symtab->fetchLazy(Sym); } +template static void handleLibcall(StringRef Name) { + Symbol *Sym = Symtab->find(Name); + if (!Sym || !Sym->isLazy()) + return; + + MemoryBufferRef MB; + if (auto *LO = dyn_cast(Sym)) + MB = LO->File->MB; + else + MB = cast(Sym)->getMemberBuffer(); + + 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 +1403,20 @@ template void LinkerDriver::link(opt::InputArgList &Args) { // 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 +1458,9 @@ template void LinkerDriver::link(opt::InputArgList &Args) { // 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; diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 4243cb1e80ef..72942e028b4f 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -204,6 +204,15 @@ void Symbol::parseSymbolVersion() { 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; diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 8c9513b9368b..3019e4747bfc 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -286,6 +286,7 @@ public: static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; } InputFile *fetch(); + MemoryBufferRef getMemberBuffer(); private: const llvm::object::Archive::Symbol Sym; diff --git a/lld/test/ELF/lto/Inputs/libcall-archive.s b/lld/test/ELF/lto/Inputs/libcall-archive.s new file mode 100644 index 000000000000..6ca6e5fa821e --- /dev/null +++ b/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: diff --git a/lld/test/ELF/lto/libcall-archive.ll b/lld/test/ELF/lto/libcall-archive.ll index 043532942da3..7e8ac183317d 100644 --- a/lld/test/ELF/lto/libcall-archive.ll +++ b/lld/test/ELF/lto/libcall-archive.ll @@ -2,10 +2,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 -- GitLab