[lld] r265710 - ELF: Implement --start-lib and --end-lib

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 7 12:24:53 PDT 2016


Author: ruiu
Date: Thu Apr  7 14:24:51 2016
New Revision: 265710

URL: http://llvm.org/viewvc/llvm-project?rev=265710&view=rev
Log:
ELF: Implement --start-lib and --end-lib

start-lib and end-lib are options to link object files in the same
semantics as archive files. If an object is in start-lib and end-lib,
the object is linked only when the file is needed to resolve
undefined symbols. That means, if an object is in start-lib and end-lib,
it behaves as if it were in an archive file.

In this patch, I introduced a new notion, LazyObjectFile. That is
analogous to Archive file type, but that works for a single object
file instead of for an archive file.

http://reviews.llvm.org/D18814

Added:
    lld/trunk/test/ELF/lto/Inputs/start-lib.ll
    lld/trunk/test/ELF/lto/start-lib.ll
    lld/trunk/test/ELF/start-lib.s
Modified:
    lld/trunk/ELF/Driver.cpp
    lld/trunk/ELF/Driver.h
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/Options.td
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/SymbolTable.cpp
    lld/trunk/ELF/SymbolTable.h
    lld/trunk/ELF/Symbols.cpp
    lld/trunk/ELF/Symbols.h

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Thu Apr  7 14:24:51 2016
@@ -129,7 +129,10 @@ void LinkerDriver::addFile(StringRef Pat
     Files.push_back(createSharedFile(MBRef));
     return;
   default:
-    Files.push_back(createObjectFile(MBRef));
+    if (InLib)
+      Files.push_back(make_unique<LazyObjectFile>(MBRef));
+    else
+      Files.push_back(createObjectFile(MBRef));
   }
 }
 
@@ -359,6 +362,12 @@ void LinkerDriver::createFiles(opt::Inpu
     case OPT_no_whole_archive:
       WholeArchive = false;
       break;
+    case OPT_start_lib:
+      InLib = true;
+      break;
+    case OPT_end_lib:
+      InLib = false;
+      break;
     }
   }
 

Modified: lld/trunk/ELF/Driver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.h?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.h (original)
+++ lld/trunk/ELF/Driver.h Thu Apr  7 14:24:51 2016
@@ -33,8 +33,13 @@ private:
   void createFiles(llvm::opt::InputArgList &Args);
   template <class ELFT> void link(llvm::opt::InputArgList &Args);
 
-  llvm::BumpPtrAllocator Alloc;
+  // True if we are in --whole-archive and --no-whole-archive.
   bool WholeArchive = false;
+
+  // True if we are in --start-lib and --end-lib.
+  bool InLib = false;
+
+  llvm::BumpPtrAllocator Alloc;
   std::vector<std::unique_ptr<InputFile>> Files;
   std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
 };

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Thu Apr  7 14:24:51 2016
@@ -564,6 +564,66 @@ std::unique_ptr<InputFile> elf::createSh
   return createELFFile<SharedFile>(MB);
 }
 
