[lld] r305920 - Implement the --exclude-libs option.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 21 08:36:25 PDT 2017


Author: ruiu
Date: Wed Jun 21 10:36:24 2017
New Revision: 305920

URL: http://llvm.org/viewvc/llvm-project?rev=305920&view=rev
Log:
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

Added:
    lld/trunk/test/ELF/Inputs/exclude-libs.s
    lld/trunk/test/ELF/exclude-libs.s
Modified:
    lld/trunk/ELF/Driver.cpp
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/Options.td
    lld/trunk/ELF/SymbolTable.cpp
    lld/trunk/ELF/SymbolTable.h

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=305920&r1=305919&r2=305920&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Wed Jun 21 10:36:24 2017
@@ -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:
   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.

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=305920&r1=305919&r2=305920&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Wed Jun 21 10:36:24 2017
@@ -632,8 +632,9 @@ ArchiveFile::ArchiveFile(std::unique_ptr
       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.

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=305920&r1=305919&r2=305920&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Wed Jun 21 10:36:24 2017
@@ -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 {

Modified: lld/trunk/ELF/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Options.td?rev=305920&r1=305919&r2=305920&view=diff
==============================================================================
--- lld/trunk/ELF/Options.td (original)
+++ lld/trunk/ELF/Options.td Wed Jun 21 10:36:24 2017
@@ -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">,
 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>;

Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=305920&r1=305919&r2=305920&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Wed Jun 21 10:36:24 2017
@@ -518,18 +518,18 @@ SymbolBody *SymbolTable<ELFT>::findInCur
 }
 
 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(A
   // 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>

Modified: lld/trunk/ELF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=305920&r1=305919&r2=305920&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.h (original)
+++ lld/trunk/ELF/SymbolTable.h Wed Jun 21 10:36:24 2017
@@ -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);

Added: lld/trunk/test/ELF/Inputs/exclude-libs.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/exclude-libs.s?rev=305920&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/exclude-libs.s (added)
+++ lld/trunk/test/ELF/Inputs/exclude-libs.s Wed Jun 21 10:36:24 2017
@@ -0,0 +1,3 @@
+.globl fn
+fn:
+  nop

Added: lld/trunk/test/ELF/exclude-libs.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/exclude-libs.s?rev=305920&view=auto
==============================================================================
--- lld/trunk/test/ELF/exclude-libs.s (added)
+++ lld/trunk/test/ELF/exclude-libs.s Wed Jun 21 10:36:24 2017
@@ -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 at PLT




More information about the llvm-commits mailing list