<div dir="ltr">I've reverted this change as it was causing ASan/MSan failures like the following: <a href="http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/34761/steps/check-lld%20asan/logs/stdio">http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/34761/steps/check-lld%20asan/logs/stdio</a></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Aug 30, 2019 at 9:48 AM Bob Haarman via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: inglorion<br>
Date: Fri Aug 30 09:50:10 2019<br>
New Revision: 370487<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=370487&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=370487&view=rev</a><br>
Log:<br>
[lld-link] implement -start-lib and -end-lib<br>
<br>
Summary:<br>
This implements -start-lib and -end-lib flags for lld-link, analogous<br>
to the similarly named options in ld.lld. Object files after<br>
-start-lib are included in the link only when needed to resolve<br>
undefined symbols. The -end-lib flag goes back to the normal behavior<br>
of always including object files in the link. This mimics the<br>
semantics of static libraries, but without needing to actually create<br>
the archive file.<br>
<br>
Reviewers: ruiu, smeenai, MaskRay<br>
<br>
Reviewed By: ruiu, MaskRay<br>
<br>
Subscribers: akhuang, llvm-commits<br>
<br>
Tags: #llvm<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D66848" rel="noreferrer" target="_blank">https://reviews.llvm.org/D66848</a><br>
<br>
Added:<br>
    lld/trunk/test/COFF/Inputs/start-lib1.ll<br>
    lld/trunk/test/COFF/Inputs/start-lib2.ll<br>
    lld/trunk/test/COFF/start-lib-cmd-diagnostics.ll<br>
    lld/trunk/test/COFF/start-lib.ll<br>
Modified:<br>
    lld/trunk/COFF/DebugTypes.cpp<br>
    lld/trunk/COFF/Driver.cpp<br>
    lld/trunk/COFF/Driver.h<br>
    lld/trunk/COFF/InputFiles.cpp<br>
    lld/trunk/COFF/InputFiles.h<br>
    lld/trunk/COFF/Options.td<br>
    lld/trunk/COFF/SymbolTable.cpp<br>
    lld/trunk/COFF/SymbolTable.h<br>
    lld/trunk/COFF/Symbols.cpp<br>
    lld/trunk/COFF/Symbols.h<br>
    lld/trunk/COFF/Writer.cpp<br>
<br>
Modified: lld/trunk/COFF/DebugTypes.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DebugTypes.cpp?rev=370487&r1=370486&r2=370487&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DebugTypes.cpp?rev=370487&r1=370486&r2=370487&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/COFF/DebugTypes.cpp (original)<br>
+++ lld/trunk/COFF/DebugTypes.cpp Fri Aug 30 09:50:10 2019<br>
@@ -231,7 +231,7 @@ void TypeServerSource::enqueue(const Obj<br>
   if (!it.second)<br>
     return; // another OBJ already scheduled this PDB for load<br>
<br>
-  driver->enqueuePath(*p, false);<br>
+  driver->enqueuePath(*p, false, false);<br>
 }<br>
<br>
 // Create an instance of TypeServerSource or an error string if the PDB couldn't<br>
<br>
Modified: lld/trunk/COFF/Driver.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=370487&r1=370486&r2=370487&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=370487&r1=370486&r2=370487&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/COFF/Driver.cpp (original)<br>
+++ lld/trunk/COFF/Driver.cpp Fri Aug 30 09:50:10 2019<br>
@@ -170,7 +170,7 @@ MemoryBufferRef LinkerDriver::takeBuffer<br>
 }<br>
<br>
 void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,<br>
-                             bool wholeArchive) {<br>
+                             bool wholeArchive, bool lazy) {<br>
   StringRef filename = mb->getBufferIdentifier();<br>
<br>
   MemoryBufferRef mbref = takeBuffer(std::move(mb));<br>
@@ -195,11 +195,17 @@ void LinkerDriver::addBuffer(std::unique<br>
     symtab->addFile(make<ArchiveFile>(mbref));<br>
     break;<br>
   case file_magic::bitcode:<br>
-    symtab->addFile(make<BitcodeFile>(mbref, "", 0));<br>
+    if (lazy)<br>
+      symtab->addFile(make<LazyObjFile>(mbref));<br>
+    else<br>
+      symtab->addFile(make<BitcodeFile>(mbref, "", 0));<br>
     break;<br>
   case file_magic::coff_object:<br>
   case file_magic::coff_import_library:<br>
-    symtab->addFile(make<ObjFile>(mbref));<br>
+    if (lazy)<br>
+      symtab->addFile(make<LazyObjFile>(mbref));<br>
+    else<br>
+      symtab->addFile(make<ObjFile>(mbref));<br>
     break;<br>
   case file_magic::pdb:<br>
     loadTypeServerSource(mbref);<br>
@@ -220,7 +226,7 @@ void LinkerDriver::addBuffer(std::unique<br>
   }<br>
 }<br>
<br>
-void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive) {<br>
+void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {<br>
   auto future =<br>
       std::make_shared<std::future<MBErrPair>>(createFutureForFile(path));<br>
   std::string pathStr = path;<br>
@@ -240,7 +246,7 @@ void LinkerDriver::enqueuePath(StringRef<br>
       else<br>
         error(msg + "; did you mean '" + nearest + "'");<br>
     } else<br>
-      driver->addBuffer(std::move(mbOrErr.first), wholeArchive);<br>
+      driver->addBuffer(std::move(mbOrErr.first), wholeArchive, lazy);<br>
   });<br>
 }<br>