+void LazyObjectFile::parse() {
+  for (StringRef Sym : getSymbols())
+    LazySymbols.emplace_back(Sym, this->MB);
+}
+
+template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
+  typedef typename ELFT::Shdr Elf_Shdr;
+  typedef typename ELFT::Sym Elf_Sym;
+  typedef typename ELFT::SymRange Elf_Sym_Range;
+
+  const ELFFile<ELFT> Obj = createELFObj<ELFT>(this->MB);
+  for (const Elf_Shdr &Sec : Obj.sections()) {
+    if (Sec.sh_type != SHT_SYMTAB)
+      continue;
+    Elf_Sym_Range Syms = Obj.symbols(&Sec);
+    uint32_t FirstNonLocal = Sec.sh_info;
+    StringRef StringTable = check(Obj.getStringTableForSymtab(Sec));
+    std::vector<StringRef> V;
+    for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal))
+      V.push_back(check(Sym.getName(StringTable)));
+    return V;
+  }
+  return {};
+}
+
+std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() {
+  LLVMContext Context;
+  std::unique_ptr<IRObjectFile> Obj =
+      check(IRObjectFile::create(this->MB, Context));
+  std::vector<StringRef> V;
+  for (const BasicSymbolRef &Sym : Obj->symbols()) {
+    if (BitcodeFile::shouldSkip(Sym))
+      continue;
+    SmallString<64> Name;
+    raw_svector_ostream OS(Name);
+    Sym.printName(OS);
+    V.push_back(Saver.save(StringRef(Name)));
+  }
+  return V;
+}
+
+// Returns a vector of globally-visible symbol names.
+std::vector<StringRef> LazyObjectFile::getSymbols() {
+  using namespace sys::fs;
+
+  StringRef Buf = this->MB.getBuffer();
+  if (identify_magic(Buf) == file_magic::bitcode)
+    return getBitcodeSymbols();
+
+  std::pair<unsigned char, unsigned char> Type = getElfArchType(Buf);
+  if (Type.first == ELF::ELFCLASS32) {
+    if (Type.second == ELF::ELFDATA2LSB)
+      return getElfSymbols<ELF32LE>();
+    return getElfSymbols<ELF32BE>();
+  }
+  if (Type.second == ELF::ELFDATA2LSB)
+    return getElfSymbols<ELF64LE>();
+  return getElfSymbols<ELF64BE>();
+}
+
 template class elf::ELFFileBase<ELF32LE>;
 template class elf::ELFFileBase<ELF32BE>;
 template class elf::ELFFileBase<ELF64LE>;

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Thu Apr  7 14:24:51 2016
@@ -36,7 +36,14 @@ class SymbolBody;
 // The root class of input files.
 class InputFile {
 public:
-  enum Kind { ObjectKind, SharedKind, ArchiveKind, BitcodeKind };
+  enum Kind {
+    ObjectKind,
+    SharedKind,
+    LazyObjectKind,
+    ArchiveKind,
+    BitcodeKind,
+  };
+
   Kind kind() const { return FileKind; }
 
   StringRef getName() const { return MB.getBufferIdentifier(); }
@@ -154,6 +161,36 @@ private:
   llvm::SpecificBumpPtrAllocator<EHInputSection<ELFT>> EHAlloc;
 };
 
+// LazyObjectFile is analogous to ArchiveFile in the sense that
+// the file contains lazy symbols. The difference is that
+// LazyObjectFile wraps a single file instead of multiple files.
+//
+// This class is used for --start-lib and --end-lib options which
+// instruct the linker to link object files between them with the
+// archive file semantics.
+class LazyObjectFile : public InputFile {
+public:
+  explicit LazyObjectFile(MemoryBufferRef M) : InputFile(LazyObjectKind, M) {}
+
+  static bool classof(const InputFile *F) {
+    return F->kind() == LazyObjectKind;
+  }
+
+  void parse();
+
+  llvm::MutableArrayRef<LazyObject> getLazySymbols() { return LazySymbols; }
+
+private:
+  std::vector<StringRef> getSymbols();
+  template <class ELFT> std::vector<StringRef> getElfSymbols();
+  std::vector<StringRef> getBitcodeSymbols();
+
+  llvm::BumpPtrAllocator Alloc;
+  llvm::StringSaver Saver{Alloc};
+  std::vector<LazyObject> LazySymbols;
+};
+
+// An ArchiveFile object represents a .a file.
 class ArchiveFile : public InputFile {
 public:
   explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
@@ -165,11 +202,11 @@ public:
   // (So that we don't instantiate same members more than once.)
   MemoryBufferRef getMember(const Archive::Symbol *Sym);
 
-  llvm::MutableArrayRef<Lazy> getLazySymbols() { return LazySymbols; }
+  llvm::MutableArrayRef<LazyArchive> getLazySymbols() { return LazySymbols; }
 
 private:
   std::unique_ptr<Archive> File;
-  std::vector<Lazy> LazySymbols;
+  std::vector<LazyArchive> LazySymbols;
   llvm::DenseSet<uint64_t> Seen;
 };
 

Modified: lld/trunk/ELF/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Options.td?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/Options.td (original)
+++ lld/trunk/ELF/Options.td Thu Apr  7 14:24:51 2016
@@ -48,6 +48,9 @@ def eh_frame_hdr : Flag<["--"], "eh-fram
 def enable_new_dtags : Flag<["--"], "enable-new-dtags">,
   HelpText<"Enable new dynamic tags">;
 
+def end_lib : Flag<["--"], "end-lib">,
+  HelpText<"End a library">;
+
 def entry : Separate<["--", "-"], "entry">, MetaVarName<"<entry>">,
   HelpText<"Name of entry point symbol">;
 
@@ -121,6 +124,9 @@ def shared : Flag<["-"], "shared">,
 def soname : Joined<["-"], "soname=">,
   HelpText<"Set DT_SONAME">;
 
+def start_lib : Flag<["--"], "start-lib">,
+  HelpText<"Start a library">;
+
 def strip_all : Flag<["--"], "strip-all">,
   HelpText<"Strip all symbols">;
 

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Thu Apr  7 14:24:51 2016
@@ -1501,7 +1501,8 @@ SymbolTableSection<ELFT>::getOutputSecti
     break;
   case SymbolBody::UndefinedElfKind:
   case SymbolBody::UndefinedBitcodeKind:
