[lld] r370487 - [lld-link] implement -start-lib and -end-lib

Bob Haarman via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 30 09:50:10 PDT 2019


Author: inglorion
Date: Fri Aug 30 09:50:10 2019
New Revision: 370487

URL: http://llvm.org/viewvc/llvm-project?rev=370487&view=rev
Log:
[lld-link] implement -start-lib and -end-lib

Summary:
This implements -start-lib and -end-lib flags for lld-link, analogous
to the similarly named options in ld.lld. Object files after
-start-lib are included in the link only when needed to resolve
undefined symbols. The -end-lib flag goes back to the normal behavior
of always including object files in the link. This mimics the
semantics of static libraries, but without needing to actually create
the archive file.

Reviewers: ruiu, smeenai, MaskRay

Reviewed By: ruiu, MaskRay

Subscribers: akhuang, llvm-commits

Tags: #llvm

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

Added:
    lld/trunk/test/COFF/Inputs/start-lib1.ll
    lld/trunk/test/COFF/Inputs/start-lib2.ll
    lld/trunk/test/COFF/start-lib-cmd-diagnostics.ll
    lld/trunk/test/COFF/start-lib.ll
Modified:
    lld/trunk/COFF/DebugTypes.cpp
    lld/trunk/COFF/Driver.cpp
    lld/trunk/COFF/Driver.h
    lld/trunk/COFF/InputFiles.cpp
    lld/trunk/COFF/InputFiles.h
    lld/trunk/COFF/Options.td
    lld/trunk/COFF/SymbolTable.cpp
    lld/trunk/COFF/SymbolTable.h
    lld/trunk/COFF/Symbols.cpp
    lld/trunk/COFF/Symbols.h
    lld/trunk/COFF/Writer.cpp

Modified: lld/trunk/COFF/DebugTypes.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DebugTypes.cpp?rev=370487&r1=370486&r2=370487&view=diff
==============================================================================
--- lld/trunk/COFF/DebugTypes.cpp (original)
+++ lld/trunk/COFF/DebugTypes.cpp Fri Aug 30 09:50:10 2019
@@ -231,7 +231,7 @@ void TypeServerSource::enqueue(const Obj
   if (!it.second)
     return; // another OBJ already scheduled this PDB for load
 
-  driver->enqueuePath(*p, false);
+  driver->enqueuePath(*p, false, false);
 }
 
 // Create an instance of TypeServerSource or an error string if the PDB couldn't

Modified: lld/trunk/COFF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=370487&r1=370486&r2=370487&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.cpp (original)
+++ lld/trunk/COFF/Driver.cpp Fri Aug 30 09:50:10 2019
@@ -170,7 +170,7 @@ MemoryBufferRef LinkerDriver::takeBuffer
 }
 
 void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
-                             bool wholeArchive) {
+                             bool wholeArchive, bool lazy) {
   StringRef filename = mb->getBufferIdentifier();
 
   MemoryBufferRef mbref = takeBuffer(std::move(mb));
@@ -195,11 +195,17 @@ void LinkerDriver::addBuffer(std::unique
     symtab->addFile(make<ArchiveFile>(mbref));
     break;
   case file_magic::bitcode:
-    symtab->addFile(make<BitcodeFile>(mbref, "", 0));
+    if (lazy)
+      symtab->addFile(make<LazyObjFile>(mbref));
+    else
+      symtab->addFile(make<BitcodeFile>(mbref, "", 0));
     break;
   case file_magic::coff_object:
   case file_magic::coff_import_library:
-    symtab->addFile(make<ObjFile>(mbref));
+    if (lazy)
+      symtab->addFile(make<LazyObjFile>(mbref));
+    else
+      symtab->addFile(make<ObjFile>(mbref));
     break;
   case file_magic::pdb:
     loadTypeServerSource(mbref);
@@ -220,7 +226,7 @@ void LinkerDriver::addBuffer(std::unique
   }
 }
 
-void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive) {
+void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
   auto future =
       std::make_shared<std::future<MBErrPair>>(createFutureForFile(path));
   std::string pathStr = path;
@@ -240,7 +246,7 @@ void LinkerDriver::enqueuePath(StringRef
       else
         error(msg + "; did you mean '" + nearest + "'");
     } else
-      driver->addBuffer(std::move(mbOrErr.first), wholeArchive);
+      driver->addBuffer(std::move(mbOrErr.first), wholeArchive, lazy);
   });
 }
 
