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.

llvm-svn: 240483
This commit is contained in:
Rui Ueyama 2015-06-23 23:56:39 +00:00
parent 240fc1e0aa
commit 0d2e999050
6 changed files with 100 additions and 83 deletions

View File

@ -85,8 +85,7 @@ static std::unique_ptr<InputFile> createFile(MemoryBufferRef MB) {
// 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 S,
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<const char *> ArgsArr) {
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<const char *> ArgsArr) {
// 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<const char *> ArgsArr) {
}
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;
}

View File

@ -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);

View File

@ -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::addMemberFile(Lazy *Body) {
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 Name) {
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::addCombinedLTOObject() {
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::addCombinedLTOObject() {
// 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::addCombinedLTOObject() {
// 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::createLTOObject(LTOCodeGenerator *CG) {
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;

View File

@ -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;

View File

@ -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;
}

14
lld/test/COFF/order.test Normal file
View File

@ -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