diff options
Diffstat (limited to 'COFF/SymbolTable.cpp')
-rw-r--r-- | COFF/SymbolTable.cpp | 185 |
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); |