@@ -359,7 +365,7 @@ void LinkerDriver::parseDirectives(Input
       break;
     case OPT_defaultlib:
       if (Optional<StringRef> path = findLib(arg->getValue()))
-        enqueuePath(*path, false);
+        enqueuePath(*path, false, false);
       break;
     case OPT_entry:
       config->entry = addUndefined(mangle(arg->getValue()));
@@ -1553,19 +1559,45 @@ void LinkerDriver::link(ArrayRef<const c
     return false;
   };
 
-  // Create a list of input files. Files can be given as arguments
-  // for /defaultlib option.
-  for (auto *arg : args.filtered(OPT_INPUT, OPT_wholearchive_file))
-    if (Optional<StringRef> path = findFile(arg->getValue()))
-      enqueuePath(*path, isWholeArchive(*path));
+  // Create a list of input files. These can be given as OPT_INPUT options
+  // and OPT_wholearchive_file options, and we also need to track OPT_start_lib
+  // and OPT_end_lib.
+  bool inLib = false;
+  for (auto *arg : args) {
+    switch (arg->getOption().getID()) {
+    case OPT_end_lib:
+      if (!inLib)
+        error("stray " + arg->getSpelling());
+      inLib = false;
+      break;
+    case OPT_start_lib:
+      if (inLib)
+        error("nested " + arg->getSpelling());
+      inLib = true;
+      break;
+    case OPT_wholearchive_file:
+      if (Optional<StringRef> path = findFile(arg->getValue()))
+        enqueuePath(*path, true, inLib);
+      break;
+    case OPT_INPUT:
+      if (Optional<StringRef> path = findFile(arg->getValue()))
+        enqueuePath(*path, isWholeArchive(*path), inLib);
+      break;
+    default:
+      // Ignore other options.
+      break;
+    }
+  }
 
+  // Process files specified as /defaultlib. These should be enequeued after
+  // other files, which is why they are in a separate loop.
   for (auto *arg : args.filtered(OPT_defaultlib))
     if (Optional<StringRef> path = findLib(arg->getValue()))
-      enqueuePath(*path, false);
+      enqueuePath(*path, false, false);
 
   // Windows specific -- Create a resource file containing a manifest file.
   if (config->manifest == Configuration::Embed)
-    addBuffer(createManifestRes(), false);
+    addBuffer(createManifestRes(), false, false);
 
   // Read all input files given via the command line.
   run();
@@ -1782,7 +1814,7 @@ void LinkerDriver::link(ArrayRef<const c
   if (args.hasArg(OPT_include_optional)) {
     // Handle /includeoptional
     for (auto *arg : args.filtered(OPT_include_optional))
-      if (dyn_cast_or_null<Lazy>(symtab->find(arg->getValue())))
+      if (dyn_cast_or_null<LazyArchive>(symtab->find(arg->getValue())))
         addUndefined(arg->getValue());
     while (run());
   }

Modified: lld/trunk/COFF/Driver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.h?rev=370487&r1=370486&r2=370487&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.h (original)
+++ lld/trunk/COFF/Driver.h Fri Aug 30 09:50:10 2019
@@ -77,7 +77,7 @@ public:
 
   MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> mb);
 
-  void enqueuePath(StringRef path, bool wholeArchive);
+  void enqueuePath(StringRef path, bool wholeArchive, bool lazy);
 
 private:
   std::unique_ptr<llvm::TarWriter> tar; // for /linkrepro
@@ -124,7 +124,8 @@ private:
   StringRef findDefaultEntry();
   WindowsSubsystem inferSubsystem();
 
-  void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive);
+  void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive,
+                 bool lazy);
   void addArchiveBuffer(MemoryBufferRef mbref, StringRef symName,
                         StringRef parentName, uint64_t offsetInArchive);
 

Modified: lld/trunk/COFF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.cpp?rev=370487&r1=370486&r2=370487&view=diff
==============================================================================
--- lld/trunk/COFF/InputFiles.cpp (original)
+++ lld/trunk/COFF/InputFiles.cpp Fri Aug 30 09:50:10 2019
@@ -73,6 +73,10 @@ static void checkAndSetWeakAlias(SymbolT
   }
 }
 
