Skip to content

Commit

Permalink
Implement the --exclude-libs option.
Browse files Browse the repository at this point in the history
The --exclude-libs option is not a popular option, but at least some
programs in Android depend on it, so it's worth to support it.

Differential Revision: https://reviews.llvm.org/D34422

llvm-svn: 305920
  • Loading branch information
rui314 committed Jun 21, 2017
1 parent 8f9621a commit d1f8b81
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 7 deletions.
44 changes: 44 additions & 0 deletions lld/ELF/Driver.cpp
Expand Up @@ -908,6 +908,41 @@ getDefsym(opt::InputArgList &Args) {
return Ret;
}

// Parses `--exclude-libs=lib,lib,...`.
// The library names may be delimited by commas or colons.
static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) {
DenseSet<StringRef> Ret;
for (auto *Arg : Args.filtered(OPT_exclude_libs)) {
StringRef S = Arg->getValue();
for (;;) {
size_t Pos = S.find_first_of(",:");
if (Pos == StringRef::npos)
break;
Ret.insert(S.substr(0, Pos));
S = S.substr(Pos + 1);
}
Ret.insert(S);
}
return Ret;
}

// Handles the -exclude-libs option. If a static library file is specified
// by the -exclude-libs option, all public symbols from the archive become
// private unless otherwise specified by version scripts or something.
// A special library name "ALL" means all archive files.
//
// This is not a popular option, but some programs such as bionic libc use it.
static void excludeLibs(opt::InputArgList &Args, ArrayRef<InputFile *> Files) {
DenseSet<StringRef> Libs = getExcludeLibs(Args);
bool All = Libs.count("ALL");

for (InputFile *File : Files)
if (auto *F = dyn_cast<ArchiveFile>(File))
if (All || Libs.count(path::filename(F->getName())))
for (Symbol *Sym : F->getSymbols())
Sym->VersionId = VER_NDX_LOCAL;
}

// Do actual linking. Note that when this function is called,
// all linker scripts have already been parsed.
template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
Expand Down Expand Up @@ -959,8 +994,17 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (ErrorCount)
return;

// Handle the `--undefined <sym>` options.
Symtab.scanUndefinedFlags();

// Handle undefined symbols in DSOs.
Symtab.scanShlibUndefined();

// Handle the -exclude-libs option.
if (Args.hasArg(OPT_exclude_libs))
excludeLibs(Args, Files);

// Apply version scripts.
Symtab.scanVersionScript();

// Create wrapped symbols for -wrap option.
Expand Down
3 changes: 2 additions & 1 deletion lld/ELF/InputFiles.cpp
Expand Up @@ -632,8 +632,9 @@ ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File)
File(std::move(File)) {}

template <class ELFT> void ArchiveFile::parse() {
Symbols.reserve(File->getNumberOfSymbols());
for (const Archive::Symbol &Sym : File->symbols())
Symtab<ELFT>::X->addLazyArchive(this, Sym);
Symbols.push_back(Symtab<ELFT>::X->addLazyArchive(this, Sym));
}

// Returns a buffer pointing to a member file containing a given symbol.
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/InputFiles.h
Expand Up @@ -251,6 +251,7 @@ class ArchiveFile : public InputFile {
explicit ArchiveFile(std::unique_ptr<Archive> &&File);
static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
template <class ELFT> void parse();
ArrayRef<Symbol *> getSymbols() { return Symbols; }

// Returns a memory buffer for a given symbol and the offset in the archive
// for the member. An empty memory buffer and an offset of zero
Expand All @@ -261,6 +262,7 @@ class ArchiveFile : public InputFile {
private:
std::unique_ptr<Archive> File;
llvm::DenseSet<uint64_t> Seen;
std::vector<Symbol *> Symbols;
};

class BitcodeFile : public InputFile {
Expand Down
4 changes: 4 additions & 0 deletions lld/ELF/Options.td
Expand Up @@ -92,6 +92,9 @@ def error_limit: S<"error-limit">,
def error_unresolved_symbols: F<"error-unresolved-symbols">,
HelpText<"Report unresolved symbols as errors">;

def exclude_libs: S<"exclude-libs">,
HelpText<"Exclude static libraries from automatic export">;

def export_dynamic: F<"export-dynamic">,
HelpText<"Put symbols in the dynamic symbol table">;

Expand Down Expand Up @@ -298,6 +301,7 @@ def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>;
def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
def alias_entry_entry: J<"entry=">, Alias<entry>;
def alias_error_limit: J<"error-limit=">, Alias<error_limit>;
def alias_exclude_libs: J<"exclude-libs=">, Alias<exclude_libs>;
def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>;
def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">,
Alias<export_dynamic_symbol>;
Expand Down
11 changes: 6 additions & 5 deletions lld/ELF/SymbolTable.cpp
Expand Up @@ -518,18 +518,18 @@ SymbolBody *SymbolTable<ELFT>::findInCurrentDSO(StringRef Name) {
}

template <class ELFT>
void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
const object::Archive::Symbol Sym) {
Symbol *SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
const object::Archive::Symbol Sym) {
Symbol *S;
bool WasInserted;
StringRef Name = Sym.getName();
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
replaceBody<LazyArchive>(S, *F, Sym, SymbolBody::UnknownType);
return;
return S;
}
if (!S->body()->isUndefined())
return;
return S;

// Weak undefined symbols should not fetch members from archives. If we were
// to keep old symbol we would not know that an archive member was available
Expand All @@ -540,11 +540,12 @@ void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
// to preserve its type. FIXME: Move the Type field to Symbol.
if (S->isWeak()) {
replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type);
return;
return S;
}
std::pair<MemoryBufferRef, uint64_t> MBInfo = F->getMember(&Sym);
if (!MBInfo.first.getBuffer().empty())
addFile(createObjectFile(MBInfo.first, F->getName(), MBInfo.second));
return S;
}

template <class ELFT>
Expand Down
2 changes: 1 addition & 1 deletion lld/ELF/SymbolTable.h
Expand Up @@ -66,7 +66,7 @@ template <class ELFT> class SymbolTable {
void addShared(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
const typename ELFT::Verdef *Verdef);

void addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S);
Symbol *addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S);
void addLazyObject(StringRef Name, LazyObjectFile &Obj);
Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther,
uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File);
Expand Down
3 changes: 3 additions & 0 deletions lld/test/ELF/Inputs/exclude-libs.s
@@ -0,0 +1,3 @@
.globl fn
fn:
nop
30 changes: 30 additions & 0 deletions lld/test/ELF/exclude-libs.s
@@ -0,0 +1,30 @@
// REQUIRES: x86

// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
// RUN: %p/Inputs/exclude-libs.s -o %t2.o
// RUN: mkdir -p %t.dir
// RUN: rm -f %t.dir/exc.a
// RUN: llvm-ar rcs %t.dir/exc.a %t2.o

// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe
// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=DEFAULT %s

// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs=foo,bar
// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=DEFAULT %s

// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs foo,bar,exc.a
// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s

// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs foo:bar:exc.a
// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s

// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs=ALL
// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s

// DEFAULT: Name: fn
// EXCLUDE-NOT: Name: fn

.globl fn
foo:
call fn@PLT

0 comments on commit d1f8b81

Please sign in to comment.