diff options
| author | Rui Ueyama <ruiu@google.com> | 2017-06-21 15:36:24 +0000 |
|---|---|---|
| committer | Rui Ueyama <ruiu@google.com> | 2017-06-21 15:36:24 +0000 |
| commit | d1f8b8162b11bebb948f9361f578263e4b847039 (patch) | |
| tree | c09513c1b4738157edf9ad2945c788b591f53231 | |
| parent | 8f9621ae0407e31dab865d9aa7235501125032f3 (diff) | |
| download | bcm5719-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.cpp | 44 | ||||
| -rw-r--r-- | lld/ELF/InputFiles.cpp | 3 | ||||
| -rw-r--r-- | lld/ELF/InputFiles.h | 2 | ||||
| -rw-r--r-- | lld/ELF/Options.td | 4 | ||||
| -rw-r--r-- | lld/ELF/SymbolTable.cpp | 11 | ||||
| -rw-r--r-- | lld/ELF/SymbolTable.h | 2 | ||||
| -rw-r--r-- | lld/test/ELF/Inputs/exclude-libs.s | 3 | ||||
| -rw-r--r-- | lld/test/ELF/exclude-libs.s | 30 |
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 |