<br>
@@ -359,7 +365,7 @@ void LinkerDriver::parseDirectives(Input<br>
       break;<br>
     case OPT_defaultlib:<br>
       if (Optional<StringRef> path = findLib(arg->getValue()))<br>
-        enqueuePath(*path, false);<br>
+        enqueuePath(*path, false, false);<br>
       break;<br>
     case OPT_entry:<br>
       config->entry = addUndefined(mangle(arg->getValue()));<br>
@@ -1553,19 +1559,45 @@ void LinkerDriver::link(ArrayRef<const c<br>
     return false;<br>
   };<br>
<br>
-  // Create a list of input files. Files can be given as arguments<br>
-  // for /defaultlib option.<br>
-  for (auto *arg : args.filtered(OPT_INPUT, OPT_wholearchive_file))<br>
-    if (Optional<StringRef> path = findFile(arg->getValue()))<br>
-      enqueuePath(*path, isWholeArchive(*path));<br>
+  // Create a list of input files. These can be given as OPT_INPUT options<br>
+  // and OPT_wholearchive_file options, and we also need to track OPT_start_lib<br>
+  // and OPT_end_lib.<br>
+  bool inLib = false;<br>
+  for (auto *arg : args) {<br>
+    switch (arg->getOption().getID()) {<br>
+    case OPT_end_lib:<br>
+      if (!inLib)<br>
+        error("stray " + arg->getSpelling());<br>
+      inLib = false;<br>
+      break;<br>
+    case OPT_start_lib:<br>
+      if (inLib)<br>
+        error("nested " + arg->getSpelling());<br>
+      inLib = true;<br>
+      break;<br>
+    case OPT_wholearchive_file:<br>
+      if (Optional<StringRef> path = findFile(arg->getValue()))<br>
+        enqueuePath(*path, true, inLib);<br>
+      break;<br>
+    case OPT_INPUT:<br>
+      if (Optional<StringRef> path = findFile(arg->getValue()))<br>
+        enqueuePath(*path, isWholeArchive(*path), inLib);<br>
+      break;<br>
+    default:<br>
+      // Ignore other options.<br>
+      break;<br>
+    }<br>
+  }<br>
<br>
+  // Process files specified as /defaultlib. These should be enequeued after<br>
+  // other files, which is why they are in a separate loop.<br>
   for (auto *arg : args.filtered(OPT_defaultlib))<br>
     if (Optional<StringRef> path = findLib(arg->getValue()))<br>
-      enqueuePath(*path, false);<br>
+      enqueuePath(*path, false, false);<br>
<br>
   // Windows specific -- Create a resource file containing a manifest file.<br>
   if (config->manifest == Configuration::Embed)<br>
-    addBuffer(createManifestRes(), false);<br>
+    addBuffer(createManifestRes(), false, false);<br>
<br>
   // Read all input files given via the command line.<br>
   run();<br>
@@ -1782,7 +1814,7 @@ void LinkerDriver::link(ArrayRef<const c<br>
   if (args.hasArg(OPT_include_optional)) {<br>
     // Handle /includeoptional<br>
     for (auto *arg : args.filtered(OPT_include_optional))<br>
-      if (dyn_cast_or_null<Lazy>(symtab->find(arg->getValue())))<br>
+      if (dyn_cast_or_null<LazyArchive>(symtab->find(arg->getValue())))<br>
         addUndefined(arg->getValue());<br>
     while (run());<br>
   }<br>
<br>
Modified: lld/trunk/COFF/Driver.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.h?rev=370487&r1=370486&r2=370487&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.h?rev=370487&r1=370486&r2=370487&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/COFF/Driver.h (original)<br>
+++ lld/trunk/COFF/Driver.h Fri Aug 30 09:50:10 2019<br>
@@ -77,7 +77,7 @@ public:<br>
<br>
   MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> mb);<br>
<br>
-  void enqueuePath(StringRef path, bool wholeArchive);<br>
+  void enqueuePath(StringRef path, bool wholeArchive, bool lazy);<br>
<br>
 private:<br>
   std::unique_ptr<llvm::TarWriter> tar; // for /linkrepro<br>
@@ -124,7 +124,8 @@ private:<br>
   StringRef findDefaultEntry();<br>
   WindowsSubsystem inferSubsystem();<br>
<br>
-  void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive);<br>
+  void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive,<br>
+                 bool lazy);<br>
   void addArchiveBuffer(MemoryBufferRef mbref, StringRef symName,<br>
                         StringRef parentName, uint64_t offsetInArchive);<br>
<br>
<br>
Modified: lld/trunk/COFF/InputFiles.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.cpp?rev=370487&r1=370486&r2=370487&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.cpp?rev=370487&r1=370486&r2=370487&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/COFF/InputFiles.cpp (original)<br>
+++ lld/trunk/COFF/InputFiles.cpp Fri Aug 30 09:50:10 2019<br>
@@ -73,6 +73,10 @@ static void checkAndSetWeakAlias(SymbolT<br>
   }<br>
 }<br>
<br>
+static bool ignoredSymbolName(StringRef name) {<br>
+  return name == "@feat.00" || name == "@<a href="http://comp.id" rel="noreferrer" target="_blank">comp.id</a>";<br>
+}<br>
+<br>
 ArchiveFile::ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {}<br>
