summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRui Ueyama <ruiu@google.com>2017-06-21 15:36:24 +0000
committerRui Ueyama <ruiu@google.com>2017-06-21 15:36:24 +0000
commitd1f8b8162b11bebb948f9361f578263e4b847039 (patch)
treec09513c1b4738157edf9ad2945c788b591f53231
parent8f9621ae0407e31dab865d9aa7235501125032f3 (diff)
downloadbcm5719-llvm-d1f8b8162b11bebb948f9361f578263e4b847039.tar.gz
bcm5719-llvm-d1f8b8162b11bebb948f9361f578263e4b847039.zip
Implement the --exclude-libs option.
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
-rw-r--r--lld/ELF/Driver.cpp44
-rw-r--r--lld/ELF/InputFiles.cpp3
-rw-r--r--lld/ELF/InputFiles.h2
-rw-r--r--lld/ELF/Options.td4
-rw-r--r--lld/ELF/SymbolTable.cpp11
-rw-r--r--lld/ELF/SymbolTable.h2
-rw-r--r--lld/test/ELF/Inputs/exclude-libs.s3
-rw-r--r--lld/test/ELF/exclude-libs.s30
8 files changed, 92 insertions, 7 deletions
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 692d710d6e5..5fb33caea46 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -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) {
@@ -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.
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 3d11239bf88..1ff0b4224e7 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -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.
diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h
index 2eec7844483..544a0b009b3 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -251,6 +251,7 @@ public:
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
@@ -261,6 +262,7 @@ public:
private:
std::unique_ptr<Archive> File;
llvm::DenseSet<uint64_t> Seen;
+ std::vector<Symbol *> Symbols;
};
class BitcodeFile : public InputFile {
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 335c7ade6db..29e14c530c6 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -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">;
@@ -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>;
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index a223aec9862..79251f0285d 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -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
@@ -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>
diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h
index f38d09760c7..316d9c9bf37 100644
--- a/lld/ELF/SymbolTable.h
+++ b/lld/ELF/SymbolTable.h
@@ -66,7 +66,7 @@ public:
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);
diff --git a/lld/test/ELF/Inputs/exclude-libs.s b/lld/test/ELF/Inputs/exclude-libs.s
new file mode 100644
index 00000000000..6d05c5e3aa9
--- /dev/null
+++ b/lld/test/ELF/Inputs/exclude-libs.s
@@ -0,0 +1,3 @@
+.globl fn
+fn:
+ nop
diff --git a/lld/test/ELF/exclude-libs.s b/lld/test/ELF/exclude-libs.s
new file mode 100644
index 00000000000..c36081f40e5
--- /dev/null
+++ b/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
OpenPOWER on IntegriCloud