Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
ELF: Only add libcall symbols to the link if defined in bitcode.
Browse files Browse the repository at this point in the history
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

git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@339301 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
pcc committed Aug 8, 2018
1 parent 1859a60 commit 3be4e82
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 4 deletions.
33 changes: 30 additions & 3 deletions ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,21 @@ template <class ELFT> static void handleUndefined(StringRef Name) {
Symtab->fetchLazy<ELFT>(Sym);
}

template <class ELFT> static void handleLibcall(StringRef Name) {
Symbol *Sym = Symtab->find(Name);
if (!Sym || !Sym->isLazy())
return;

MemoryBufferRef MB;
if (auto *LO = dyn_cast<LazyObject>(Sym))
MB = LO->File->MB;
else
MB = cast<LazyArchive>(Sym)->getMemberBuffer();

if (isBitcode(MB))
Symtab->fetchLazy<ELFT>(Sym);
}

template <class ELFT> 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
Expand Down Expand Up @@ -1388,11 +1403,20 @@ template <class ELFT> 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<ELFT>(S);
handleLibcall<ELFT>(S);

// Return if there were name resolution errors.
if (errorCount())
Expand Down Expand Up @@ -1434,6 +1458,9 @@ template <class ELFT> 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<ELFT>();
if (errorCount())
return;
Expand Down
9 changes: 9 additions & 0 deletions ELF/Symbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,15 @@ void Symbol::parseSymbolVersion() {

InputFile *LazyArchive::fetch() { return cast<ArchiveFile>(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;
Expand Down
1 change: 1 addition & 0 deletions ELF/Symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ class LazyArchive : public Symbol {
static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; }

InputFile *fetch();
MemoryBufferRef getMemberBuffer();

private:
const llvm::object::Archive::Symbol Sym;
Expand Down
2 changes: 2 additions & 0 deletions test/ELF/lto/Inputs/libcall-archive.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.globl __sync_val_compare_and_swap_8
__sync_val_compare_and_swap_8:
6 changes: 5 additions & 1 deletion test/ELF/lto/libcall-archive.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 3be4e82

Please sign in to comment.