-  case SymbolBody::LazyKind:
+  case SymbolBody::LazyArchiveKind:
+  case SymbolBody::LazyObjectKind:
     break;
   case SymbolBody::DefinedBitcodeKind:
     llvm_unreachable("should have been replaced");

Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Thu Apr  7 14:24:51 2016
@@ -75,7 +75,7 @@ void SymbolTable<ELFT>::addFile(std::uni
     return;
   }
 
-  // LLVM bitcode file.
+  // LLVM bitcode file
   if (auto *F = dyn_cast<BitcodeFile>(FileP)) {
     BitcodeFiles.emplace_back(cast<BitcodeFile>(File.release()));
     F->parse(ComdatGroups);
@@ -85,7 +85,16 @@ void SymbolTable<ELFT>::addFile(std::uni
     return;
   }
 
-  // .o file
+  // Lazy object file
+  if (auto *F = dyn_cast<LazyObjectFile>(FileP)) {
+    LazyObjectFiles.emplace_back(cast<LazyObjectFile>(File.release()));
+    F->parse();
+    for (Lazy &Sym : F->getLazySymbols())
+      addLazy(&Sym);
+    return;
+  }
+
+  // Regular object file
   auto *F = cast<ObjectFile<ELFT>>(FileP);
   ObjectFiles.emplace_back(cast<ObjectFile<ELFT>>(File.release()));
   F->parse(ComdatGroups);
@@ -306,7 +315,7 @@ void SymbolTable<ELFT>::addMemberFile(Sy
 
   // Fetch a member file that has the definition for L.
   // getMember returns nullptr if the member was already read from the library.
-  if (std::unique_ptr<InputFile> File = L->getMember())
+  if (std::unique_ptr<InputFile> File = L->getFile())
     addFile(std::move(File));
 }
 

Modified: lld/trunk/ELF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.h (original)
+++ lld/trunk/ELF/SymbolTable.h Thu Apr  7 14:24:51 2016
@@ -89,6 +89,7 @@ private:
   // The symbol table owns all file objects.
   std::vector<std::unique_ptr<ArchiveFile>> ArchiveFiles;
   std::vector<std::unique_ptr<ObjectFile<ELFT>>> ObjectFiles;
+  std::vector<std::unique_ptr<LazyObjectFile>> LazyObjectFiles;
   std::vector<std::unique_ptr<SharedFile<ELFT>>> SharedFiles;
   std::vector<std::unique_ptr<BitcodeFile>> BitcodeFiles;
 

Modified: lld/trunk/ELF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.cpp (original)
+++ lld/trunk/ELF/Symbols.cpp Thu Apr  7 14:24:51 2016
@@ -78,7 +78,8 @@ static typename ELFT::uint getSymVA(cons
   case SymbolBody::UndefinedElfKind:
   case SymbolBody::UndefinedBitcodeKind:
     return 0;
-  case SymbolBody::LazyKind:
+  case SymbolBody::LazyArchiveKind:
+  case SymbolBody::LazyObjectKind:
     assert(Body.isUsedInRegularObj() && "lazy symbol reached writer");
     return 0;
   case SymbolBody::DefinedBitcodeKind:
@@ -301,7 +302,13 @@ DefinedCommon::DefinedCommon(StringRef N
     : Defined(SymbolBody::DefinedCommonKind, N, Binding, StOther, Type),
       Alignment(Alignment), Size(Size) {}
 
-std::unique_ptr<InputFile> Lazy::getMember() {
+std::unique_ptr<InputFile> Lazy::getFile() {
+  if (auto *S = dyn_cast<LazyArchive>(this))
+    return S->getFile();
+  return cast<LazyObject>(this)->getFile();
+}
+
+std::unique_ptr<InputFile> LazyArchive::getFile() {
   MemoryBufferRef MBRef = File->getMember(&Sym);
 
   // getMember returns an empty buffer if the member was already
@@ -311,6 +318,10 @@ std::unique_ptr<InputFile> Lazy::getMemb
   return createObjectFile(MBRef, File->getName());
 }
 
+std::unique_ptr<InputFile> LazyObject::getFile() {
+  return createObjectFile(MBRef);
+}
+
 // Returns the demangled C++ symbol name for Name.
 std::string elf::demangle(StringRef Name) {
 #if !defined(HAVE_CXXABI_H)

Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Thu Apr  7 14:24:51 2016
@@ -59,7 +59,8 @@ public:
     DefinedLast = DefinedSyntheticKind,
     UndefinedElfKind,
     UndefinedBitcodeKind,
-    LazyKind
+    LazyArchiveKind,
+    LazyObjectKind,
   };
 
   Kind kind() const { return static_cast<Kind>(SymbolKind); }
@@ -70,7 +71,9 @@ public:
   }
   bool isDefined() const { return SymbolKind <= DefinedLast; }
   bool isCommon() const { return SymbolKind == DefinedCommonKind; }
-  bool isLazy() const { return SymbolKind == LazyKind; }
+  bool isLazy() const {
+    return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
+  }
   bool isShared() const { return SymbolKind == SharedKind; }
   bool isLocal() const { return Binding == llvm::ELF::STB_LOCAL; }
   bool isUsedInRegularObj() const { return IsUsedInRegularObj; }
@@ -339,22 +342,51 @@ public:
 // the same name, it will ask the Lazy to load a file.
 class Lazy : public SymbolBody {
 public:
-  Lazy(ArchiveFile *F, const llvm::object::Archive::Symbol S)
-      : SymbolBody(LazyKind, S.getName(), llvm::ELF::STB_GLOBAL,
-                   llvm::ELF::STV_DEFAULT, /* Type */ 0),
-        File(F), Sym(S) {}
+  Lazy(SymbolBody::Kind K, StringRef Name)
+      : SymbolBody(K, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT,
+                   /* Type */ 0) {}
 
-  static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; }
+  static bool classof(const SymbolBody *S) { return S->isLazy(); }
 
   // Returns an object file for this symbol, or a nullptr if the file
   // was already returned.
-  std::unique_ptr<InputFile> getMember();
+  std::unique_ptr<InputFile> getFile();
+};
+
+// LazyArchive symbols represents symbols in archive files.
+class LazyArchive : public Lazy {
+public:
+  LazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S)
+      : Lazy(LazyArchiveKind, S.getName()), File(F), Sym(S) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == LazyArchiveKind;
+  }
+
+  std::unique_ptr<InputFile> getFile();
 
 private:
   ArchiveFile *File;
   const llvm::object::Archive::Symbol Sym;
 };
 