+static bool ignoredSymbolName(StringRef name) {
+  return name == "@feat.00" || name == "@comp.id";
+}
+
 ArchiveFile::ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {}
 
 void ArchiveFile::parse() {
@@ -81,7 +85,7 @@ void ArchiveFile::parse() {
 
   // Read the symbol table to construct Lazy objects.
   for (const Archive::Symbol &sym : file->symbols())
-    symtab->addLazy(this, sym);
+    symtab->addLazyArchive(this, sym);
 }
 
 // Returns a buffer pointing to a member file containing a given symbol.
@@ -116,6 +120,49 @@ std::vector<MemoryBufferRef> getArchiveM
   return v;
 }
 
+void LazyObjFile::fetch() {
+  if (mb.getBuffer().empty())
+    return;
+
+  InputFile *file;
+  if (isBitcode(mb))
+    file = make<BitcodeFile>(mb, "", 0, std::move(symbols));
+  else
+    file = make<ObjFile>(mb, std::move(symbols));
+  mb = {};
+  symtab->addFile(file);
+}
+
+void LazyObjFile::parse() {
+  if (isBitcode(this->mb)) {
+    // Bitcode file.
+    std::unique_ptr<lto::InputFile> obj =
+        CHECK(lto::InputFile::create(this->mb), this);
+    for (const lto::InputFile::Symbol &sym : obj->symbols()) {
+      if (!sym.isUndefined())
+        symtab->addLazyObject(this, sym.getName());
+    }
+    return;
+  }
+
+  // Native object file.
+  COFFObjectFile *coffObj =
+      dyn_cast<COFFObjectFile>(CHECK(createBinary(mb), this).get());
+  uint32_t numSymbols = coffObj->getNumberOfSymbols();
+  for (uint32_t i = 0; i < numSymbols; ++i) {
+    COFFSymbolRef coffSym = check(coffObj->getSymbol(i));
+    if (coffSym.isUndefined() || !coffSym.isExternal() ||
+        coffSym.isWeakExternal())
+      continue;
+    StringRef name;
+    coffObj->getSymbolName(coffSym, name);
+    if (coffSym.isAbsolute() && ignoredSymbolName(name))
+      continue;
+    symtab->addLazyObject(this, name);
+    i += coffSym.getNumberOfAuxSymbols();
+  }
+}
+
 void ObjFile::parse() {
   // Parse a memory buffer as a COFF file.
   std::unique_ptr<Binary> bin = CHECK(createBinary(mb), this);
@@ -526,13 +573,11 @@ Optional<Symbol *> ObjFile::createDefine
   if (sym.isAbsolute()) {
     StringRef name = getName();
 
-    // Skip special symbols.
-    if (name == "@comp.id")
-      return nullptr;
-    if (name == "@feat.00") {
+    if (name == "@feat.00")
       feat00Flags = sym.getValue();
+    // Skip special symbols.
+    if (ignoredSymbolName(name))
       return nullptr;
-    }
 
     if (sym.isExternal())
       return symtab->addAbsolute(name, sym);
@@ -782,8 +827,9 @@ void ImportFile::parse() {
 }
 
 BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
-                         uint64_t offsetInArchive)
-    : InputFile(BitcodeKind, mb) {
+                         uint64_t offsetInArchive,
+                         std::vector<Symbol *> &&symbols)
+    : InputFile(BitcodeKind, mb), symbols(std::move(symbols)) {
   std::string path = mb.getBufferIdentifier().str();
   if (config->thinLTOIndexOnly)
     path = replaceThinLTOSuffix(mb.getBufferIdentifier());

Modified: lld/trunk/COFF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.h?rev=370487&r1=370486&r2=370487&view=diff
==============================================================================
--- lld/trunk/COFF/InputFiles.h (original)
+++ lld/trunk/COFF/InputFiles.h Fri Aug 30 09:50:10 2019
@@ -14,6 +14,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/BinaryFormat/Magic.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
 #include "llvm/LTO/LTO.h"
 #include "llvm/Object/Archive.h"
@@ -55,7 +56,13 @@ class TpiSource;
 // The root class of input files.
 class InputFile {
 public:
-  enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind };
+  enum Kind {
+    ArchiveKind,
+    ObjectKind,
+    LazyObjectKind,
+    ImportKind,
+    BitcodeKind
+  };
   Kind kind() const { return fileKind; }
   virtual ~InputFile() {}
 
@@ -102,10 +109,28 @@ private:
   llvm::DenseSet<uint64_t> seen;
 };
 
+// .obj or .o file between -start-lib and -end-lib.
+class LazyObjFile : public InputFile {
+public:
+  explicit LazyObjFile(MemoryBufferRef m) : InputFile(LazyObjectKind, m) {}
+  static bool classof(const InputFile *f) {
+    return f->kind() == LazyObjectKind;
+  }
+  // Makes this object file part of the link.
+  void fetch();
+  // Adds the symbols in this file to the symbol table as LazyObject symbols.
+  void parse() override;
+
+private:
+  std::vector<Symbol *> symbols;
+};
+
 // .obj or .o file. This may be a member of an archive file.
 class ObjFile : public InputFile {
 public:
   explicit ObjFile(MemoryBufferRef m) : InputFile(ObjectKind, m) {}
+  explicit ObjFile(MemoryBufferRef m, std::vector<Symbol *> &&symbols)
+      : InputFile(ObjectKind, m), symbols(std::move(symbols)) {}
   static bool classof(const InputFile *f) { return f->kind() == ObjectKind; }
   void parse() override;
   MachineTypes getMachineType() override;
@@ -301,7 +326,11 @@ public:
 class BitcodeFile : public InputFile {
 public:
   BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
-              uint64_t offsetInArchive);
+              uint64_t offsetInArchive)
+      : BitcodeFile(mb, archiveName, offsetInArchive, {}) {}
+  explicit BitcodeFile(MemoryBufferRef m, StringRef archiveName,
+                       uint64_t offsetInArchive,
+                       std::vector<Symbol *> &&symbols);
   static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
   ArrayRef<Symbol *> getSymbols() { return symbols; }
   MachineTypes getMachineType() override;
@@ -314,6 +343,10 @@ private:
   std::vector<Symbol *> symbols;
 };
 
