Index: COFF/Driver.h =================================================================== --- COFF/Driver.h +++ COFF/Driver.h @@ -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 @@ private: ErrorOr parse(std::vector Argv); - std::vector tokenize(StringRef S); ErrorOr> @@ -66,13 +66,13 @@ bool link(llvm::ArrayRef Args); // Used by the resolver to parse .drectve section contents. - std::error_code - parseDirectives(StringRef S, std::vector> *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 openFile(StringRef Path); Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -85,8 +85,7 @@ // Parses .drectve section contents and returns a list of files // specified by /defaultlib. std::error_code -LinkerDriver::parseDirectives(StringRef S, - std::vector> *Res) { +LinkerDriver::parseDirectives(StringRef S) { auto ArgsOrErr = Parser.parse(S); if (auto EC = ArgsOrErr.getError()) return EC; @@ -103,8 +102,7 @@ ErrorOr MBOrErr = openFile(*Path); if (auto EC = MBOrErr.getError()) return EC; - std::unique_ptr File = createFile(MBOrErr.get()); - Res->push_back(std::move(File)); + Symtab.addFile(createFile(MBOrErr.get())); } break; case OPT_export: { @@ -458,9 +456,6 @@ 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 @@ // 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 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 @@ } 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; } Index: COFF/SymbolTable.h =================================================================== --- COFF/SymbolTable.h +++ COFF/SymbolTable.h @@ -34,7 +34,8 @@ class SymbolTable { public: SymbolTable(); - std::error_code addFile(std::unique_ptr File); + void addFile(std::unique_ptr File); + std::error_code run(); size_t getVersion() { return Version; } // Print an error message on undefined symbols. @@ -68,10 +69,10 @@ // The writer needs to handle DLL import libraries specially in // order to create the import descriptor table. - std::vector> ImportFiles; + std::vector ImportFiles; // The writer needs to infer the machine type from the object files. - std::vector> ObjectFiles; + std::vector ObjectFiles; // Creates an Undefined symbol for a given name. std::error_code addUndefined(StringRef Name); @@ -80,16 +81,16 @@ 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 createLTOObject(llvm::LTOCodeGenerator *CG); std::unordered_map Symtab; - std::vector> ArchiveFiles; - std::vector> BitcodeFiles; + std::vector> Files; + size_t FileIdx = 0; + std::vector ArchiveFiles; + std::vector BitcodeFiles; std::unique_ptr LTOMB; llvm::BumpPtrAllocator Alloc; Index: COFF/SymbolTable.cpp =================================================================== --- COFF/SymbolTable.cpp +++ COFF/SymbolTable.cpp @@ -27,43 +27,38 @@ resolve(new (Alloc) Undefined(Config->EntryName)); } -std::error_code SymbolTable::addFile(std::unique_ptr File) { - if (auto EC = File->parse()) - return EC; - InputFile *F = File.release(); - if (auto *P = dyn_cast(F)) { - ObjectFiles.emplace_back(P); - } else if (auto *P = dyn_cast(F)) { - ArchiveFiles.emplace_back(P); - } else if (auto *P = dyn_cast(F)) { - BitcodeFiles.emplace_back(P); - } else { - ImportFiles.emplace_back(cast(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 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> Libs; - if (auto EC = Driver->parseDirectives(S, &Libs)) - return EC; - for (std::unique_ptr &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(F)) { + ObjectFiles.push_back(P); + } else if (auto *P = dyn_cast(F)) { + ArchiveFiles.push_back(P); + } else if (auto *P = dyn_cast(F)) { + BitcodeFiles.push_back(P); + } else { + ImportFiles.push_back(cast(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 @@ 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 SymbolTable::getChunks() { std::vector Res; - for (std::unique_ptr &File : ObjectFiles) { + for (ObjectFile *File : ObjectFiles) { std::vector &V = File->getChunks(); Res.insert(Res.end(), V.begin(), V.end()); } @@ -164,9 +160,13 @@ std::error_code SymbolTable::resolveLazy(StringRef Name) { auto It = Symtab.find(Name); - if (It != Symtab.end()) - if (auto *B = dyn_cast(It->second->Body)) - return addMemberFile(B); + if (It == Symtab.end()) + return std::error_code(); + if (auto *B = dyn_cast(It->second->Body)) { + if (auto EC = addMemberFile(B)) + return EC; + return run(); + } return std::error_code(); } @@ -245,6 +245,10 @@ 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 @@ // 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(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(Sym->Body)) + addMemberFile(B); + } + + size_t End = BitcodeFiles.end(); + if (auto EC = run()) + return EC; + if (End != BitcodeFiles.end()) { + 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 @@ // as a regular COFF object file. ErrorOr SymbolTable::createLTOObject(LTOCodeGenerator *CG) { // All symbols referenced by non-bitcode objects must be preserved. - for (std::unique_ptr &File : ObjectFiles) + for (ObjectFile *File : ObjectFiles) for (SymbolBody *Body : File->getSymbols()) if (auto *S = dyn_cast(Body->getReplacement())) CG->addMustPreserveSymbol(S->getName()); // Likewise for bitcode symbols which we initially resolved to non-bitcode. - for (std::unique_ptr &File : BitcodeFiles) + for (BitcodeFile *File : BitcodeFiles) for (SymbolBody *Body : File->getSymbols()) if (isa(Body) && !isa(Body->getReplacement())) @@ -332,8 +335,9 @@ 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; Index: COFF/Writer.cpp =================================================================== --- COFF/Writer.cpp +++ COFF/Writer.cpp @@ -159,7 +159,7 @@ if (Symtab->ImportFiles.empty()) return; OutputSection *Text = createSection(".text"); - for (std::unique_ptr &File : Symtab->ImportFiles) { + for (ImportFile *File : Symtab->ImportFiles) { for (SymbolBody *B : File->getSymbols()) { auto *Import = dyn_cast(B); if (!Import) { @@ -234,10 +234,10 @@ } static MachineTypes -inferMachineType(std::vector> &ObjectFiles) { - for (std::unique_ptr &File : ObjectFiles) { +inferMachineType(const std::vector &Files) { + for (ObjectFile *F : Files) { // Try to infer machine type from the magic byte of the object file. - auto MT = static_cast(File->getCOFFObj()->getMachine()); + auto MT = static_cast(F->getCOFFObj()->getMachine()); if (MT != IMAGE_FILE_MACHINE_UNKNOWN) return MT; } Index: test/COFF/order.test =================================================================== --- /dev/null +++ test/COFF/order.test @@ -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