[lld] r240483 - COFF: Make link order compatible with MSVC link.exe.

Rui Ueyama ruiu at google.com
Tue Jun 23 16:56:39 PDT 2015


Author: ruiu
Date: Tue Jun 23 18:56:39 2015
New Revision: 240483

URL: http://llvm.org/viewvc/llvm-project?rev=240483&view=rev
Log:
COFF: Make link order compatible with MSVC link.exe.

Previously, we added files in directive sections to the symbol
table as we read the sections, so the link order was depth-first.
That's not compatible with MSVC link.exe nor the old LLD.

This patch is to queue files so that new files are added to the
end of the queue and processed last. Now addFile() doesn't parse
files nor resolve symbols. You need to call run() to process
queued files.

Added:
    lld/trunk/test/COFF/order.test
Modified:
    lld/trunk/COFF/Driver.cpp
    lld/trunk/COFF/Driver.h
    lld/trunk/COFF/SymbolTable.cpp
    lld/trunk/COFF/SymbolTable.h
    lld/trunk/COFF/Writer.cpp

Modified: lld/trunk/COFF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=240483&r1=240482&r2=240483&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.cpp (original)
+++ lld/trunk/COFF/Driver.cpp Tue Jun 23 18:56:39 2015
@@ -85,8 +85,7 @@ static std::unique_ptr<InputFile> create
 // Parses .drectve section contents and returns a list of files
 // specified by /defaultlib.
 std::error_code