+inline bool isBitcode(MemoryBufferRef mb) {
+  return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode;
+}
+
 std::string replaceThinLTOSuffix(StringRef path);
 } // namespace coff
 

Modified: lld/trunk/COFF/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Options.td?rev=370487&r1=370486&r2=370487&view=diff
==============================================================================
--- lld/trunk/COFF/Options.td (original)
+++ lld/trunk/COFF/Options.td Fri Aug 30 09:50:10 2019
@@ -162,6 +162,8 @@ def help : F<"help">;
 def help_q : Flag<["/??", "-??", "/?", "-?"], "">, Alias<help>;
 
 // LLD extensions
+def end_lib : F<"end-lib">,
+  HelpText<"End a grouping of objects that should be treated as if they were together in an archive">;
 def exclude_all_symbols : F<"exclude-all-symbols">;
 def export_all_symbols : F<"export-all-symbols">;
 defm demangle : B<"demangle",
@@ -176,6 +178,8 @@ def pdb_source_path : P<"pdbsourcepath",
                         "Base path used to make relative source file path absolute in PDB">;
 def rsp_quoting : Joined<["--"], "rsp-quoting=">,
   HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">;
+def start_lib : F<"start-lib">,
+  HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;
 def thinlto_emit_imports_files :
     F<"thinlto-emit-imports-files">,
     HelpText<"Emit .imports files with -thinlto-index-only">;

Modified: lld/trunk/COFF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.cpp?rev=370487&r1=370486&r2=370487&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.cpp (original)
+++ lld/trunk/COFF/SymbolTable.cpp Fri Aug 30 09:50:10 2019
@@ -61,6 +61,24 @@ static void errorOrWarn(const Twine &s)
     error(s);
 }
 
+// Causes the file associated with a lazy symbol to be linked in.
+static void forceLazy(Symbol *s) {
+  s->pendingArchiveLoad = true;
+  switch (s->kind()) {
+  case Symbol::Kind::LazyArchiveKind: {
+    auto *l = cast<LazyArchive>(s);
+    l->file->addMember(l->sym);
+    break;
+  }
+  case Symbol::Kind::LazyObjectKind:
+    cast<LazyObject>(s)->file->fetch();
+    break;
+  default:
+    llvm_unreachable(
+        "symbol passed to forceLazy is not a LazyArchive or LazyObject");
+  }
+}
+
 // Returns the symbol in SC whose value is <= Addr that is closest to Addr.
 // This is generally the global variable or function whose definition contains
 // Addr.
@@ -192,16 +210,15 @@ void SymbolTable::loadMinGWAutomaticImpo
 
     if (name.startswith("__imp_"))
       continue;