<br>
 void ArchiveFile::parse() {<br>
@@ -81,7 +85,7 @@ void ArchiveFile::parse() {<br>
<br>
   // Read the symbol table to construct Lazy objects.<br>
   for (const Archive::Symbol &sym : file->symbols())<br>
-    symtab->addLazy(this, sym);<br>
+    symtab->addLazyArchive(this, sym);<br>
 }<br>
<br>
 // Returns a buffer pointing to a member file containing a given symbol.<br>
@@ -116,6 +120,49 @@ std::vector<MemoryBufferRef> getArchiveM<br>
   return v;<br>
 }<br>
<br>
+void LazyObjFile::fetch() {<br>
+  if (mb.getBuffer().empty())<br>
+    return;<br>
+<br>
+  InputFile *file;<br>
+  if (isBitcode(mb))<br>
+    file = make<BitcodeFile>(mb, "", 0, std::move(symbols));<br>
+  else<br>
+    file = make<ObjFile>(mb, std::move(symbols));<br>
+  mb = {};<br>
+  symtab->addFile(file);<br>
+}<br>
+<br>
+void LazyObjFile::parse() {<br>
+  if (isBitcode(this->mb)) {<br>
+    // Bitcode file.<br>
+    std::unique_ptr<lto::InputFile> obj =<br>
+        CHECK(lto::InputFile::create(this->mb), this);<br>
+    for (const lto::InputFile::Symbol &sym : obj->symbols()) {<br>
+      if (!sym.isUndefined())<br>
+        symtab->addLazyObject(this, sym.getName());<br>
+    }<br>
+    return;<br>
+  }<br>
+<br>
+  // Native object file.<br>
+  COFFObjectFile *coffObj =<br>
+      dyn_cast<COFFObjectFile>(CHECK(createBinary(mb), this).get());<br>
+  uint32_t numSymbols = coffObj->getNumberOfSymbols();<br>
+  for (uint32_t i = 0; i < numSymbols; ++i) {<br>
+    COFFSymbolRef coffSym = check(coffObj->getSymbol(i));<br>
+    if (coffSym.isUndefined() || !coffSym.isExternal() ||<br>
+        coffSym.isWeakExternal())<br>
+      continue;<br>
+    StringRef name;<br>
+    coffObj->getSymbolName(coffSym, name);<br>
+    if (coffSym.isAbsolute() && ignoredSymbolName(name))<br>
+      continue;<br>
+    symtab->addLazyObject(this, name);<br>
+    i += coffSym.getNumberOfAuxSymbols();<br>
+  }<br>
+}<br>
+<br>
 void ObjFile::parse() {<br>
   // Parse a memory buffer as a COFF file.<br>
   std::unique_ptr<Binary> bin = CHECK(createBinary(mb), this);<br>
@@ -526,13 +573,11 @@ Optional<Symbol *> ObjFile::createDefine<br>
   if (sym.isAbsolute()) {<br>
     StringRef name = getName();<br>
<br>
-    // Skip special symbols.<br>
-    if (name == "@<a href="http://comp.id" rel="noreferrer" target="_blank">comp.id</a>")<br>
-      return nullptr;<br>
-    if (name == "@feat.00") {<br>
+    if (name == "@feat.00")<br>
       feat00Flags = sym.getValue();<br>
+    // Skip special symbols.<br>
+    if (ignoredSymbolName(name))<br>
       return nullptr;<br>
-    }<br>
<br>
     if (sym.isExternal())<br>
       return symtab->addAbsolute(name, sym);<br>
@@ -782,8 +827,9 @@ void ImportFile::parse() {<br>
 }<br>
<br>
 BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,<br>
-                         uint64_t offsetInArchive)<br>
-    : InputFile(BitcodeKind, mb) {<br>
+                         uint64_t offsetInArchive,<br>
+                         std::vector<Symbol *> &&symbols)<br>
+    : InputFile(BitcodeKind, mb), symbols(std::move(symbols)) {<br>
   std::string path = mb.getBufferIdentifier().str();<br>
   if (config->thinLTOIndexOnly)<br>
     path = replaceThinLTOSuffix(mb.getBufferIdentifier());<br>
<br>
Modified: lld/trunk/COFF/InputFiles.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.h?rev=370487&r1=370486&r2=370487&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.h?rev=370487&r1=370486&r2=370487&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/COFF/InputFiles.h (original)<br>
+++ lld/trunk/COFF/InputFiles.h Fri Aug 30 09:50:10 2019<br>
@@ -14,6 +14,7 @@<br>
 #include "llvm/ADT/ArrayRef.h"<br>
 #include "llvm/ADT/DenseMap.h"<br>
 #include "llvm/ADT/DenseSet.h"<br>
+#include "llvm/BinaryFormat/Magic.h"<br>
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"<br>
 #include "llvm/LTO/LTO.h"<br>
 #include "llvm/Object/Archive.h"<br>
@@ -55,7 +56,13 @@ class TpiSource;<br>
 // The root class of input files.<br>
 class InputFile {<br>
 public:<br>
-  enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind };<br>
+  enum Kind {<br>
+    ArchiveKind,<br>
+    ObjectKind,<br>
+    LazyObjectKind,<br>
+    ImportKind,<br>
+    BitcodeKind<br>
+  };<br>
   Kind kind() const { return fileKind; }<br>
   virtual ~InputFile() {}<br>
<br>
@@ -102,10 +109,28 @@ private:<br>
   llvm::DenseSet<uint64_t> seen;<br>
 };<br>
<br>
+// .obj or .o file between -start-lib and -end-lib.<br>
+class LazyObjFile : public InputFile {<br>
+public:<br>
+  explicit LazyObjFile(MemoryBufferRef m) : InputFile(LazyObjectKind, m) {}<br>
+  static bool classof(const InputFile *f) {<br>
+    return f->kind() == LazyObjectKind;<br>
+  }<br>
+  // Makes this object file part of the link.<br>
+  void fetch();<br>
+  // Adds the symbols in this file to the symbol table as LazyObject symbols.<br>
+  void parse() override;<br>
+<br>
+private:<br>
+  std::vector<Symbol *> symbols;<br>
+};<br>
+<br>
 // .obj or .o file. This may be a member of an archive file.<br>
 class ObjFile : public InputFile {<br>
 public:<br>
   explicit ObjFile(MemoryBufferRef m) : InputFile(ObjectKind, m) {}<br>
+  explicit ObjFile(MemoryBufferRef m, std::vector<Symbol *> &&symbols)<br>
+      : InputFile(ObjectKind, m), symbols(std::move(symbols)) {}<br>
   static bool classof(const InputFile *f) { return f->kind() == ObjectKind; }<br>
   void parse() override;<br>
   MachineTypes getMachineType() override;<br>
@@ -301,7 +326,11 @@ public:<br>
 class BitcodeFile : public InputFile {<br>
 public:<br>
   BitcodeFile(MemoryBufferRef mb, StringRef archiveName,<br>
-              uint64_t offsetInArchive);<br>
+              uint64_t offsetInArchive)<br>
+      : BitcodeFile(mb, archiveName, offsetInArchive, {}) {}<br>
+  explicit BitcodeFile(MemoryBufferRef m, StringRef archiveName,<br>
+                       uint64_t offsetInArchive,<br>
+                       std::vector<Symbol *> &&symbols);<br>
   static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }<br>
   ArrayRef<Symbol *> getSymbols() { return symbols; }<br>
   MachineTypes getMachineType() override;<br>
@@ -314,6 +343,10 @@ private:<br>
   std::vector<Symbol *> symbols;<br>
 };<br>
<br>
+inline bool isBitcode(MemoryBufferRef mb) {<br>
+  return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode;<br>
+}<br>
+<br>
 std::string replaceThinLTOSuffix(StringRef path);<br>
 } // namespace coff<br>