+// LazyObject symbols represents symbols in object files between
+// --start-lib and --end-lib options.
+class LazyObject : public Lazy {
+public:
+  LazyObject(StringRef Name, MemoryBufferRef M)
+      : Lazy(LazyObjectKind, Name), MBRef(M) {}
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == LazyObjectKind;
+  }
+
+  std::unique_ptr<InputFile> getFile();
+
+private:
+  MemoryBufferRef MBRef;
+};
+
 // Some linker-generated symbols need to be created as
 // DefinedRegular symbols.
 template <class ELFT> struct ElfSym {

Added: lld/trunk/test/ELF/lto/Inputs/start-lib.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/Inputs/start-lib.ll?rev=265710&view=auto
==============================================================================
--- lld/trunk/test/ELF/lto/Inputs/start-lib.ll (added)
+++ lld/trunk/test/ELF/lto/Inputs/start-lib.ll Thu Apr  7 14:24:51 2016
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @_bar() {
+  ret void
+}

Added: lld/trunk/test/ELF/lto/start-lib.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/start-lib.ll?rev=265710&view=auto
==============================================================================
--- lld/trunk/test/ELF/lto/start-lib.ll (added)
+++ lld/trunk/test/ELF/lto/start-lib.ll Thu Apr  7 14:24:51 2016
@@ -0,0 +1,19 @@
+; REQUIRES: x86
+;
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-as %p/Inputs/start-lib.ll -o %t2.o
+;
+; RUN: ld.lld -m elf_x86_64 -shared -o %t3 %t1.o %t2.o
+; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=ADDED %s
+; ADDED: Name: _bar
+;
+; RUN: ld.lld -m elf_x86_64 -shared -o %t3 %t1.o --start-lib %t2.o
+; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=LIB %s
+; LIB-NOT: Name: _bar
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @_start() {
+  ret void
+}

Added: lld/trunk/test/ELF/start-lib.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/start-lib.s?rev=265710&view=auto
==============================================================================
--- lld/trunk/test/ELF/start-lib.s (added)
+++ lld/trunk/test/ELF/start-lib.s Thu Apr  7 14:24:51 2016
@@ -0,0 +1,16 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN:   %p/Inputs/whole-archive.s -o %t2.o
+
+// RUN: ld.lld -o %t3 %t1.o %t2.o
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=ADDED %s
+// ADDED: Name: _bar
+
+// RUN: ld.lld -o %t3 %t1.o --start-lib %t2.o
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=LIB %s
+// LIB-NOT: Name: _bar
+
+.globl _start
+_start:




More information about the llvm-commits mailing list