-    // If we have an undefined symbol, but we have a Lazy representing a
-    // symbol we could load from file, make sure to load that.
-    Lazy *l = dyn_cast_or_null<Lazy>(find(("__imp_" + name).str()));
-    if (!l || l->pendingArchiveLoad)
+    // If we have an undefined symbol, but we have a lazy symbol we could
+    // load, load it.
+    Symbol *l = find(("__imp_" + name).str());
+    if (!l || l->pendingArchiveLoad || !l->isLazy())
       continue;
 
-    log("Loading lazy " + l->getName() + " from " + l->file->getName() +
+    log("Loading lazy " + l->getName() + " from " + l->getFile()->getName() +
         " for automatic import");
-    l->pendingArchiveLoad = true;
-    l->file->addMember(l->sym);
+    forceLazy(l);
   }
 }
 
@@ -435,26 +452,22 @@ Symbol *SymbolTable::addUndefined(String
   Symbol *s;
   bool wasInserted;
   std::tie(s, wasInserted) = insert(name, f);
-  if (wasInserted || (isa<Lazy>(s) && isWeakAlias)) {
+  if (wasInserted || (s->isLazy() && isWeakAlias)) {
     replaceSymbol<Undefined>(s, name);
     return s;
   }
-  if (auto *l = dyn_cast<Lazy>(s)) {
-    if (!s->pendingArchiveLoad) {
-      s->pendingArchiveLoad = true;
-      l->file->addMember(l->sym);
-    }
-  }
+  if (s->isLazy())
+    forceLazy(s);
   return s;
 }
 
-void SymbolTable::addLazy(ArchiveFile *f, const Archive::Symbol &sym) {
+void SymbolTable::addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym) {
   StringRef name = sym.getName();
   Symbol *s;
   bool wasInserted;
   std::tie(s, wasInserted) = insert(name);
   if (wasInserted) {
-    replaceSymbol<Lazy>(s, f, sym);
+    replaceSymbol<LazyArchive>(s, f, sym);
     return;
   }
   auto *u = dyn_cast<Undefined>(s);
@@ -464,6 +477,21 @@ void SymbolTable::addLazy(ArchiveFile *f
   f->addMember(sym);
 }
 
+void SymbolTable::addLazyObject(LazyObjFile *f, StringRef n) {
+  Symbol *s;
+  bool wasInserted;
+  std::tie(s, wasInserted) = insert(n, f);
+  if (wasInserted) {
+    replaceSymbol<LazyObject>(s, f, n);
+    return;
+  }
+  auto *u = dyn_cast<Undefined>(s);
+  if (!u || u->weakAlias || s->pendingArchiveLoad)
+    return;
+  s->pendingArchiveLoad = true;
+  f->fetch();
+}
+
 void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile) {
   std::string msg = "duplicate symbol: " + toString(*existing) + " in " +
                     toString(existing->getFile()) + " and in " +
@@ -480,7 +508,7 @@ Symbol *SymbolTable::addAbsolute(StringR
   bool wasInserted;
   std::tie(s, wasInserted) = insert(n, nullptr);
   s->isUsedInRegularObj = true;
-  if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
+  if (wasInserted || isa<Undefined>(s) || s->isLazy())
     replaceSymbol<DefinedAbsolute>(s, n, sym);
   else if (!isa<DefinedCOFF>(s))
     reportDuplicate(s, nullptr);
@@ -492,7 +520,7 @@ Symbol *SymbolTable::addAbsolute(StringR
   bool wasInserted;
   std::tie(s, wasInserted) = insert(n, nullptr);
   s->isUsedInRegularObj = true;
-  if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
+  if (wasInserted || isa<Undefined>(s) || s->isLazy())
     replaceSymbol<DefinedAbsolute>(s, n, va);
   else if (!isa<DefinedCOFF>(s))
     reportDuplicate(s, nullptr);
@@ -504,7 +532,7 @@ Symbol *SymbolTable::addSynthetic(String
   bool wasInserted;
   std::tie(s, wasInserted) = insert(n, nullptr);
   s->isUsedInRegularObj = true;
-  if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
+  if (wasInserted || isa<Undefined>(s) || s->isLazy())
     replaceSymbol<DefinedSynthetic>(s, n, c);
   else if (!isa<DefinedCOFF>(s))
     reportDuplicate(s, nullptr);
@@ -560,7 +588,7 @@ Symbol *SymbolTable::addImportData(Strin
   bool wasInserted;
   std::tie(s, wasInserted) = insert(n, nullptr);
   s->isUsedInRegularObj = true;
-  if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) {
+  if (wasInserted || isa<Undefined>(s) || s->isLazy()) {
     replaceSymbol<DefinedImportData>(s, n, f);
     return s;
   }
@@ -575,7 +603,7 @@ Symbol *SymbolTable::addImportThunk(Stri
   bool wasInserted;
   std::tie(s, wasInserted) = insert(name, nullptr);
   s->isUsedInRegularObj = true;
-  if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) {
+  if (wasInserted || isa<Undefined>(s) || s->isLazy()) {
     replaceSymbol<DefinedImportThunk>(s, name, id, machine);
     return s;
   }
@@ -589,9 +617,12 @@ void SymbolTable::addLibcall(StringRef n
   if (!sym)
     return;
 
-  if (Lazy *l = dyn_cast<Lazy>(sym)) {
+  if (auto *l = dyn_cast<LazyArchive>(sym)) {
     MemoryBufferRef mb = l->getMemberBuffer();
-    if (identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode)
+    if (isBitcode(mb))
+      addUndefined(sym->getName());
+  } else if (LazyObject *o = dyn_cast<LazyObject>(sym)) {
+    if (isBitcode(o->file->mb))
       addUndefined(sym->getName());
   }
 }

Modified: lld/trunk/COFF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.h?rev=370487&r1=370486&r2=370487&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.h (original)
+++ lld/trunk/COFF/SymbolTable.h Fri Aug 30 09:50:10 2019
@@ -29,7 +29,7 @@ class Defined;
 class DefinedAbsolute;
 class DefinedRegular;
 class DefinedRelative;
-class Lazy;
+class LazyArchive;
 class SectionChunk;
 class Symbol;
 
@@ -86,7 +86,8 @@ public:
   Symbol *addAbsolute(StringRef n, uint64_t va);
 
   Symbol *addUndefined(StringRef name, InputFile *f, bool isWeakAlias);
-  void addLazy(ArchiveFile *f, const Archive::Symbol &sym);
+  void addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym);
+  void addLazyObject(LazyObjFile *f, StringRef n);
   Symbol *addAbsolute(StringRef n, COFFSymbolRef s);
   Symbol *addRegular(InputFile *f, StringRef n,
                      const llvm::object::coff_symbol_generic *s = nullptr,

Modified: lld/trunk/COFF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Symbols.cpp?rev=370487&r1=370486&r2=370487&view=diff
==============================================================================
--- lld/trunk/COFF/Symbols.cpp (original)
+++ lld/trunk/COFF/Symbols.cpp Fri Aug 30 09:50:10 2019
@@ -61,7 +61,9 @@ StringRef Symbol::getName() {
 InputFile *Symbol::getFile() {
   if (auto *sym = dyn_cast<DefinedCOFF>(this))
     return sym->file;
-  if (auto *sym = dyn_cast<Lazy>(this))
+  if (auto *sym = dyn_cast<LazyArchive>(this))
+    return sym->file;
+  if (auto *sym = dyn_cast<LazyObject>(this))
     return sym->file;
   return nullptr;
 }
@@ -119,7 +121,7 @@ Defined *Undefined::getWeakAlias() {
   return nullptr;
 }
 
-MemoryBufferRef Lazy::getMemberBuffer() {
+MemoryBufferRef LazyArchive::getMemberBuffer() {
   Archive::Child c =
     CHECK(sym.getMember(),
           "could not get the member for symbol " + toCOFFString(sym));

Modified: lld/trunk/COFF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Symbols.h?rev=370487&r1=370486&r2=370487&view=diff
==============================================================================
--- lld/trunk/COFF/Symbols.h (original)
+++ lld/trunk/COFF/Symbols.h Fri Aug 30 09:50:10 2019
@@ -59,7 +59,8 @@ public:
     DefinedSyntheticKind,
 
     UndefinedKind,
-    LazyKind,
+    LazyArchiveKind,
+    LazyObjectKind,
 
     LastDefinedCOFFKind = DefinedCommonKind,
     LastDefinedKind = DefinedSyntheticKind,
@@ -79,6 +80,10 @@ public:
   // after calling markLive.
   bool isLive() const;
 
+  bool isLazy() const {
+    return symbolKind == LazyArchiveKind || symbolKind == LazyObjectKind;
+  }
+
 protected:
   friend SymbolTable;
   explicit Symbol(Kind k, StringRef n = "")
@@ -256,26 +261,29 @@ private:
 // This class represents a symbol defined in an archive file. It is
 // created from an archive file header, and it knows how to load an
 // object file from an archive to replace itself with a defined
-// symbol. If the resolver finds both Undefined and Lazy for
-// the same name, it will ask the Lazy to load a file.
-class Lazy : public Symbol {
+// symbol. If the resolver finds both Undefined and LazyArchive for
+// the same name, it will ask the LazyArchive to load a file.
+class LazyArchive : public Symbol {
 public:
-  Lazy(ArchiveFile *f, const Archive::Symbol s)
-      : Symbol(LazyKind, s.getName()), file(f), sym(s) {}
+  LazyArchive(ArchiveFile *f, const Archive::Symbol s)
+      : Symbol(LazyArchiveKind, s.getName()), file(f), sym(s) {}
 
-  static bool classof(const Symbol *s) { return s->kind() == LazyKind; }
+  static bool classof(const Symbol *s) { return s->kind() == LazyArchiveKind; }
 
   MemoryBufferRef getMemberBuffer();
 
   ArchiveFile *file;
-
-private:
-  friend SymbolTable;
-
-private:
   const Archive::Symbol sym;
 };
 
+class LazyObject : public Symbol {
+public:
+  LazyObject(LazyObjFile *f, StringRef n)
+      : Symbol(LazyObjectKind, n), file(f) {}
+  static bool classof(const Symbol *s) { return s->kind() == LazyObjectKind; }
+  LazyObjFile *file;
+};
+
 // Undefined symbols.
 class Undefined : public Symbol {
 public:
@@ -381,7 +389,8 @@ inline uint64_t Defined::getRVA() {
     return cast<DefinedCommon>(this)->getRVA();
   case DefinedRegularKind:
     return cast<DefinedRegular>(this)->getRVA();
-  case LazyKind:
+  case LazyArchiveKind:
+  case LazyObjectKind:
   case UndefinedKind:
     llvm_unreachable("Cannot get the address for an undefined symbol.");
   }
@@ -404,7 +413,8 @@ inline Chunk *Defined::getChunk() {
     return cast<DefinedLocalImport>(this)->getChunk();
   case DefinedCommonKind:
     return cast<DefinedCommon>(this)->getChunk();
-  case LazyKind:
+  case LazyArchiveKind:
+  case LazyObjectKind:
   case UndefinedKind:
     llvm_unreachable("Cannot get the chunk of an undefined symbol.");
   }
@@ -419,11 +429,12 @@ union SymbolUnion {
   alignas(DefinedCommon) char b[sizeof(DefinedCommon)];
   alignas(DefinedAbsolute) char c[sizeof(DefinedAbsolute)];
   alignas(DefinedSynthetic) char d[sizeof(DefinedSynthetic)];
-  alignas(Lazy) char e[sizeof(Lazy)];
+  alignas(LazyArchive) char e[sizeof(LazyArchive)];
   alignas(Undefined) char f[sizeof(Undefined)];
   alignas(DefinedImportData) char g[sizeof(DefinedImportData)];
   alignas(DefinedImportThunk) char h[sizeof(DefinedImportThunk)];
   alignas(DefinedLocalImport) char i[sizeof(DefinedLocalImport)];
+  alignas(LazyObject) char j[sizeof(LazyObject)];
 };
 
 template <typename T, typename... ArgT>

Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=370487&r1=370486&r2=370487&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Fri Aug 30 09:50:10 2019
@@ -1519,7 +1519,8 @@ static void maybeAddAddressTakenFunction
     // Absolute is never code, synthetic generally isn't and usually isn't
     // determinable.
     break;
-  case Symbol::LazyKind:
+  case Symbol::LazyArchiveKind:
+  case Symbol::LazyObjectKind:
   case Symbol::UndefinedKind:
     // Undefined symbols resolve to zero, so they don't have an RVA. Lazy
     // symbols shouldn't have relocations.

Added: lld/trunk/test/COFF/Inputs/start-lib1.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/start-lib1.ll?rev=370487&view=auto
==============================================================================
--- lld/trunk/test/COFF/Inputs/start-lib1.ll (added)
+++ lld/trunk/test/COFF/Inputs/start-lib1.ll Fri Aug 30 09:50:10 2019
@@ -0,0 +1,13 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+declare i32 @bar()
+
+define i32 @foo() {
+  %1 = call i32 () @bar()
+  %2 = add i32 %1, 1
+  ret i32 %2
+}
+
+!llvm.linker.options = !{!0}
+!0 = !{!"/INCLUDE:foo"}

Added: lld/trunk/test/COFF/Inputs/start-lib2.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/start-lib2.ll?rev=370487&view=auto
==============================================================================
--- lld/trunk/test/COFF/Inputs/start-lib2.ll (added)
+++ lld/trunk/test/COFF/Inputs/start-lib2.ll Fri Aug 30 09:50:10 2019
@@ -0,0 +1,9 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define i32 @bar() {
+  ret i32 1
+}
+
+!llvm.linker.options = !{!0}
+!0 = !{!"/INCLUDE:bar"}

Added: lld/trunk/test/COFF/start-lib-cmd-diagnostics.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/start-lib-cmd-diagnostics.ll?rev=370487&view=auto
==============================================================================
--- lld/trunk/test/COFF/start-lib-cmd-diagnostics.ll (added)
+++ lld/trunk/test/COFF/start-lib-cmd-diagnostics.ll Fri Aug 30 09:50:10 2019
@@ -0,0 +1,19 @@
+; REQUIRES: x86
+;
+; We need an input file to lld, so create one.
+; RUN: llc -filetype=obj %s -o %t.obj
+
+; RUN: not lld-link %t.obj -end-lib 2>&1 \
+; RUN:     | FileCheck --check-prefix=STRAY_END %s
+; STRAY_END: stray -end-lib
+
+; RUN: not lld-link -start-lib -start-lib %t.obj 2>&1 \
+; RUN:     | FileCheck --check-prefix=NESTED_START %s
+; NESTED_START: nested -start-lib
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @main() {
+  ret void
+}

Added: lld/trunk/test/COFF/start-lib.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/start-lib.ll?rev=370487&view=auto
==============================================================================
--- lld/trunk/test/COFF/start-lib.ll (added)
+++ lld/trunk/test/COFF/start-lib.ll Fri Aug 30 09:50:10 2019
@@ -0,0 +1,43 @@
+; REQUIRES: x86
+;
+; RUN: llc -filetype=obj %s -o %t.obj
+; RUN: llc -filetype=obj %p/Inputs/start-lib1.ll -o %t1.obj
+; RUN: llc -filetype=obj %p/Inputs/start-lib2.ll -o %t2.obj
+; RUN: opt -thinlto-bc %s -o %t.bc
+; RUN: opt -thinlto-bc %p/Inputs/start-lib1.ll -o %t1.bc
+; RUN: opt -thinlto-bc %p/Inputs/start-lib2.ll -o %t2.bc
+;
+; RUN: lld-link -out:%t1.exe -entry:main -opt:noref -lldmap:%t1.map \
+; RUN:     %t.obj %t1.obj %t2.obj
+; RUN: FileCheck --check-prefix=TEST1 %s < %t1.map
+; RUN: lld-link -out:%t1.exe -entry:main -opt:noref -lldmap:%t1.thinlto.map \
+; RUN:     %t.bc %t1.bc %t2.bc
+; RUN: FileCheck --check-prefix=TEST1 %s < %t1.thinlto.map
+; TEST1: foo
+; TEST1: bar
+;
+; RUN: lld-link -out:%t2.exe -entry:main -opt:noref -lldmap:%t2.map \
+; RUN:     %t.obj -start-lib %t1.obj -end-lib %t2.obj
+; RUN: FileCheck --check-prefix=TEST2 %s < %t2.map
+; RUN: lld-link -out:%t2.exe -entry:main -opt:noref -lldmap:%t2.thinlto.map \
+; RUN:     %t.bc -start-lib %t1.bc -end-lib %t2.bc
+; RUN: FileCheck --check-prefix=TEST2 %s < %t2.thinlto.map
+; TEST2-NOT: Name: foo
+; TEST2: bar
+; TEST2-NOT: Name: foo
+;
+; RUN: lld-link -out:%t3.exe -entry:main -opt:noref -lldmap:%t3.map \
+; RUN:     %t.obj -start-lib %t1.obj %t2.obj
+; RUN: FileCheck --check-prefix=TEST3 %s < %t3.map
+; RUN: lld-link -out:%t3.exe -entry:main -opt:noref -lldmap:%t3.thinlto.map \
+; RUN:     %t.bc -start-lib %t1.bc %t2.bc
+; RUN: FileCheck --check-prefix=TEST3 %s < %t3.thinlto.map
+; TEST3-NOT: foo
+; TEST3-NOT: bar
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @main() {
+  ret void
+}




More information about the llvm-commits mailing list