<br>
<br>
Modified: lld/trunk/COFF/Options.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Options.td?rev=370487&r1=370486&r2=370487&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Options.td?rev=370487&r1=370486&r2=370487&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/COFF/Options.td (original)<br>
+++ lld/trunk/COFF/Options.td Fri Aug 30 09:50:10 2019<br>
@@ -162,6 +162,8 @@ def help : F<"help">;<br>
 def help_q : Flag<["/??", "-??", "/?", "-?"], "">, Alias<help>;<br>
<br>
 // LLD extensions<br>
+def end_lib : F<"end-lib">,<br>
+  HelpText<"End a grouping of objects that should be treated as if they were together in an archive">;<br>
 def exclude_all_symbols : F<"exclude-all-symbols">;<br>
 def export_all_symbols : F<"export-all-symbols">;<br>
 defm demangle : B<"demangle",<br>
@@ -176,6 +178,8 @@ def pdb_source_path : P<"pdbsourcepath",<br>
                         "Base path used to make relative source file path absolute in PDB">;<br>
 def rsp_quoting : Joined<["--"], "rsp-quoting=">,<br>
   HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">;<br>
+def start_lib : F<"start-lib">,<br>
+  HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;<br>
 def thinlto_emit_imports_files :<br>
     F<"thinlto-emit-imports-files">,<br>
     HelpText<"Emit .imports files with -thinlto-index-only">;<br>
<br>
Modified: lld/trunk/COFF/SymbolTable.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.cpp?rev=370487&r1=370486&r2=370487&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.cpp?rev=370487&r1=370486&r2=370487&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/COFF/SymbolTable.cpp (original)<br>
+++ lld/trunk/COFF/SymbolTable.cpp Fri Aug 30 09:50:10 2019<br>
@@ -61,6 +61,24 @@ static void errorOrWarn(const Twine &s)<br>
     error(s);<br>
 }<br>
<br>
+// Causes the file associated with a lazy symbol to be linked in.<br>
+static void forceLazy(Symbol *s) {<br>
+  s->pendingArchiveLoad = true;<br>
+  switch (s->kind()) {<br>
+  case Symbol::Kind::LazyArchiveKind: {<br>
+    auto *l = cast<LazyArchive>(s);<br>
+    l->file->addMember(l->sym);<br>
+    break;<br>
+  }<br>
+  case Symbol::Kind::LazyObjectKind:<br>
+    cast<LazyObject>(s)->file->fetch();<br>
+    break;<br>
+  default:<br>
+    llvm_unreachable(<br>
+        "symbol passed to forceLazy is not a LazyArchive or LazyObject");<br>
+  }<br>
+}<br>
+<br>
 // Returns the symbol in SC whose value is <= Addr that is closest to Addr.<br>
 // This is generally the global variable or function whose definition contains<br>
 // Addr.<br>
@@ -192,16 +210,15 @@ void SymbolTable::loadMinGWAutomaticImpo<br>
<br>
     if (name.startswith("__imp_"))<br>
       continue;<br>