-LinkerDriver::parseDirectives(StringRef S,
-                              std::vector<std::unique_ptr<InputFile>> *Res) {
+LinkerDriver::parseDirectives(StringRef S) {
   auto ArgsOrErr = Parser.parse(S);
   if (auto EC = ArgsOrErr.getError())
     return EC;
@@ -103,8 +102,7 @@ LinkerDriver::parseDirectives(StringRef
         ErrorOr<MemoryBufferRef> MBOrErr = openFile(*Path);
         if (auto EC = MBOrErr.getError())
           return EC;
-        std::unique_ptr<InputFile> File = createFile(MBOrErr.get());
-        Res->push_back(std::move(File));
+        Symtab.addFile(createFile(MBOrErr.get()));
       }
       break;
     case OPT_export: {
@@ -458,9 +456,6 @@ bool LinkerDriver::link(llvm::ArrayRef<c
     Inputs.push_back(MBOrErr.get());
   }
 
-  // Create a symbol table.
-  SymbolTable Symtab;
-
   // Windows specific -- Create a resource file containing a manifest file.
   if (Config->Manifest == Configuration::Embed) {
     auto MBOrErr = createManifestRes();
@@ -491,14 +486,11 @@ bool LinkerDriver::link(llvm::ArrayRef<c
 
   // Parse all input files and put all symbols to the symbol table.
   // The symbol table will take care of name resolution.
-  for (MemoryBufferRef MB : Inputs) {
-    std::unique_ptr<InputFile> File = createFile(MB);
-    if (Config->Verbose)
-      llvm::outs() << "Reading " << File->getName() << "\n";
-    if (auto EC = Symtab.addFile(std::move(File))) {
-      llvm::errs() << MB.getBufferIdentifier() << ": " << EC.message() << "\n";
-      return false;
-    }
+  for (MemoryBufferRef MB : Inputs)
+    Symtab.addFile(createFile(MB));
+  if (auto EC = Symtab.run()) {
+    llvm::errs() << EC.message() << "\n";
+    return false;
   }
 
   // Resolve auxiliary symbols until converge.
@@ -539,6 +531,12 @@ bool LinkerDriver::link(llvm::ArrayRef<c
       }
       Config->EntryName = EntryOrErr.get();
     }
+    Symtab.addUndefined(Config->EntryName);
+
+    if (auto EC = Symtab.run()) {
+      llvm::errs() << EC.message() << "\n";
+      return false;
+    }
     if (Ver == Symtab.getVersion())
       break;
   }

Modified: lld/trunk/COFF/Driver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.h?rev=240483&r1=240482&r2=240483&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.h (original)
+++ lld/trunk/COFF/Driver.h Tue Jun 23 18:56:39 2015
@@ -11,6 +11,7 @@
 #define LLD_COFF_DRIVER_H
 
 #include "Config.h"
+#include "SymbolTable.h"
 #include "lld/Core/LLVM.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/StringRef.h"
@@ -50,7 +51,6 @@ public:
 
 private:
   ErrorOr<llvm::opt::InputArgList> parse(std::vector<const char *> Argv);
-
   std::vector<const char *> tokenize(StringRef S);
 
   ErrorOr<std::vector<const char *>>
@@ -66,13 +66,13 @@ public:
   bool link(llvm::ArrayRef<const char *> Args);
 
   // Used by the resolver to parse .drectve section contents.
-  std::error_code
-  parseDirectives(StringRef S, std::vector<std::unique_ptr<InputFile>> *Res);
+  std::error_code parseDirectives(StringRef S);
 
 private:
   llvm::BumpPtrAllocator AllocAux;
   llvm::BumpPtrStringSaver Alloc;
   ArgParser Parser;
+  SymbolTable Symtab;
 
   // Opens a file. Path has to be resolved already.
   ErrorOr<MemoryBufferRef> openFile(StringRef Path);

Modified: lld/trunk/COFF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.cpp?rev=240483&r1=240482&r2=240483&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.cpp (original)
+++ lld/trunk/COFF/SymbolTable.cpp Tue Jun 23 18:56:39 2015
@@ -27,43 +27,38 @@ SymbolTable::SymbolTable() {
     resolve(new (Alloc) Undefined(Config->EntryName));
 }
 
-std::error_code SymbolTable::addFile(std::unique_ptr<InputFile> File) {
-  if (auto EC = File->parse())
-    return EC;
-  InputFile *F = File.release();
-  if (auto *P = dyn_cast<ObjectFile>(F)) {
-    ObjectFiles.emplace_back(P);
-  } else if (auto *P = dyn_cast<ArchiveFile>(F)) {
-    ArchiveFiles.emplace_back(P);
-  } else if (auto *P = dyn_cast<BitcodeFile>(F)) {
-    BitcodeFiles.emplace_back(P);
-  } else {
-    ImportFiles.emplace_back(cast<ImportFile>(F));
-  }
-
-  for (SymbolBody *B : F->getSymbols())
-    if (B->isExternal())
-      if (auto EC = resolve(B))
-        return EC;
-
-  // If a object file contains .drectve section,
-  // read that and add files listed there.
-  return addDirectives(F);
+void SymbolTable::addFile(std::unique_ptr<InputFile> File) {
+  Files.push_back(std::move(File));
 }
 
-std::error_code SymbolTable::addDirectives(InputFile *File) {
-  StringRef S = File->getDirectives();
-  if (S.empty())
-    return std::error_code();
-  std::vector<std::unique_ptr<InputFile>> Libs;
-  if (auto EC = Driver->parseDirectives(S, &Libs))
-    return EC;
-  for (std::unique_ptr<InputFile> &Lib : Libs) {
-    if (Config->Verbose) {
-      llvm::outs() << "Reading " << Lib->getName()
-                   << " for " << File->getName() << "\n";
+std::error_code SymbolTable::run() {
+  while (FileIdx < Files.size()) {
+    InputFile *F = Files[FileIdx++].get();
+    if (Config->Verbose)
+      llvm::outs() << "Reading " << F->getShortName() << "\n";
+    if (auto EC = F->parse())
+      return EC;
+    if (auto *P = dyn_cast<ObjectFile>(F)) {
+      ObjectFiles.push_back(P);
+    } else if (auto *P = dyn_cast<ArchiveFile>(F)) {
+      ArchiveFiles.push_back(P);
+    } else if (auto *P = dyn_cast<BitcodeFile>(F)) {
+      BitcodeFiles.push_back(P);
+    } else {
+      ImportFiles.push_back(cast<ImportFile>(F));
     }
-    addFile(std::move(Lib));
+
+    for (SymbolBody *B : F->getSymbols())
+      if (B->isExternal())
+        if (auto EC = resolve(B))
+          return EC;
+
+    // If a object file contains .drectve section,
+    // read that and add files listed there.
+    StringRef S = F->getDirectives();
+    if (!S.empty())
+      if (auto EC = Driver->parseDirectives(S))
+        return EC;
   }
   return std::error_code();
 }
@@ -141,12 +136,13 @@ std::error_code SymbolTable::addMemberFi
   if (Config->Verbose)
     llvm::outs() << "Loaded " << File->getShortName() << " for "
                  << Body->getName() << "\n";
-  return addFile(std::move(File));
+  addFile(std::move(File));
+  return std::error_code();
 }
 
 std::vector<Chunk *> SymbolTable::getChunks() {
   std::vector<Chunk *> Res;
-  for (std::unique_ptr<ObjectFile> &File : ObjectFiles) {
+  for (ObjectFile *File : ObjectFiles) {
     std::vector<Chunk *> &V = File->getChunks();
     Res.insert(Res.end(), V.begin(), V.end());
   }
@@ -164,9 +160,13 @@ Defined *SymbolTable::find(StringRef Nam
 
 std::error_code SymbolTable::resolveLazy(StringRef Name) {
   auto It = Symtab.find(Name);
-  if (It != Symtab.end())
-    if (auto *B = dyn_cast<Lazy>(It->second->Body))
-      return addMemberFile(B);
+  if (It == Symtab.end())
+    return std::error_code();
+  if (auto *B = dyn_cast<Lazy>(It->second->Body)) {
+    if (auto EC = addMemberFile(B))
+      return EC;
+    return run();
+  }
   return std::error_code();
 }
 
@@ -245,6 +245,10 @@ std::error_code SymbolTable::addCombined
     return EC;
   ObjectFile *Obj = FileOrErr.get();
 
+  // Skip the combined object file as the file is processed below
+  // rather than by run().
+  ++FileIdx;
+
   for (SymbolBody *Body : Obj->getSymbols()) {
     if (!Body->isExternal())
       continue;
@@ -282,17 +286,16 @@ std::error_code SymbolTable::addCombined
 
     // We may see new references to runtime library symbols such as __chkstk
     // here. These symbols must be wholly defined in non-bitcode files.
-    if (auto *B = dyn_cast<Lazy>(Sym->Body)) {
-      size_t NumBitcodeFiles = BitcodeFiles.size();
-      if (auto EC = addMemberFile(B))
-        return EC;
-      if (BitcodeFiles.size() != NumBitcodeFiles) {
-        llvm::errs()
-            << "LTO: late loaded symbol created new bitcode reference: " << Name
-            << "\n";
-        return make_error_code(LLDError::BrokenFile);
-      }
-    }
+    if (auto *B = dyn_cast<Lazy>(Sym->Body))
+      addMemberFile(B);
+  }
+
+  size_t NumBitcodeFiles = BitcodeFiles.size();
+  if (auto EC = run())
+    return EC;
+  if (BitcodeFiles.size() != NumBitcodeFiles) {
+    llvm::errs() << "LTO: late loaded symbol created new bitcode reference\n";
+    return make_error_code(LLDError::BrokenFile);
   }
 
   // New runtime library symbol references may have created undefined references.
@@ -305,13 +308,13 @@ std::error_code SymbolTable::addCombined
 // as a regular COFF object file.
 ErrorOr<ObjectFile *> SymbolTable::createLTOObject(LTOCodeGenerator *CG) {
   // All symbols referenced by non-bitcode objects must be preserved.
-  for (std::unique_ptr<ObjectFile> &File : ObjectFiles)
+  for (ObjectFile *File : ObjectFiles)
     for (SymbolBody *Body : File->getSymbols())
       if (auto *S = dyn_cast<DefinedBitcode>(Body->getReplacement()))
         CG->addMustPreserveSymbol(S->getName());
 
   // Likewise for bitcode symbols which we initially resolved to non-bitcode.
-  for (std::unique_ptr<BitcodeFile> &File : BitcodeFiles)
+  for (BitcodeFile *File : BitcodeFiles)
     for (SymbolBody *Body : File->getSymbols())
       if (isa<DefinedBitcode>(Body) &&
           !isa<DefinedBitcode>(Body->getReplacement()))
@@ -332,8 +335,9 @@ ErrorOr<ObjectFile *> SymbolTable::creat
     llvm::errs() << ErrMsg << '\n';
     return make_error_code(LLDError::BrokenFile);
   }
-  auto Obj = new ObjectFile(LTOMB->getMemBufferRef());
-  ObjectFiles.emplace_back(Obj);
+  auto *Obj = new ObjectFile(LTOMB->getMemBufferRef());
+  Files.emplace_back(Obj);
+  ObjectFiles.push_back(Obj);
   if (auto EC = Obj->parse())
     return EC;
   return Obj;

Modified: lld/trunk/COFF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.h?rev=240483&r1=240482&r2=240483&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.h (original)
+++ lld/trunk/COFF/SymbolTable.h Tue Jun 23 18:56:39 2015
@@ -34,7 +34,8 @@ namespace coff {
 class SymbolTable {
 public:
   SymbolTable();
-  std::error_code addFile(std::unique_ptr<InputFile> File);
+  void addFile(std::unique_ptr<InputFile> File);
+  std::error_code run();
   size_t getVersion() { return Version; }
 
   // Print an error message on undefined symbols.
@@ -68,10 +69,10 @@ public:
 
   // The writer needs to handle DLL import libraries specially in
   // order to create the import descriptor table.
-  std::vector<std::unique_ptr<ImportFile>> ImportFiles;
+  std::vector<ImportFile *> ImportFiles;
 
   // The writer needs to infer the machine type from the object files.
-  std::vector<std::unique_ptr<ObjectFile>> ObjectFiles;
+  std::vector<ObjectFile *> ObjectFiles;
 
   // Creates an Undefined symbol for a given name.
   std::error_code addUndefined(StringRef Name);
@@ -80,16 +81,16 @@ public:
   std::error_code rename(StringRef From, StringRef To);
 
 private:
-  std::error_code addDirectives(InputFile *File);
-
   std::error_code resolve(SymbolBody *Body);
   std::error_code resolveLazy(StringRef Name);
   std::error_code addMemberFile(Lazy *Body);
   ErrorOr<ObjectFile *> createLTOObject(llvm::LTOCodeGenerator *CG);
 
   std::unordered_map<StringRef, Symbol *> Symtab;
-  std::vector<std::unique_ptr<ArchiveFile>> ArchiveFiles;
-  std::vector<std::unique_ptr<BitcodeFile>> BitcodeFiles;
+  std::vector<std::unique_ptr<InputFile>> Files;
+  size_t FileIdx = 0;
+  std::vector<ArchiveFile *> ArchiveFiles;
+  std::vector<BitcodeFile *> BitcodeFiles;
   std::unique_ptr<MemoryBuffer> LTOMB;
   llvm::BumpPtrAllocator Alloc;
 

Modified: lld/trunk/COFF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=240483&r1=240482&r2=240483&view=diff
==============================================================================
--- lld/trunk/COFF/Writer.cpp (original)
+++ lld/trunk/COFF/Writer.cpp Tue Jun 23 18:56:39 2015
@@ -159,7 +159,7 @@ void Writer::createImportTables() {
   if (Symtab->ImportFiles.empty())
     return;
   OutputSection *Text = createSection(".text");
-  for (std::unique_ptr<ImportFile> &File : Symtab->ImportFiles) {
+  for (ImportFile *File : Symtab->ImportFiles) {
     for (SymbolBody *B : File->getSymbols()) {
       auto *Import = dyn_cast<DefinedImportData>(B);
       if (!Import) {
@@ -234,10 +234,10 @@ void Writer::assignAddresses() {
 }
 
 static MachineTypes
-inferMachineType(std::vector<std::unique_ptr<ObjectFile>> &ObjectFiles) {
-  for (std::unique_ptr<ObjectFile> &File : ObjectFiles) {
+inferMachineType(const std::vector<ObjectFile *> &Files) {
+  for (ObjectFile *F : Files) {
     // Try to infer machine type from the magic byte of the object file.
-    auto MT = static_cast<MachineTypes>(File->getCOFFObj()->getMachine());
+    auto MT = static_cast<MachineTypes>(F->getCOFFObj()->getMachine());
     if (MT != IMAGE_FILE_MACHINE_UNKNOWN)
       return MT;
   }

Added: lld/trunk/test/COFF/order.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/order.test?rev=240483&view=auto
==============================================================================
--- lld/trunk/test/COFF/order.test (added)
+++ lld/trunk/test/COFF/order.test Tue Jun 23 18:56:39 2015
@@ -0,0 +1,14 @@
+# RUN: yaml2obj < %p/Inputs/include1a.yaml > %t1.obj
+# RUN: yaml2obj < %p/Inputs/include1b.yaml > %t2.obj
+# RUN: yaml2obj < %p/Inputs/include1c.yaml > %t3.obj
+# RUN: rm -f %t2.lib %t3.lib
+# RUN: llvm-ar cru %t2.lib %t2.obj
+# RUN: llvm-ar cru %t3.lib %t3.obj
+# RUN: lld -flavor link2 /out:%t.exe %t1.obj %t2.lib %t3.obj %t3.lib /verbose >& %t.log
+# RUN: FileCheck %s < %t.log
+
+CHECK: order.test.tmp1.obj
+CHECK: order.test.tmp2.lib
+CHECK: order.test.tmp3.obj
+CHECK: order.test.tmp3.lib
+CHECK: order.test.tmp2.lib(order.test.tmp2.obj) for foo





More information about the llvm-commits mailing list