aboutsummaryrefslogtreecommitdiff
path: root/COFF/SymbolTable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'COFF/SymbolTable.cpp')
-rw-r--r--COFF/SymbolTable.cpp185
1 files changed, 136 insertions, 49 deletions
diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp
index b286d865caaf..1a9e0455dc1d 100644
--- a/COFF/SymbolTable.cpp
+++ b/COFF/SymbolTable.cpp
@@ -60,16 +60,16 @@ void SymbolTable::addFile(InputFile *File) {
}
static void errorOrWarn(const Twine &S) {
- if (Config->Force)
+ if (Config->ForceUnresolved)
warn(S);
else
error(S);
}
-// Returns the name of the symbol in SC whose value is <= Addr that is closest
-// to Addr. This is generally the name of the global variable or function whose
-// definition contains Addr.
-static StringRef getSymbolName(SectionChunk *SC, uint32_t Addr) {
+// Returns the symbol in SC whose value is <= Addr that is closest to Addr.
+// This is generally the global variable or function whose definition contains
+// Addr.
+static Symbol *getSymbol(SectionChunk *SC, uint32_t Addr) {
DefinedRegular *Candidate = nullptr;
for (Symbol *S : SC->File->getSymbols()) {
@@ -81,14 +81,12 @@ static StringRef getSymbolName(SectionChunk *SC, uint32_t Addr) {
Candidate = D;
}
- if (!Candidate)
- return "";
- return Candidate->getName();
+ return Candidate;
}
-static std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
+std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
struct Location {
- StringRef SymName;
+ Symbol *Sym;
std::pair<StringRef, uint32_t> FileLine;
};
std::vector<Location> Locations;
@@ -102,14 +100,14 @@ static std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
continue;
std::pair<StringRef, uint32_t> FileLine =
getFileLine(SC, R.VirtualAddress);
- StringRef SymName = getSymbolName(SC, R.VirtualAddress);
- if (!FileLine.first.empty() || !SymName.empty())
- Locations.push_back({SymName, FileLine});
+ Symbol *Sym = getSymbol(SC, R.VirtualAddress);
+ if (!FileLine.first.empty() || Sym)
+ Locations.push_back({Sym, FileLine});
}
}
if (Locations.empty())
- return "\n>>> referenced by " + toString(File) + "\n";
+ return "\n>>> referenced by " + toString(File);
std::string Out;
llvm::raw_string_ostream OS(Out);
@@ -119,13 +117,87 @@ static std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
OS << Loc.FileLine.first << ":" << Loc.FileLine.second
<< "\n>>> ";
OS << toString(File);
- if (!Loc.SymName.empty())
- OS << ":(" << Loc.SymName << ')';
+ if (Loc.Sym)
+ OS << ":(" << toString(*Loc.Sym) << ')';
}
- OS << '\n';
return OS.str();
}
+void SymbolTable::loadMinGWAutomaticImports() {
+ for (auto &I : SymMap) {
+ Symbol *Sym = I.second;
+ auto *Undef = dyn_cast<Undefined>(Sym);
+ if (!Undef)
+ continue;
+ if (!Sym->IsUsedInRegularObj)
+ continue;
+
+ StringRef Name = Undef->getName();
+
+ if (Name.startswith("__imp_"))
+ continue;
+ // If we have an undefined symbol, but we have a Lazy representing a
+ // symbol we could load from file, make sure to load that.
+ Lazy *L = dyn_cast_or_null<Lazy>(find(("__imp_" + Name).str()));
+ if (!L || L->PendingArchiveLoad)
+ continue;
+
+ log("Loading lazy " + L->getName() + " from " + L->File->getName() +
+ " for automatic import");
+ L->PendingArchiveLoad = true;
+ L->File->addMember(&L->Sym);
+ }
+}
+
+bool SymbolTable::handleMinGWAutomaticImport(Symbol *Sym, StringRef Name) {
+ if (Name.startswith("__imp_"))
+ return false;
+ Defined *Imp = dyn_cast_or_null<Defined>(find(("__imp_" + Name).str()));
+ if (!Imp)
+ return false;
+
+ // Replace the reference directly to a variable with a reference
+ // to the import address table instead. This obviously isn't right,
+ // but we mark the symbol as IsRuntimePseudoReloc, and a later pass
+ // will add runtime pseudo relocations for every relocation against
+ // this Symbol. The runtime pseudo relocation framework expects the
+ // reference itself to point at the IAT entry.
+ size_t ImpSize = 0;
+ if (isa<DefinedImportData>(Imp)) {
+ log("Automatically importing " + Name + " from " +
+ cast<DefinedImportData>(Imp)->getDLLName());
+ ImpSize = sizeof(DefinedImportData);
+ } else if (isa<DefinedRegular>(Imp)) {
+ log("Automatically importing " + Name + " from " +
+ toString(cast<DefinedRegular>(Imp)->File));
+ ImpSize = sizeof(DefinedRegular);
+ } else {
+ warn("unable to automatically import " + Name + " from " + Imp->getName() +
+ " from " + toString(cast<DefinedRegular>(Imp)->File) +
+ "; unexpected symbol type");
+ return false;
+ }
+ Sym->replaceKeepingName(Imp, ImpSize);
+ Sym->IsRuntimePseudoReloc = true;
+
+ // There may exist symbols named .refptr.<name> which only consist
+ // of a single pointer to <name>. If it turns out <name> is
+ // automatically imported, we don't need to keep the .refptr.<name>
+ // pointer at all, but redirect all accesses to it to the IAT entry
+ // for __imp_<name> instead, and drop the whole .refptr.<name> chunk.
+ DefinedRegular *Refptr =
+ dyn_cast_or_null<DefinedRegular>(find((".refptr." + Name).str()));
+ if (Refptr && Refptr->getChunk()->getSize() == Config->Wordsize) {
+ SectionChunk *SC = dyn_cast_or_null<SectionChunk>(Refptr->getChunk());
+ if (SC && SC->Relocs.size() == 1 && *SC->symbols().begin() == Sym) {
+ log("Replacing .refptr." + Name + " with " + Imp->getName());
+ Refptr->getChunk()->Live = false;
+ Refptr->replaceKeepingName(Imp, ImpSize);
+ }
+ }
+ return true;
+}
+
void SymbolTable::reportRemainingUndefines() {
SmallPtrSet<Symbol *, 8> Undefs;
DenseMap<Symbol *, Symbol *> LocalImports;
@@ -169,9 +241,17 @@ void SymbolTable::reportRemainingUndefines() {
}
}
+ // We don't want to report missing Microsoft precompiled headers symbols.
+ // A proper message will be emitted instead in PDBLinker::aquirePrecompObj
+ if (Name.contains("_PchSym_"))
+ continue;
+
+ if (Config->MinGW && handleMinGWAutomaticImport(Sym, Name))
+ continue;
+
// Remaining undefined symbols are not fatal if /force is specified.
// They are replaced with dummy defined symbols.
- if (Config->Force)
+ if (Config->ForceUnresolved)
replaceSymbol<DefinedAbsolute>(Sym, Name, 0);
Undefs.insert(Sym);
}
@@ -181,10 +261,10 @@ void SymbolTable::reportRemainingUndefines() {
for (Symbol *B : Config->GCRoot) {
if (Undefs.count(B))
- errorOrWarn("<root>: undefined symbol: " + B->getName());
+ errorOrWarn("<root>: undefined symbol: " + toString(*B));
if (Config->WarnLocallyDefinedImported)
if (Symbol *Imp = LocalImports.lookup(B))
- warn("<root>: locally defined symbol imported: " + Imp->getName() +
+ warn("<root>: locally defined symbol imported: " + toString(*Imp) +
" (defined in " + toString(Imp->getFile()) + ") [LNK4217]");
}
@@ -195,34 +275,41 @@ void SymbolTable::reportRemainingUndefines() {
if (!Sym)
continue;
if (Undefs.count(Sym))
- errorOrWarn("undefined symbol: " + Sym->getName() +
+ errorOrWarn("undefined symbol: " + toString(*Sym) +
getSymbolLocations(File, SymIndex));
if (Config->WarnLocallyDefinedImported)
if (Symbol *Imp = LocalImports.lookup(Sym))
- warn(toString(File) + ": locally defined symbol imported: " +
- Imp->getName() + " (defined in " + toString(Imp->getFile()) +
- ") [LNK4217]");
+ warn(toString(File) +
+ ": locally defined symbol imported: " + toString(*Imp) +
+ " (defined in " + toString(Imp->getFile()) + ") [LNK4217]");
}
}
}
std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
+ bool Inserted = false;
Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
- if (Sym)
- return {Sym, false};
- Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
- Sym->IsUsedInRegularObj = false;
- Sym->PendingArchiveLoad = false;
- return {Sym, true};
+ if (!Sym) {
+ Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
+ Sym->IsUsedInRegularObj = false;
+ Sym->PendingArchiveLoad = false;
+ Inserted = true;
+ }
+ return {Sym, Inserted};
+}
+
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, InputFile *File) {
+ std::pair<Symbol *, bool> Result = insert(Name);
+ if (!File || !isa<BitcodeFile>(File))
+ Result.first->IsUsedInRegularObj = true;
+ return Result;
}
Symbol *SymbolTable::addUndefined(StringRef Name, InputFile *F,
bool IsWeakAlias) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
- if (!F || !isa<BitcodeFile>(F))
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(Name, F);
if (WasInserted || (isa<Lazy>(S) && IsWeakAlias)) {
replaceSymbol<Undefined>(S, Name);
return S;
@@ -253,14 +340,20 @@ void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) {
}
void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
- error("duplicate symbol: " + toString(*Existing) + " in " +
- toString(Existing->getFile()) + " and in " + toString(NewFile));
+ std::string Msg = "duplicate symbol: " + toString(*Existing) + " in " +
+ toString(Existing->getFile()) + " and in " +
+ toString(NewFile);
+
+ if (Config->ForceMultiple)
+ warn(Msg);
+ else
+ error(Msg);
}
Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N);
+ std::tie(S, WasInserted) = insert(N, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
replaceSymbol<DefinedAbsolute>(S, N, Sym);
@@ -272,7 +365,7 @@ Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) {
Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N);
+ std::tie(S, WasInserted) = insert(N, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
replaceSymbol<DefinedAbsolute>(S, N, VA);
@@ -284,7 +377,7 @@ Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) {
Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N);
+ std::tie(S, WasInserted) = insert(N, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
replaceSymbol<DefinedSynthetic>(S, N, C);
@@ -298,9 +391,7 @@ Symbol *SymbolTable::addRegular(InputFile *F, StringRef N,
SectionChunk *C) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N);
- if (!isa<BitcodeFile>(F))
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(N, F);
if (WasInserted || !isa<DefinedRegular>(S))
replaceSymbol<DefinedRegular>(S, F, N, /*IsCOMDAT*/ false,
/*IsExternal*/ true, Sym, C);
@@ -314,9 +405,7 @@ SymbolTable::addComdat(InputFile *F, StringRef N,
const coff_symbol_generic *Sym) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N);
- if (!isa<BitcodeFile>(F))
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(N, F);
if (WasInserted || !isa<DefinedRegular>(S)) {
replaceSymbol<DefinedRegular>(S, F, N, /*IsCOMDAT*/ true,
/*IsExternal*/ true, Sym, nullptr);
@@ -331,9 +420,7 @@ 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(N);
- if (!isa<BitcodeFile>(F))
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(N, F);
if (WasInserted || !isa<DefinedCOFF>(S))
replaceSymbol<DefinedCommon>(S, F, N, Size, Sym, C);
else if (auto *DC = dyn_cast<DefinedCommon>(S))
@@ -345,7 +432,7 @@ Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size,
Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N);
+ std::tie(S, WasInserted) = insert(N, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {
replaceSymbol<DefinedImportData>(S, N, F);
@@ -360,7 +447,7 @@ Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID,
uint16_t Machine) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
+ std::tie(S, WasInserted) = insert(Name, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {
replaceSymbol<DefinedImportThunk>(S, Name, ID, Machine);