-    // If we have an undefined symbol, but we have a Lazy representing a<br>
-    // symbol we could load from file, make sure to load that.<br>
-    Lazy *l = dyn_cast_or_null<Lazy>(find(("__imp_" + name).str()));<br>
-    if (!l || l->pendingArchiveLoad)<br>
+    // If we have an undefined symbol, but we have a lazy symbol we could<br>
+    // load, load it.<br>
+    Symbol *l = find(("__imp_" + name).str());<br>
+    if (!l || l->pendingArchiveLoad || !l->isLazy())<br>
       continue;<br>
<br>
-    log("Loading lazy " + l->getName() + " from " + l->file->getName() +<br>
+    log("Loading lazy " + l->getName() + " from " + l->getFile()->getName() +<br>
         " for automatic import");<br>
-    l->pendingArchiveLoad = true;<br>
-    l->file->addMember(l->sym);<br>
+    forceLazy(l);<br>
   }<br>
 }<br>
<br>
@@ -435,26 +452,22 @@ Symbol *SymbolTable::addUndefined(String<br>
   Symbol *s;<br>
   bool wasInserted;<br>
   std::tie(s, wasInserted) = insert(name, f);<br>
-  if (wasInserted || (isa<Lazy>(s) && isWeakAlias)) {<br>
+  if (wasInserted || (s->isLazy() && isWeakAlias)) {<br>
     replaceSymbol<Undefined>(s, name);<br>
     return s;<br>
   }<br>
-  if (auto *l = dyn_cast<Lazy>(s)) {<br>
-    if (!s->pendingArchiveLoad) {<br>
-      s->pendingArchiveLoad = true;<br>
-      l->file->addMember(l->sym);<br>
-    }<br>
-  }<br>
+  if (s->isLazy())<br>
+    forceLazy(s);<br>
   return s;<br>
 }<br>
<br>
-void SymbolTable::addLazy(ArchiveFile *f, const Archive::Symbol &sym) {<br>
+void SymbolTable::addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym) {<br>
   StringRef name = sym.getName();<br>
   Symbol *s;<br>
   bool wasInserted;<br>
   std::tie(s, wasInserted) = insert(name);<br>
   if (wasInserted) {<br>
-    replaceSymbol<Lazy>(s, f, sym);<br>
+    replaceSymbol<LazyArchive>(s, f, sym);<br>
     return;<br>
   }<br>
   auto *u = dyn_cast<Undefined>(s);<br>
@@ -464,6 +477,21 @@ void SymbolTable::addLazy(ArchiveFile *f<br>
   f->addMember(sym);<br>
 }<br>
<br>
+void SymbolTable::addLazyObject(LazyObjFile *f, StringRef n) {<br>
+  Symbol *s;<br>
+  bool wasInserted;<br>
+  std::tie(s, wasInserted) = insert(n, f);<br>
+  if (wasInserted) {<br>
+    replaceSymbol<LazyObject>(s, f, n);<br>
+    return;<br>
+  }<br>
+  auto *u = dyn_cast<Undefined>(s);<br>
+  if (!u || u->weakAlias || s->pendingArchiveLoad)<br>
+    return;<br>
+  s->pendingArchiveLoad = true;<br>
+  f->fetch();<br>
+}<br>
+<br>
 void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile) {<br>
   std::string msg = "duplicate symbol: " + toString(*existing) + " in " +<br>
                     toString(existing->getFile()) + " and in " +<br>
@@ -480,7 +508,7 @@ Symbol *SymbolTable::addAbsolute(StringR<br>
   bool wasInserted;<br>
   std::tie(s, wasInserted) = insert(n, nullptr);<br>
   s->isUsedInRegularObj = true;<br>
-  if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))<br>
+  if (wasInserted || isa<Undefined>(s) || s->isLazy())<br>
     replaceSymbol<DefinedAbsolute>(s, n, sym);<br>
   else if (!isa<DefinedCOFF>(s))<br>
     reportDuplicate(s, nullptr);<br>
@@ -492,7 +520,7 @@ Symbol *SymbolTable::addAbsolute(StringR<br>
   bool wasInserted;<br>
   std::tie(s, wasInserted) = insert(n, nullptr);<br>
   s->isUsedInRegularObj = true;<br>
-  if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))<br>
+  if (wasInserted || isa<Undefined>(s) || s->isLazy())<br>
     replaceSymbol<DefinedAbsolute>(s, n, va);<br>
   else if (!isa<DefinedCOFF>(s))<br>
     reportDuplicate(s, nullptr);<br>
@@ -504,7 +532,7 @@ Symbol *SymbolTable::addSynthetic(String<br>
   bool wasInserted;<br>
   std::tie(s, wasInserted) = insert(n, nullptr);<br>
   s->isUsedInRegularObj = true;<br>
-  if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))<br>
+  if (wasInserted || isa<Undefined>(s) || s->isLazy())<br>
     replaceSymbol<DefinedSynthetic>(s, n, c);<br>
   else if (!isa<DefinedCOFF>(s))<br>
     reportDuplicate(s, nullptr);<br>
