mirror of
https://github.com/intel/llvm.git
synced 2026-01-31 07:27:33 +08:00
This is an initial patch for a section-based COFF linker. The patch has 2300 lines of code including comments and blank lines. Before diving into details, you want to start from reading README because it should give you an overview of the design. All important things are written in the README file, so I write summary here. - The linker is already able to self-link on Windows. - It's significantly faster than the existing implementation. The existing one takes 5 seconds to link LLD on my machine, while the new one only takes 1.2 seconds, even though the new one is not multi-threaded yet. (And a proof-of-concept multi- threaded version was able to link it in 0.5 seconds.) - It uses much less memory (250MB vs. 2GB virtual memory space to self-host). - IMHO the new code is much simpler and easier to read than the existing PE/COFF port. http://reviews.llvm.org/D10036 llvm-svn: 238458
176 lines
5.3 KiB
C++
176 lines
5.3 KiB
C++
//===- SymbolTable.cpp ----------------------------------------------------===//
|
|
//
|
|
// The LLVM Linker
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Config.h"
|
|
#include "Driver.h"
|
|
#include "SymbolTable.h"
|
|
#include "lld/Core/Error.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
namespace lld {
|
|
namespace coff {
|
|
|
|
SymbolTable::SymbolTable() {
|
|
addInitialSymbol(new DefinedAbsolute("__ImageBase", Config->ImageBase));
|
|
addInitialSymbol(new Undefined(Config->EntryName));
|
|
}
|
|
|
|
void SymbolTable::addInitialSymbol(SymbolBody *Body) {
|
|
OwnedSymbols.push_back(std::unique_ptr<SymbolBody>(Body));
|
|
Symtab[Body->getName()] = new (Alloc) Symbol(Body);
|
|
}
|
|
|
|
std::error_code SymbolTable::addFile(std::unique_ptr<InputFile> File) {
|
|
if (auto EC = File->parse())
|
|
return EC;
|
|
InputFile *FileP = File.release();
|
|
if (auto *P = dyn_cast<ObjectFile>(FileP))
|
|
return addObject(P);
|
|
if (auto *P = dyn_cast<ArchiveFile>(FileP))
|
|
return addArchive(P);
|
|
return addImport(cast<ImportFile>(FileP));
|
|
}
|
|
|
|
std::error_code SymbolTable::addObject(ObjectFile *File) {
|
|
ObjectFiles.emplace_back(File);
|
|
for (SymbolBody *Body : File->getSymbols())
|
|
if (Body->isExternal())
|
|
if (auto EC = resolve(Body))
|
|
return EC;
|
|
|
|
// If an object file contains .drectve section, read it and add
|
|
// files listed in the section.
|
|
StringRef Dir = File->getDirectives();
|
|
if (!Dir.empty()) {
|
|
std::vector<std::unique_ptr<InputFile>> Libs;
|
|
if (auto EC = parseDirectives(Dir, &Libs, &StringAlloc))
|
|
return EC;
|
|
for (std::unique_ptr<InputFile> &Lib : Libs)
|
|
addFile(std::move(Lib));
|
|
}
|
|
return std::error_code();
|
|
}
|
|
|
|
std::error_code SymbolTable::addArchive(ArchiveFile *File) {
|
|
ArchiveFiles.emplace_back(File);
|
|
for (SymbolBody *Body : File->getSymbols())
|
|
if (auto EC = resolve(Body))
|
|
return EC;
|
|
return std::error_code();
|
|
}
|
|
|
|
std::error_code SymbolTable::addImport(ImportFile *File) {
|
|
ImportFiles.emplace_back(File);
|
|
for (SymbolBody *Body : File->getSymbols())
|
|
if (auto EC = resolve(Body))
|
|
return EC;
|
|
return std::error_code();
|
|
}
|
|
|
|
bool SymbolTable::reportRemainingUndefines() {
|
|
bool Ret = false;
|
|
for (auto &I : Symtab) {
|
|
Symbol *Sym = I.second;
|
|
auto *Undef = dyn_cast<Undefined>(Sym->Body);
|
|
if (!Undef)
|
|
continue;
|
|
if (SymbolBody *Alias = Undef->getWeakAlias()) {
|
|
Sym->Body = Alias->getReplacement();
|
|
if (!isa<Defined>(Sym->Body)) {
|
|
// Aliases are yet another symbols pointed by other symbols
|
|
// that could also remain undefined.
|
|
llvm::errs() << "undefined symbol: " << Undef->getName() << "\n";
|
|
Ret = true;
|
|
}
|
|
continue;
|
|
}
|
|
llvm::errs() << "undefined symbol: " << Undef->getName() << "\n";
|
|
Ret = true;
|
|
}
|
|
return Ret;
|
|
}
|
|
|
|
// This function resolves conflicts if there's an existing symbol with
|
|
// the same name. Decisions are made based on symbol type.
|
|
std::error_code SymbolTable::resolve(SymbolBody *New) {
|
|
// Find an existing Symbol or create and insert a new one.
|
|
StringRef Name = New->getName();
|
|
Symbol *&Sym = Symtab[Name];
|
|
if (!Sym) {
|
|
Sym = new (Alloc) Symbol(New);
|
|
New->setBackref(Sym);
|
|
return std::error_code();
|
|
}
|
|
New->setBackref(Sym);
|
|
|
|
// compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
|
|
// equivalent (conflicting), or more preferable, respectively.
|
|
SymbolBody *Existing = Sym->Body;
|
|
int comp = Existing->compare(New);
|
|
if (comp < 0)
|
|
Sym->Body = New;
|
|
if (comp == 0)
|
|
return make_dynamic_error_code(Twine("duplicate symbol: ") + Name);
|
|
|
|
// If we have an Undefined symbol for a Lazy symbol, we need
|
|
// to read an archive member to replace the Lazy symbol with
|
|
// a Defined symbol.
|
|
if (isa<Undefined>(Existing) || isa<Undefined>(New))
|
|
if (auto *B = dyn_cast<Lazy>(Sym->Body))
|
|
return addMemberFile(B);
|
|
return std::error_code();
|
|
}
|
|
|
|
// Reads an archive member file pointed by a given symbol.
|
|
std::error_code SymbolTable::addMemberFile(Lazy *Body) {
|
|
auto FileOrErr = Body->getMember();
|
|
if (auto EC = FileOrErr.getError())
|
|
return EC;
|
|
std::unique_ptr<InputFile> File = std::move(FileOrErr.get());
|
|
|
|
// getMember returns an empty buffer if the member was already
|
|
// read from the library.
|
|
if (!File)
|
|
return std::error_code();
|
|
if (Config->Verbose)
|
|
llvm::dbgs() << "Loaded " << File->getShortName() << " for "
|
|
<< Body->getName() << "\n";
|
|
return addFile(std::move(File));
|
|
}
|
|
|
|
std::vector<Chunk *> SymbolTable::getChunks() {
|
|
std::vector<Chunk *> Res;
|
|
for (std::unique_ptr<ObjectFile> &File : ObjectFiles) {
|
|
std::vector<Chunk *> &V = File->getChunks();
|
|
Res.insert(Res.end(), V.begin(), V.end());
|
|
}
|
|
return Res;
|
|
}
|
|
|
|
SymbolBody *SymbolTable::find(StringRef Name) {
|
|
auto It = Symtab.find(Name);
|
|
if (It == Symtab.end())
|
|
return nullptr;
|
|
return It->second->Body;
|
|
}
|
|
|
|
void SymbolTable::dump() {
|
|
for (auto &P : Symtab) {
|
|
Symbol *Ref = P.second;
|
|
if (auto *Body = dyn_cast<Defined>(Ref->Body))
|
|
llvm::dbgs() << Twine::utohexstr(Config->ImageBase + Body->getRVA())
|
|
<< " " << Body->getName() << "\n";
|
|
}
|
|
}
|
|
|
|
} // namespace coff
|
|
} // namespace lld
|