aboutsummaryrefslogtreecommitdiff
path: root/COFF/SymbolTable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'COFF/SymbolTable.cpp')
-rw-r--r--COFF/SymbolTable.cpp173
1 files changed, 61 insertions, 112 deletions
diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp
index 9cc0b75c1510..310eab274526 100644
--- a/COFF/SymbolTable.cpp
+++ b/COFF/SymbolTable.cpp
@@ -11,10 +11,10 @@
#include "Config.h"
#include "Driver.h"
#include "Error.h"
+#include "LTO.h"
#include "Memory.h"
#include "Symbols.h"
#include "llvm/IR/LLVMContext.h"
-#include "llvm/LTO/legacy/LTOCodeGenerator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <utility>
@@ -24,11 +24,40 @@ using namespace llvm;
namespace lld {
namespace coff {
+enum SymbolPreference {
+ SP_EXISTING = -1,
+ SP_CONFLICT = 0,
+ SP_NEW = 1,
+};
+
+/// Checks if an existing symbol S should be kept or replaced by a new symbol.
+/// Returns SP_EXISTING when S should be kept, SP_NEW when the new symbol
+/// should be kept, and SP_CONFLICT if no valid resolution exists.
+static SymbolPreference compareDefined(Symbol *S, bool WasInserted,
+ bool NewIsCOMDAT) {
+ // If the symbol wasn't previously known, the new symbol wins by default.
+ if (WasInserted || !isa<Defined>(S->body()))
+ return SP_NEW;
+
+ // If the existing symbol is a DefinedRegular, both it and the new symbol
+ // must be comdats. In that case, we have no reason to prefer one symbol
+ // over the other, and we keep the existing one. If one of the symbols
+ // is not a comdat, we report a conflict.
+ if (auto *R = dyn_cast<DefinedRegular>(S->body())) {
+ if (NewIsCOMDAT && R->isCOMDAT())
+ return SP_EXISTING;
+ else
+ return SP_CONFLICT;
+ }
+
+ // Existing symbol is not a DefinedRegular; new symbol wins.
+ return SP_NEW;
+}
+
SymbolTable *Symtab;
void SymbolTable::addFile(InputFile *File) {
- if (Config->Verbose)
- outs() << "Reading " << toString(File) << "\n";
+ log("Reading " + toString(File));
File->parse();
MachineTypes MT = File->getMachineType();
@@ -51,8 +80,7 @@ void SymbolTable::addFile(InputFile *File) {
if (S.empty())
return;
- if (Config->Verbose)
- outs() << "Directives: " << toString(File) << ": " << S << "\n";
+ log("Directives: " + toString(File) + ": " + S);
Driver->parseDirectives(S);
}
@@ -106,12 +134,11 @@ void SymbolTable::reportRemainingUndefines() {
return;
for (SymbolBody *B : Config->GCRoot)
if (Undefs.count(B))
- errs() << "<root>: undefined symbol: " << B->getName() << "\n";
+ warn("<root>: undefined symbol: " + B->getName());
for (ObjectFile *File : ObjectFiles)
for (SymbolBody *Sym : File->getSymbols())
if (Undefs.count(Sym))
- errs() << toString(File) << ": undefined symbol: " << Sym->getName()
- << "\n";
+ warn(toString(File) + ": undefined symbol: " + Sym->getName());
if (!Config->Force)
fatal("link failed");
}
@@ -163,7 +190,7 @@ void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) {
}
void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
- fatal("duplicate symbol: " + toString(*Existing->body()) + " in " +
+ error("duplicate symbol: " + toString(*Existing->body()) + " in " +
toString(Existing->body()->getFile()) + " and in " +
(NewFile ? toString(NewFile) : "(internal)"));
}
@@ -204,59 +231,35 @@ Symbol *SymbolTable::addRelative(StringRef N, uint64_t VA) {
return S;
}
-Symbol *SymbolTable::addRegular(ObjectFile *F, COFFSymbolRef Sym,
+Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, bool IsCOMDAT,
+ const coff_symbol_generic *Sym,
SectionChunk *C) {
- StringRef Name;
- F->getCOFFObj()->getSymbolName(Sym, Name);
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
- S->IsUsedInRegularObj = true;
- if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body()))
- replaceBody<DefinedRegular>(S, F, Sym, C);
- else if (auto *R = dyn_cast<DefinedRegular>(S->body())) {
- if (!C->isCOMDAT() || !R->isCOMDAT())
- reportDuplicate(S, F);
- } else if (auto *B = dyn_cast<DefinedBitcode>(S->body())) {
- if (B->IsReplaceable)
- replaceBody<DefinedRegular>(S, F, Sym, C);
- else if (!C->isCOMDAT())
- reportDuplicate(S, F);
- } else
- replaceBody<DefinedRegular>(S, F, Sym, C);
- return S;
-}
-
-Symbol *SymbolTable::addBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N);
- if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body())) {
- replaceBody<DefinedBitcode>(S, F, N, IsReplaceable);
- return S;
+ if (!isa<BitcodeFile>(F))
+ S->IsUsedInRegularObj = true;
+ SymbolPreference SP = compareDefined(S, WasInserted, IsCOMDAT);
+ if (SP == SP_CONFLICT) {
+ reportDuplicate(S, F);
+ } else if (SP == SP_NEW) {
+ replaceBody<DefinedRegular>(S, F, N, IsCOMDAT, /*IsExternal*/ true, Sym, C);
}
- if (isa<DefinedCommon>(S->body()))
- return S;
- if (IsReplaceable)
- if (isa<DefinedRegular>(S->body()) || isa<DefinedBitcode>(S->body()))
- return S;
- reportDuplicate(S, F);
return S;
}
-Symbol *SymbolTable::addCommon(ObjectFile *F, COFFSymbolRef Sym,
- CommonChunk *C) {
- StringRef Name;
- F->getCOFFObj()->getSymbolName(Sym, Name);
+Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size,
+ const coff_symbol_generic *Sym, CommonChunk *C) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(N);
+ if (!isa<BitcodeFile>(F))
+ S->IsUsedInRegularObj = true;
if (WasInserted || !isa<DefinedCOFF>(S->body()))
- replaceBody<DefinedCommon>(S, F, Sym, C);
+ replaceBody<DefinedCommon>(S, F, N, Size, Sym, C);
else if (auto *DC = dyn_cast<DefinedCommon>(S->body()))
- if (Sym.getValue() > DC->getSize())
- replaceBody<DefinedCommon>(S, F, Sym, C);
+ if (Size > DC->getSize())
+ replaceBody<DefinedCommon>(S, F, N, Size, Sym, C);
return S;
}
@@ -345,75 +348,21 @@ SymbolBody *SymbolTable::addUndefined(StringRef Name) {
return addUndefined(Name, nullptr, false)->body();
}
-void SymbolTable::printMap(llvm::raw_ostream &OS) {
- for (ObjectFile *File : ObjectFiles) {
- OS << toString(File) << ":\n";
- for (SymbolBody *Body : File->getSymbols())
- if (auto *R = dyn_cast<DefinedRegular>(Body))
- if (R->getChunk()->isLive())
- OS << Twine::utohexstr(Config->ImageBase + R->getRVA())
- << " " << R->getName() << "\n";
- }
+std::vector<StringRef> SymbolTable::compileBitcodeFiles() {
+ LTO.reset(new BitcodeCompiler);
+ for (BitcodeFile *F : BitcodeFiles)
+ LTO->add(*F);
+ return LTO->compile();
}
void SymbolTable::addCombinedLTOObjects() {
if (BitcodeFiles.empty())
return;
-
- // Create an object file and add it to the symbol table by replacing any
- // DefinedBitcode symbols with the definitions in the object file.
- LTOCodeGenerator CG(BitcodeFile::Context);
- CG.setOptLevel(Config->LTOOptLevel);
- for (ObjectFile *Obj : createLTOObjects(&CG))
+ for (StringRef Object : compileBitcodeFiles()) {
+ auto *Obj = make<ObjectFile>(MemoryBufferRef(Object, "lto.tmp"));
Obj->parse();
-}
-
-// Combine and compile bitcode files and then return the result
-// as a vector of regular COFF object files.
-std::vector<ObjectFile *> SymbolTable::createLTOObjects(LTOCodeGenerator *CG) {
- // All symbols referenced by non-bitcode objects, including GC roots, must be
- // preserved. We must also replace bitcode symbols with undefined symbols so
- // that they may be replaced with real definitions without conflicting.
- for (BitcodeFile *File : BitcodeFiles)
- for (SymbolBody *Body : File->getSymbols()) {
- if (!isa<DefinedBitcode>(Body))
- continue;
- if (Body->symbol()->IsUsedInRegularObj)
- CG->addMustPreserveSymbol(Body->getName());
- replaceBody<Undefined>(Body->symbol(), Body->getName());
- }
-
- CG->setModule(BitcodeFiles[0]->takeModule());
- for (unsigned I = 1, E = BitcodeFiles.size(); I != E; ++I)
- CG->addModule(BitcodeFiles[I]->takeModule().get());
-
- bool DisableVerify = true;
-#ifdef NDEBUG
- DisableVerify = false;
-#endif
- if (!CG->optimize(DisableVerify, false, false, false))
- fatal(""); // optimize() should have emitted any error message.
-
- Objs.resize(Config->LTOJobs);
- // Use std::list to avoid invalidation of pointers in OSPtrs.
- std::list<raw_svector_ostream> OSs;
- std::vector<raw_pwrite_stream *> OSPtrs;
- for (SmallString<0> &Obj : Objs) {
- OSs.emplace_back(Obj);
- OSPtrs.push_back(&OSs.back());
+ ObjectFiles.push_back(Obj);
}
-
- if (!CG->compileOptimized(OSPtrs))
- fatal(""); // compileOptimized() should have emitted any error message.
-
- std::vector<ObjectFile *> ObjFiles;
- for (SmallString<0> &Obj : Objs) {
- auto *ObjFile = make<ObjectFile>(MemoryBufferRef(Obj, "<LTO object>"));
- ObjectFiles.push_back(ObjFile);
- ObjFiles.push_back(ObjFile);
- }
-
- return ObjFiles;
}
} // namespace coff