@@ -560,7 +588,7 @@ Symbol *SymbolTable::addImportData(Strin<br>
   bool wasInserted;<br>
   std::tie(s, wasInserted) = insert(n, nullptr);<br>
   s->isUsedInRegularObj = true;<br>
-  if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) {<br>
+  if (wasInserted || isa<Undefined>(s) || s->isLazy()) {<br>
     replaceSymbol<DefinedImportData>(s, n, f);<br>
     return s;<br>
   }<br>
@@ -575,7 +603,7 @@ Symbol *SymbolTable::addImportThunk(Stri<br>
   bool wasInserted;<br>
   std::tie(s, wasInserted) = insert(name, nullptr);<br>
   s->isUsedInRegularObj = true;<br>
-  if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) {<br>
+  if (wasInserted || isa<Undefined>(s) || s->isLazy()) {<br>
     replaceSymbol<DefinedImportThunk>(s, name, id, machine);<br>
     return s;<br>
   }<br>
@@ -589,9 +617,12 @@ void SymbolTable::addLibcall(StringRef n<br>
   if (!sym)<br>
     return;<br>
<br>
-  if (Lazy *l = dyn_cast<Lazy>(sym)) {<br>
+  if (auto *l = dyn_cast<LazyArchive>(sym)) {<br>
     MemoryBufferRef mb = l->getMemberBuffer();<br>
-    if (identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode)<br>
+    if (isBitcode(mb))<br>
+      addUndefined(sym->getName());<br>
+  } else if (LazyObject *o = dyn_cast<LazyObject>(sym)) {<br>
+    if (isBitcode(o->file->mb))<br>
       addUndefined(sym->getName());<br>
   }<br>
 }<br>
<br>
Modified: lld/trunk/COFF/SymbolTable.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.h?rev=370487&r1=370486&r2=370487&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.h?rev=370487&r1=370486&r2=370487&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/COFF/SymbolTable.h (original)<br>
+++ lld/trunk/COFF/SymbolTable.h Fri Aug 30 09:50:10 2019<br>
@@ -29,7 +29,7 @@ class Defined;<br>
 class DefinedAbsolute;<br>
 class DefinedRegular;<br>
 class DefinedRelative;<br>
-class Lazy;<br>
+class LazyArchive;<br>
 class SectionChunk;<br>
 class Symbol;<br>
<br>
@@ -86,7 +86,8 @@ public:<br>
   Symbol *addAbsolute(StringRef n, uint64_t va);<br>
<br>
   Symbol *addUndefined(StringRef name, InputFile *f, bool isWeakAlias);<br>
-  void addLazy(ArchiveFile *f, const Archive::Symbol &sym);<br>
+  void addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym);<br>
+  void addLazyObject(LazyObjFile *f, StringRef n);<br>
   Symbol *addAbsolute(StringRef n, COFFSymbolRef s);<br>
   Symbol *addRegular(InputFile *f, StringRef n,<br>
                      const llvm::object::coff_symbol_generic *s = nullptr,<br>
<br>
Modified: lld/trunk/COFF/Symbols.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Symbols.cpp?rev=370487&r1=370486&r2=370487&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Symbols.cpp?rev=370487&r1=370486&r2=370487&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/COFF/Symbols.cpp (original)<br>
+++ lld/trunk/COFF/Symbols.cpp Fri Aug 30 09:50:10 2019<br>
@@ -61,7 +61,9 @@ StringRef Symbol::getName() {<br>
 InputFile *Symbol::getFile() {<br>
   if (auto *sym = dyn_cast<DefinedCOFF>(this))<br>
     return sym->file;<br>
-  if (auto *sym = dyn_cast<Lazy>(this))<br>
+  if (auto *sym = dyn_cast<LazyArchive>(this))<br>
+    return sym->file;<br>
+  if (auto *sym = dyn_cast<LazyObject>(this))<br>
     return sym->file;<br>
   return nullptr;<br>
 }<br>
@@ -119,7 +121,7 @@ Defined *Undefined::getWeakAlias() {<br>
   return nullptr;<br>
 }<br>
<br>
-MemoryBufferRef Lazy::getMemberBuffer() {<br>
+MemoryBufferRef LazyArchive::getMemberBuffer() {<br>
   Archive::Child c =<br>
     CHECK(sym.getMember(),<br>
           "could not get the member for symbol " + toCOFFString(sym));<br>
<br>
Modified: lld/trunk/COFF/Symbols.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Symbols.h?rev=370487&r1=370486&r2=370487&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Symbols.h?rev=370487&r1=370486&r2=370487&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/COFF/Symbols.h (original)<br>
+++ lld/trunk/COFF/Symbols.h Fri Aug 30 09:50:10 2019<br>
@@ -59,7 +59,8 @@ public:<br>
     DefinedSyntheticKind,<br>
<br>
     UndefinedKind,<br>
-    LazyKind,<br>
+    LazyArchiveKind,<br>
+    LazyObjectKind,<br>
<br>
     LastDefinedCOFFKind = DefinedCommonKind,<br>
     LastDefinedKind = DefinedSyntheticKind,<br>
@@ -79,6 +80,10 @@ public:<br>
   // after calling markLive.<br>
   bool isLive() const;<br>
<br>
+  bool isLazy() const {<br>
+    return symbolKind == LazyArchiveKind || symbolKind == LazyObjectKind;<br>
+  }<br>
+<br>
 protected:<br>
   friend SymbolTable;<br>
   explicit Symbol(Kind k, StringRef n = "")<br>
@@ -256,26 +261,29 @@ private:<br>
 // This class represents a symbol defined in an archive file. It is<br>
 // created from an archive file header, and it knows how to load an<br>
 // object file from an archive to replace itself with a defined<br>
-// symbol. If the resolver finds both Undefined and Lazy for<br>
-// the same name, it will ask the Lazy to load a file.<br>
-class Lazy : public Symbol {<br>
+// symbol. If the resolver finds both Undefined and LazyArchive for<br>
+// the same name, it will ask the LazyArchive to load a file.<br>
+class LazyArchive : public Symbol {<br>
 public:<br>
-  Lazy(ArchiveFile *f, const Archive::Symbol s)<br>
-      : Symbol(LazyKind, s.getName()), file(f), sym(s) {}<br>
+  LazyArchive(ArchiveFile *f, const Archive::Symbol s)<br>
+      : Symbol(LazyArchiveKind, s.getName()), file(f), sym(s) {}<br>
<br>
-  static bool classof(const Symbol *s) { return s->kind() == LazyKind; }<br>
+  static bool classof(const Symbol *s) { return s->kind() == LazyArchiveKind; }<br>
<br>
   MemoryBufferRef getMemberBuffer();<br>
<br>
   ArchiveFile *file;<br>
-<br>
-private:<br>
-  friend SymbolTable;<br>
-<br>
-private:<br>
   const Archive::Symbol sym;<br>
 };<br>
<br>
+class LazyObject : public Symbol {<br>
+public:<br>
+  LazyObject(LazyObjFile *f, StringRef n)<br>
+      : Symbol(LazyObjectKind, n), file(f) {}<br>
+  static bool classof(const Symbol *s) { return s->kind() == LazyObjectKind; }<br>
+  LazyObjFile *file;<br>
+};<br>
+<br>
 // Undefined symbols.<br>
 class Undefined : public Symbol {<br>
 public:<br>
@@ -381,7 +389,8 @@ inline uint64_t Defined::getRVA() {<br>
     return cast<DefinedCommon>(this)->getRVA();<br>
   case DefinedRegularKind:<br>
     return cast<DefinedRegular>(this)->getRVA();<br>
-  case LazyKind:<br>
+  case LazyArchiveKind:<br>
+  case LazyObjectKind:<br>
   case UndefinedKind:<br>
     llvm_unreachable("Cannot get the address for an undefined symbol.");<br>
   }<br>
@@ -404,7 +413,8 @@ inline Chunk *Defined::getChunk() {<br>
     return cast<DefinedLocalImport>(this)->getChunk();<br>
   case DefinedCommonKind:<br>
     return cast<DefinedCommon>(this)->getChunk();<br>
-  case LazyKind:<br>
+  case LazyArchiveKind:<br>
+  case LazyObjectKind:<br>
   case UndefinedKind:<br>
     llvm_unreachable("Cannot get the chunk of an undefined symbol.");<br>
   }<br>
@@ -419,11 +429,12 @@ union SymbolUnion {<br>
   alignas(DefinedCommon) char b[sizeof(DefinedCommon)];<br>
   alignas(DefinedAbsolute) char c[sizeof(DefinedAbsolute)];<br>
   alignas(DefinedSynthetic) char d[sizeof(DefinedSynthetic)];<br>
-  alignas(Lazy) char e[sizeof(Lazy)];<br>
+  alignas(LazyArchive) char e[sizeof(LazyArchive)];<br>
   alignas(Undefined) char f[sizeof(Undefined)];<br>
   alignas(DefinedImportData) char g[sizeof(DefinedImportData)];<br>
   alignas(DefinedImportThunk) char h[sizeof(DefinedImportThunk)];<br>
   alignas(DefinedLocalImport) char i[sizeof(DefinedLocalImport)];<br>
+  alignas(LazyObject) char j[sizeof(LazyObject)];<br>
 };<br>
<br>
 template <typename T, typename... ArgT><br>
<br>
Modified: lld/trunk/COFF/Writer.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=370487&r1=370486&r2=370487&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=370487&r1=370486&r2=370487&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/COFF/Writer.cpp (original)<br>
+++ lld/trunk/COFF/Writer.cpp Fri Aug 30 09:50:10 2019<br>
@@ -1519,7 +1519,8 @@ static void maybeAddAddressTakenFunction<br>
     // Absolute is never code, synthetic generally isn't and usually isn't<br>
     // determinable.<br>
     break;<br>
-  case Symbol::LazyKind:<br>
+  case Symbol::LazyArchiveKind:<br>
+  case Symbol::LazyObjectKind:<br>
   case Symbol::UndefinedKind:<br>
     // Undefined symbols resolve to zero, so they don't have an RVA. Lazy<br>
     // symbols shouldn't have relocations.<br>
<br>
Added: lld/trunk/test/COFF/Inputs/start-lib1.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/start-lib1.ll?rev=370487&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/start-lib1.ll?rev=370487&view=auto</a><br>
==============================================================================<br>
--- lld/trunk/test/COFF/Inputs/start-lib1.ll (added)<br>
+++ lld/trunk/test/COFF/Inputs/start-lib1.ll Fri Aug 30 09:50:10 2019<br>
@@ -0,0 +1,13 @@<br>
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"<br>
+target triple = "x86_64-pc-windows-msvc"<br>
+<br>
+declare i32 @bar()<br>
+<br>
+define i32 @foo() {<br>
+  %1 = call i32 () @bar()<br>
+  %2 = add i32 %1, 1<br>
+  ret i32 %2<br>
+}<br>
+<br>
+!llvm.linker.options = !{!0}<br>
+!0 = !{!"/INCLUDE:foo"}<br>
<br>
Added: lld/trunk/test/COFF/Inputs/start-lib2.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/start-lib2.ll?rev=370487&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/start-lib2.ll?rev=370487&view=auto</a><br>
==============================================================================<br>
--- lld/trunk/test/COFF/Inputs/start-lib2.ll (added)<br>
+++ lld/trunk/test/COFF/Inputs/start-lib2.ll Fri Aug 30 09:50:10 2019<br>
@@ -0,0 +1,9 @@<br>
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"<br>
+target triple = "x86_64-pc-windows-msvc"<br>
+<br>
+define i32 @bar() {<br>
+  ret i32 1<br>
+}<br>
+<br>
+!llvm.linker.options = !{!0}<br>
+!0 = !{!"/INCLUDE:bar"}<br>
<br>
Added: lld/trunk/test/COFF/start-lib-cmd-diagnostics.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/start-lib-cmd-diagnostics.ll?rev=370487&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/start-lib-cmd-diagnostics.ll?rev=370487&view=auto</a><br>
==============================================================================<br>
--- lld/trunk/test/COFF/start-lib-cmd-diagnostics.ll (added)<br>
+++ lld/trunk/test/COFF/start-lib-cmd-diagnostics.ll Fri Aug 30 09:50:10 2019<br>
@@ -0,0 +1,19 @@<br>
+; REQUIRES: x86<br>
+;<br>
+; We need an input file to lld, so create one.<br>
+; RUN: llc -filetype=obj %s -o %t.obj<br>
+<br>
+; RUN: not lld-link %t.obj -end-lib 2>&1 \<br>
+; RUN:     | FileCheck --check-prefix=STRAY_END %s<br>
+; STRAY_END: stray -end-lib<br>
+<br>
+; RUN: not lld-link -start-lib -start-lib %t.obj 2>&1 \<br>
+; RUN:     | FileCheck --check-prefix=NESTED_START %s<br>
+; NESTED_START: nested -start-lib<br>
+<br>
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"<br>
+target triple = "x86_64-pc-windows-msvc"<br>
+<br>
+define void @main() {<br>
+  ret void<br>
+}<br>
<br>
Added: lld/trunk/test/COFF/start-lib.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/start-lib.ll?rev=370487&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/start-lib.ll?rev=370487&view=auto</a><br>
==============================================================================<br>
--- lld/trunk/test/COFF/start-lib.ll (added)<br>
+++ lld/trunk/test/COFF/start-lib.ll Fri Aug 30 09:50:10 2019<br>
@@ -0,0 +1,43 @@<br>
+; REQUIRES: x86<br>
+;<br>
+; RUN: llc -filetype=obj %s -o %t.obj<br>
+; RUN: llc -filetype=obj %p/Inputs/start-lib1.ll -o %t1.obj<br>
+; RUN: llc -filetype=obj %p/Inputs/start-lib2.ll -o %t2.obj<br>
+; RUN: opt -thinlto-bc %s -o %t.bc<br>
+; RUN: opt -thinlto-bc %p/Inputs/start-lib1.ll -o %t1.bc<br>
+; RUN: opt -thinlto-bc %p/Inputs/start-lib2.ll -o %t2.bc<br>
+;<br>
+; RUN: lld-link -out:%t1.exe -entry:main -opt:noref -lldmap:%t1.map \<br>
+; RUN:     %t.obj %t1.obj %t2.obj<br>
+; RUN: FileCheck --check-prefix=TEST1 %s < %t1.map<br>
+; RUN: lld-link -out:%t1.exe -entry:main -opt:noref -lldmap:%t1.thinlto.map \<br>
+; RUN:     %t.bc %t1.bc %t2.bc<br>
+; RUN: FileCheck --check-prefix=TEST1 %s < %t1.thinlto.map<br>
+; TEST1: foo<br>
+; TEST1: bar<br>
+;<br>
+; RUN: lld-link -out:%t2.exe -entry:main -opt:noref -lldmap:%t2.map \<br>
+; RUN:     %t.obj -start-lib %t1.obj -end-lib %t2.obj<br>
+; RUN: FileCheck --check-prefix=TEST2 %s < %t2.map<br>
+; RUN: lld-link -out:%t2.exe -entry:main -opt:noref -lldmap:%t2.thinlto.map \<br>
+; RUN:     %t.bc -start-lib %t1.bc -end-lib %t2.bc<br>
+; RUN: FileCheck --check-prefix=TEST2 %s < %t2.thinlto.map<br>
+; TEST2-NOT: Name: foo<br>
+; TEST2: bar<br>
+; TEST2-NOT: Name: foo<br>
+;<br>
+; RUN: lld-link -out:%t3.exe -entry:main -opt:noref -lldmap:%t3.map \<br>
+; RUN:     %t.obj -start-lib %t1.obj %t2.obj<br>
+; RUN: FileCheck --check-prefix=TEST3 %s < %t3.map<br>
+; RUN: lld-link -out:%t3.exe -entry:main -opt:noref -lldmap:%t3.thinlto.map \<br>
+; RUN:     %t.bc -start-lib %t1.bc %t2.bc<br>
+; RUN: FileCheck --check-prefix=TEST3 %s < %t3.thinlto.map<br>
+; TEST3-NOT: foo<br>
+; TEST3-NOT: bar<br>
+<br>
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"<br>
+target triple = "x86_64-pc-windows-msvc"<br>
+<br>
+define void @main() {<br>
+  ret void<br>
+}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div>