Path: blob/main/contrib/llvm-project/lld/COFF/SymbolTable.cpp
34870 views
//===- SymbolTable.cpp ----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "SymbolTable.h"9#include "COFFLinkerContext.h"10#include "Config.h"11#include "Driver.h"12#include "LTO.h"13#include "PDB.h"14#include "Symbols.h"15#include "lld/Common/ErrorHandler.h"16#include "lld/Common/Memory.h"17#include "lld/Common/Timer.h"18#include "llvm/DebugInfo/DIContext.h"19#include "llvm/IR/LLVMContext.h"20#include "llvm/LTO/LTO.h"21#include "llvm/Support/Debug.h"22#include "llvm/Support/TimeProfiler.h"23#include "llvm/Support/raw_ostream.h"24#include <utility>2526using namespace llvm;2728namespace lld::coff {2930StringRef ltrim1(StringRef s, const char *chars) {31if (!s.empty() && strchr(chars, s[0]))32return s.substr(1);33return s;34}3536static bool compatibleMachineType(COFFLinkerContext &ctx, MachineTypes mt) {37if (mt == IMAGE_FILE_MACHINE_UNKNOWN)38return true;39switch (ctx.config.machine) {40case ARM64:41return mt == ARM64 || mt == ARM64X;42case ARM64EC:43return COFF::isArm64EC(mt) || mt == AMD64;44case ARM64X:45return COFF::isAnyArm64(mt) || mt == AMD64;46default:47return ctx.config.machine == mt;48}49}5051void SymbolTable::addFile(InputFile *file) {52log("Reading " + toString(file));53if (file->lazy) {54if (auto *f = dyn_cast<BitcodeFile>(file))55f->parseLazy();56else57cast<ObjFile>(file)->parseLazy();58} else {59file->parse();60if (auto *f = dyn_cast<ObjFile>(file)) {61ctx.objFileInstances.push_back(f);62} else if (auto *f = dyn_cast<BitcodeFile>(file)) {63if (ltoCompilationDone) {64error("LTO object file " + toString(file) + " linked in after "65"doing LTO compilation.");66}67ctx.bitcodeFileInstances.push_back(f);68} else if (auto *f = dyn_cast<ImportFile>(file)) {69ctx.importFileInstances.push_back(f);70}71}7273MachineTypes mt = file->getMachineType();74if (ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN) {75ctx.config.machine = mt;76ctx.driver.addWinSysRootLibSearchPaths();77} else if (!compatibleMachineType(ctx, mt)) {78error(toString(file) + ": machine type " + machineToStr(mt) +79" conflicts with " + machineToStr(ctx.config.machine));80return;81}8283ctx.driver.parseDirectives(file);84}8586static void errorOrWarn(const Twine &s, bool forceUnresolved) {87if (forceUnresolved)88warn(s);89else90error(s);91}9293// Causes the file associated with a lazy symbol to be linked in.94static void forceLazy(Symbol *s) {95s->pendingArchiveLoad = true;96switch (s->kind()) {97case Symbol::Kind::LazyArchiveKind: {98auto *l = cast<LazyArchive>(s);99l->file->addMember(l->sym);100break;101}102case Symbol::Kind::LazyObjectKind: {103InputFile *file = cast<LazyObject>(s)->file;104file->ctx.symtab.addFile(file);105break;106}107case Symbol::Kind::LazyDLLSymbolKind: {108auto *l = cast<LazyDLLSymbol>(s);109l->file->makeImport(l->sym);110break;111}112default:113llvm_unreachable(114"symbol passed to forceLazy is not a LazyArchive or LazyObject");115}116}117118// Returns the symbol in SC whose value is <= Addr that is closest to Addr.119// This is generally the global variable or function whose definition contains120// Addr.121static Symbol *getSymbol(SectionChunk *sc, uint32_t addr) {122DefinedRegular *candidate = nullptr;123124for (Symbol *s : sc->file->getSymbols()) {125auto *d = dyn_cast_or_null<DefinedRegular>(s);126if (!d || !d->data || d->file != sc->file || d->getChunk() != sc ||127d->getValue() > addr ||128(candidate && d->getValue() < candidate->getValue()))129continue;130131candidate = d;132}133134return candidate;135}136137static std::vector<std::string> getSymbolLocations(BitcodeFile *file) {138std::string res("\n>>> referenced by ");139StringRef source = file->obj->getSourceFileName();140if (!source.empty())141res += source.str() + "\n>>> ";142res += toString(file);143return {res};144}145146static std::optional<std::pair<StringRef, uint32_t>>147getFileLineDwarf(const SectionChunk *c, uint32_t addr) {148std::optional<DILineInfo> optionalLineInfo =149c->file->getDILineInfo(addr, c->getSectionNumber() - 1);150if (!optionalLineInfo)151return std::nullopt;152const DILineInfo &lineInfo = *optionalLineInfo;153if (lineInfo.FileName == DILineInfo::BadString)154return std::nullopt;155return std::make_pair(saver().save(lineInfo.FileName), lineInfo.Line);156}157158static std::optional<std::pair<StringRef, uint32_t>>159getFileLine(const SectionChunk *c, uint32_t addr) {160// MinGW can optionally use codeview, even if the default is dwarf.161std::optional<std::pair<StringRef, uint32_t>> fileLine =162getFileLineCodeView(c, addr);163// If codeview didn't yield any result, check dwarf in MinGW mode.164if (!fileLine && c->file->ctx.config.mingw)165fileLine = getFileLineDwarf(c, addr);166return fileLine;167}168169// Given a file and the index of a symbol in that file, returns a description170// of all references to that symbol from that file. If no debug information is171// available, returns just the name of the file, else one string per actual172// reference as described in the debug info.173// Returns up to maxStrings string descriptions, along with the total number of174// locations found.175static std::pair<std::vector<std::string>, size_t>176getSymbolLocations(ObjFile *file, uint32_t symIndex, size_t maxStrings) {177struct Location {178Symbol *sym;179std::pair<StringRef, uint32_t> fileLine;180};181std::vector<Location> locations;182size_t numLocations = 0;183184for (Chunk *c : file->getChunks()) {185auto *sc = dyn_cast<SectionChunk>(c);186if (!sc)187continue;188for (const coff_relocation &r : sc->getRelocs()) {189if (r.SymbolTableIndex != symIndex)190continue;191numLocations++;192if (locations.size() >= maxStrings)193continue;194195std::optional<std::pair<StringRef, uint32_t>> fileLine =196getFileLine(sc, r.VirtualAddress);197Symbol *sym = getSymbol(sc, r.VirtualAddress);198if (fileLine)199locations.push_back({sym, *fileLine});200else if (sym)201locations.push_back({sym, {"", 0}});202}203}204205if (maxStrings == 0)206return std::make_pair(std::vector<std::string>(), numLocations);207208if (numLocations == 0)209return std::make_pair(210std::vector<std::string>{"\n>>> referenced by " + toString(file)}, 1);211212std::vector<std::string> symbolLocations(locations.size());213size_t i = 0;214for (Location loc : locations) {215llvm::raw_string_ostream os(symbolLocations[i++]);216os << "\n>>> referenced by ";217if (!loc.fileLine.first.empty())218os << loc.fileLine.first << ":" << loc.fileLine.second219<< "\n>>> ";220os << toString(file);221if (loc.sym)222os << ":(" << toString(file->ctx, *loc.sym) << ')';223}224return std::make_pair(symbolLocations, numLocations);225}226227std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {228return getSymbolLocations(file, symIndex, SIZE_MAX).first;229}230231static std::pair<std::vector<std::string>, size_t>232getSymbolLocations(InputFile *file, uint32_t symIndex, size_t maxStrings) {233if (auto *o = dyn_cast<ObjFile>(file))234return getSymbolLocations(o, symIndex, maxStrings);235if (auto *b = dyn_cast<BitcodeFile>(file)) {236std::vector<std::string> symbolLocations = getSymbolLocations(b);237size_t numLocations = symbolLocations.size();238if (symbolLocations.size() > maxStrings)239symbolLocations.resize(maxStrings);240return std::make_pair(symbolLocations, numLocations);241}242llvm_unreachable("unsupported file type passed to getSymbolLocations");243return std::make_pair(std::vector<std::string>(), (size_t)0);244}245246// For an undefined symbol, stores all files referencing it and the index of247// the undefined symbol in each file.248struct UndefinedDiag {249Symbol *sym;250struct File {251InputFile *file;252uint32_t symIndex;253};254std::vector<File> files;255};256257static void reportUndefinedSymbol(const COFFLinkerContext &ctx,258const UndefinedDiag &undefDiag) {259std::string out;260llvm::raw_string_ostream os(out);261os << "undefined symbol: " << toString(ctx, *undefDiag.sym);262263const size_t maxUndefReferences = 3;264size_t numDisplayedRefs = 0, numRefs = 0;265for (const UndefinedDiag::File &ref : undefDiag.files) {266auto [symbolLocations, totalLocations] = getSymbolLocations(267ref.file, ref.symIndex, maxUndefReferences - numDisplayedRefs);268269numRefs += totalLocations;270numDisplayedRefs += symbolLocations.size();271for (const std::string &s : symbolLocations) {272os << s;273}274}275if (numDisplayedRefs < numRefs)276os << "\n>>> referenced " << numRefs - numDisplayedRefs << " more times";277errorOrWarn(os.str(), ctx.config.forceUnresolved);278}279280void SymbolTable::loadMinGWSymbols() {281for (auto &i : symMap) {282Symbol *sym = i.second;283auto *undef = dyn_cast<Undefined>(sym);284if (!undef)285continue;286if (undef->getWeakAlias())287continue;288289StringRef name = undef->getName();290291if (ctx.config.machine == I386 && ctx.config.stdcallFixup) {292// Check if we can resolve an undefined decorated symbol by finding293// the intended target as an undecorated symbol (only with a leading294// underscore).295StringRef origName = name;296StringRef baseName = name;297// Trim down stdcall/fastcall/vectorcall symbols to the base name.298baseName = ltrim1(baseName, "_@");299baseName = baseName.substr(0, baseName.find('@'));300// Add a leading underscore, as it would be in cdecl form.301std::string newName = ("_" + baseName).str();302Symbol *l;303if (newName != origName && (l = find(newName)) != nullptr) {304// If we found a symbol and it is lazy; load it.305if (l->isLazy() && !l->pendingArchiveLoad) {306log("Loading lazy " + l->getName() + " from " +307l->getFile()->getName() + " for stdcall fixup");308forceLazy(l);309}310// If it's lazy or already defined, hook it up as weak alias.311if (l->isLazy() || isa<Defined>(l)) {312if (ctx.config.warnStdcallFixup)313warn("Resolving " + origName + " by linking to " + newName);314else315log("Resolving " + origName + " by linking to " + newName);316undef->weakAlias = l;317continue;318}319}320}321322if (ctx.config.autoImport) {323if (name.starts_with("__imp_"))324continue;325// If we have an undefined symbol, but we have a lazy symbol we could326// load, load it.327Symbol *l = find(("__imp_" + name).str());328if (!l || l->pendingArchiveLoad || !l->isLazy())329continue;330331log("Loading lazy " + l->getName() + " from " + l->getFile()->getName() +332" for automatic import");333forceLazy(l);334}335}336}337338Defined *SymbolTable::impSymbol(StringRef name) {339if (name.starts_with("__imp_"))340return nullptr;341return dyn_cast_or_null<Defined>(find(("__imp_" + name).str()));342}343344bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {345Defined *imp = impSymbol(name);346if (!imp)347return false;348349// Replace the reference directly to a variable with a reference350// to the import address table instead. This obviously isn't right,351// but we mark the symbol as isRuntimePseudoReloc, and a later pass352// will add runtime pseudo relocations for every relocation against353// this Symbol. The runtime pseudo relocation framework expects the354// reference itself to point at the IAT entry.355size_t impSize = 0;356if (isa<DefinedImportData>(imp)) {357log("Automatically importing " + name + " from " +358cast<DefinedImportData>(imp)->getDLLName());359impSize = sizeof(DefinedImportData);360} else if (isa<DefinedRegular>(imp)) {361log("Automatically importing " + name + " from " +362toString(cast<DefinedRegular>(imp)->file));363impSize = sizeof(DefinedRegular);364} else {365warn("unable to automatically import " + name + " from " + imp->getName() +366" from " + toString(cast<DefinedRegular>(imp)->file) +367"; unexpected symbol type");368return false;369}370sym->replaceKeepingName(imp, impSize);371sym->isRuntimePseudoReloc = true;372373// There may exist symbols named .refptr.<name> which only consist374// of a single pointer to <name>. If it turns out <name> is375// automatically imported, we don't need to keep the .refptr.<name>376// pointer at all, but redirect all accesses to it to the IAT entry377// for __imp_<name> instead, and drop the whole .refptr.<name> chunk.378DefinedRegular *refptr =379dyn_cast_or_null<DefinedRegular>(find((".refptr." + name).str()));380if (refptr && refptr->getChunk()->getSize() == ctx.config.wordsize) {381SectionChunk *sc = dyn_cast_or_null<SectionChunk>(refptr->getChunk());382if (sc && sc->getRelocs().size() == 1 && *sc->symbols().begin() == sym) {383log("Replacing .refptr." + name + " with " + imp->getName());384refptr->getChunk()->live = false;385refptr->replaceKeepingName(imp, impSize);386}387}388return true;389}390391/// Helper function for reportUnresolvable and resolveRemainingUndefines.392/// This function emits an "undefined symbol" diagnostic for each symbol in393/// undefs. If localImports is not nullptr, it also emits a "locally394/// defined symbol imported" diagnostic for symbols in localImports.395/// objFiles and bitcodeFiles (if not nullptr) are used to report where396/// undefined symbols are referenced.397static void reportProblemSymbols(398const COFFLinkerContext &ctx, const SmallPtrSetImpl<Symbol *> &undefs,399const DenseMap<Symbol *, Symbol *> *localImports, bool needBitcodeFiles) {400// Return early if there is nothing to report (which should be401// the common case).402if (undefs.empty() && (!localImports || localImports->empty()))403return;404405for (Symbol *b : ctx.config.gcroot) {406if (undefs.count(b))407errorOrWarn("<root>: undefined symbol: " + toString(ctx, *b),408ctx.config.forceUnresolved);409if (localImports)410if (Symbol *imp = localImports->lookup(b))411warn("<root>: locally defined symbol imported: " + toString(ctx, *imp) +412" (defined in " + toString(imp->getFile()) + ") [LNK4217]");413}414415std::vector<UndefinedDiag> undefDiags;416DenseMap<Symbol *, int> firstDiag;417418auto processFile = [&](InputFile *file, ArrayRef<Symbol *> symbols) {419uint32_t symIndex = (uint32_t)-1;420for (Symbol *sym : symbols) {421++symIndex;422if (!sym)423continue;424if (undefs.count(sym)) {425auto it = firstDiag.find(sym);426if (it == firstDiag.end()) {427firstDiag[sym] = undefDiags.size();428undefDiags.push_back({sym, {{file, symIndex}}});429} else {430undefDiags[it->second].files.push_back({file, symIndex});431}432}433if (localImports)434if (Symbol *imp = localImports->lookup(sym))435warn(toString(file) +436": locally defined symbol imported: " + toString(ctx, *imp) +437" (defined in " + toString(imp->getFile()) + ") [LNK4217]");438}439};440441for (ObjFile *file : ctx.objFileInstances)442processFile(file, file->getSymbols());443444if (needBitcodeFiles)445for (BitcodeFile *file : ctx.bitcodeFileInstances)446processFile(file, file->getSymbols());447448for (const UndefinedDiag &undefDiag : undefDiags)449reportUndefinedSymbol(ctx, undefDiag);450}451452void SymbolTable::reportUnresolvable() {453SmallPtrSet<Symbol *, 8> undefs;454for (auto &i : symMap) {455Symbol *sym = i.second;456auto *undef = dyn_cast<Undefined>(sym);457if (!undef || sym->deferUndefined)458continue;459if (undef->getWeakAlias())460continue;461StringRef name = undef->getName();462if (name.starts_with("__imp_")) {463Symbol *imp = find(name.substr(strlen("__imp_")));464if (Defined *def = dyn_cast_or_null<Defined>(imp)) {465def->isUsedInRegularObj = true;466continue;467}468}469if (name.contains("_PchSym_"))470continue;471if (ctx.config.autoImport && impSymbol(name))472continue;473undefs.insert(sym);474}475476reportProblemSymbols(ctx, undefs,477/* localImports */ nullptr, true);478}479480void SymbolTable::resolveRemainingUndefines() {481llvm::TimeTraceScope timeScope("Resolve remaining undefined symbols");482SmallPtrSet<Symbol *, 8> undefs;483DenseMap<Symbol *, Symbol *> localImports;484485for (auto &i : symMap) {486Symbol *sym = i.second;487auto *undef = dyn_cast<Undefined>(sym);488if (!undef)489continue;490if (!sym->isUsedInRegularObj)491continue;492493StringRef name = undef->getName();494495// A weak alias may have been resolved, so check for that.496if (Defined *d = undef->getWeakAlias()) {497// We want to replace Sym with D. However, we can't just blindly498// copy sizeof(SymbolUnion) bytes from D to Sym because D may be an499// internal symbol, and internal symbols are stored as "unparented"500// Symbols. For that reason we need to check which type of symbol we501// are dealing with and copy the correct number of bytes.502if (isa<DefinedRegular>(d))503memcpy(sym, d, sizeof(DefinedRegular));504else if (isa<DefinedAbsolute>(d))505memcpy(sym, d, sizeof(DefinedAbsolute));506else507memcpy(sym, d, sizeof(SymbolUnion));508continue;509}510511// If we can resolve a symbol by removing __imp_ prefix, do that.512// This odd rule is for compatibility with MSVC linker.513if (name.starts_with("__imp_")) {514Symbol *imp = find(name.substr(strlen("__imp_")));515if (imp && isa<Defined>(imp)) {516auto *d = cast<Defined>(imp);517replaceSymbol<DefinedLocalImport>(sym, ctx, name, d);518localImportChunks.push_back(cast<DefinedLocalImport>(sym)->getChunk());519localImports[sym] = d;520continue;521}522}523524// We don't want to report missing Microsoft precompiled headers symbols.525// A proper message will be emitted instead in PDBLinker::aquirePrecompObj526if (name.contains("_PchSym_"))527continue;528529if (ctx.config.autoImport && handleMinGWAutomaticImport(sym, name))530continue;531532// Remaining undefined symbols are not fatal if /force is specified.533// They are replaced with dummy defined symbols.534if (ctx.config.forceUnresolved)535replaceSymbol<DefinedAbsolute>(sym, ctx, name, 0);536undefs.insert(sym);537}538539reportProblemSymbols(540ctx, undefs,541ctx.config.warnLocallyDefinedImported ? &localImports : nullptr, false);542}543544std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {545bool inserted = false;546Symbol *&sym = symMap[CachedHashStringRef(name)];547if (!sym) {548sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());549sym->isUsedInRegularObj = false;550sym->pendingArchiveLoad = false;551sym->canInline = true;552inserted = true;553}554return {sym, inserted};555}556557std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, InputFile *file) {558std::pair<Symbol *, bool> result = insert(name);559if (!file || !isa<BitcodeFile>(file))560result.first->isUsedInRegularObj = true;561return result;562}563564void SymbolTable::addEntryThunk(Symbol *from, Symbol *to) {565entryThunks.push_back({from, to});566}567568void SymbolTable::initializeEntryThunks() {569for (auto it : entryThunks) {570auto *to = dyn_cast<Defined>(it.second);571if (!to)572continue;573auto *from = dyn_cast<DefinedRegular>(it.first);574// We need to be able to add padding to the function and fill it with an575// offset to its entry thunks. To ensure that padding the function is576// feasible, functions are required to be COMDAT symbols with no offset.577if (!from || !from->getChunk()->isCOMDAT() ||578cast<DefinedRegular>(from)->getValue()) {579error("non COMDAT symbol '" + from->getName() + "' in hybrid map");580continue;581}582from->getChunk()->setEntryThunk(to);583}584}585586Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f,587bool isWeakAlias) {588auto [s, wasInserted] = insert(name, f);589if (wasInserted || (s->isLazy() && isWeakAlias)) {590replaceSymbol<Undefined>(s, name);591return s;592}593if (s->isLazy())594forceLazy(s);595return s;596}597598void SymbolTable::addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym) {599StringRef name = sym.getName();600auto [s, wasInserted] = insert(name);601if (wasInserted) {602replaceSymbol<LazyArchive>(s, f, sym);603return;604}605auto *u = dyn_cast<Undefined>(s);606if (!u || u->weakAlias || s->pendingArchiveLoad)607return;608s->pendingArchiveLoad = true;609f->addMember(sym);610}611612void SymbolTable::addLazyObject(InputFile *f, StringRef n) {613assert(f->lazy);614auto [s, wasInserted] = insert(n, f);615if (wasInserted) {616replaceSymbol<LazyObject>(s, f, n);617return;618}619auto *u = dyn_cast<Undefined>(s);620if (!u || u->weakAlias || s->pendingArchiveLoad)621return;622s->pendingArchiveLoad = true;623f->lazy = false;624addFile(f);625}626627void SymbolTable::addLazyDLLSymbol(DLLFile *f, DLLFile::Symbol *sym,628StringRef n) {629auto [s, wasInserted] = insert(n);630if (wasInserted) {631replaceSymbol<LazyDLLSymbol>(s, f, sym, n);632return;633}634auto *u = dyn_cast<Undefined>(s);635if (!u || u->weakAlias || s->pendingArchiveLoad)636return;637s->pendingArchiveLoad = true;638f->makeImport(sym);639}640641static std::string getSourceLocationBitcode(BitcodeFile *file) {642std::string res("\n>>> defined at ");643StringRef source = file->obj->getSourceFileName();644if (!source.empty())645res += source.str() + "\n>>> ";646res += toString(file);647return res;648}649650static std::string getSourceLocationObj(ObjFile *file, SectionChunk *sc,651uint32_t offset, StringRef name) {652std::optional<std::pair<StringRef, uint32_t>> fileLine;653if (sc)654fileLine = getFileLine(sc, offset);655if (!fileLine)656fileLine = file->getVariableLocation(name);657658std::string res;659llvm::raw_string_ostream os(res);660os << "\n>>> defined at ";661if (fileLine)662os << fileLine->first << ":" << fileLine->second << "\n>>> ";663os << toString(file);664return os.str();665}666667static std::string getSourceLocation(InputFile *file, SectionChunk *sc,668uint32_t offset, StringRef name) {669if (!file)670return "";671if (auto *o = dyn_cast<ObjFile>(file))672return getSourceLocationObj(o, sc, offset, name);673if (auto *b = dyn_cast<BitcodeFile>(file))674return getSourceLocationBitcode(b);675return "\n>>> defined at " + toString(file);676}677678// Construct and print an error message in the form of:679//680// lld-link: error: duplicate symbol: foo681// >>> defined at bar.c:30682// >>> bar.o683// >>> defined at baz.c:563684// >>> baz.o685void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile,686SectionChunk *newSc,687uint32_t newSectionOffset) {688std::string msg;689llvm::raw_string_ostream os(msg);690os << "duplicate symbol: " << toString(ctx, *existing);691692DefinedRegular *d = dyn_cast<DefinedRegular>(existing);693if (d && isa<ObjFile>(d->getFile())) {694os << getSourceLocation(d->getFile(), d->getChunk(), d->getValue(),695existing->getName());696} else {697os << getSourceLocation(existing->getFile(), nullptr, 0, "");698}699os << getSourceLocation(newFile, newSc, newSectionOffset,700existing->getName());701702if (ctx.config.forceMultiple)703warn(os.str());704else705error(os.str());706}707708Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) {709auto [s, wasInserted] = insert(n, nullptr);710s->isUsedInRegularObj = true;711if (wasInserted || isa<Undefined>(s) || s->isLazy())712replaceSymbol<DefinedAbsolute>(s, ctx, n, sym);713else if (auto *da = dyn_cast<DefinedAbsolute>(s)) {714if (da->getVA() != sym.getValue())715reportDuplicate(s, nullptr);716} else if (!isa<DefinedCOFF>(s))717reportDuplicate(s, nullptr);718return s;719}720721Symbol *SymbolTable::addAbsolute(StringRef n, uint64_t va) {722auto [s, wasInserted] = insert(n, nullptr);723s->isUsedInRegularObj = true;724if (wasInserted || isa<Undefined>(s) || s->isLazy())725replaceSymbol<DefinedAbsolute>(s, ctx, n, va);726else if (auto *da = dyn_cast<DefinedAbsolute>(s)) {727if (da->getVA() != va)728reportDuplicate(s, nullptr);729} else if (!isa<DefinedCOFF>(s))730reportDuplicate(s, nullptr);731return s;732}733734Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) {735auto [s, wasInserted] = insert(n, nullptr);736s->isUsedInRegularObj = true;737if (wasInserted || isa<Undefined>(s) || s->isLazy())738replaceSymbol<DefinedSynthetic>(s, n, c);739else if (!isa<DefinedCOFF>(s))740reportDuplicate(s, nullptr);741return s;742}743744Symbol *SymbolTable::addRegular(InputFile *f, StringRef n,745const coff_symbol_generic *sym, SectionChunk *c,746uint32_t sectionOffset, bool isWeak) {747auto [s, wasInserted] = insert(n, f);748if (wasInserted || !isa<DefinedRegular>(s) || s->isWeak)749replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ false,750/*IsExternal*/ true, sym, c, isWeak);751else if (!isWeak)752reportDuplicate(s, f, c, sectionOffset);753return s;754}755756std::pair<DefinedRegular *, bool>757SymbolTable::addComdat(InputFile *f, StringRef n,758const coff_symbol_generic *sym) {759auto [s, wasInserted] = insert(n, f);760if (wasInserted || !isa<DefinedRegular>(s)) {761replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ true,762/*IsExternal*/ true, sym, nullptr);763return {cast<DefinedRegular>(s), true};764}765auto *existingSymbol = cast<DefinedRegular>(s);766if (!existingSymbol->isCOMDAT)767reportDuplicate(s, f);768return {existingSymbol, false};769}770771Symbol *SymbolTable::addCommon(InputFile *f, StringRef n, uint64_t size,772const coff_symbol_generic *sym, CommonChunk *c) {773auto [s, wasInserted] = insert(n, f);774if (wasInserted || !isa<DefinedCOFF>(s))775replaceSymbol<DefinedCommon>(s, f, n, size, sym, c);776else if (auto *dc = dyn_cast<DefinedCommon>(s))777if (size > dc->getSize())778replaceSymbol<DefinedCommon>(s, f, n, size, sym, c);779return s;780}781782Symbol *SymbolTable::addImportData(StringRef n, ImportFile *f) {783auto [s, wasInserted] = insert(n, nullptr);784s->isUsedInRegularObj = true;785if (wasInserted || isa<Undefined>(s) || s->isLazy()) {786replaceSymbol<DefinedImportData>(s, n, f);787return s;788}789790reportDuplicate(s, f);791return nullptr;792}793794Symbol *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id,795uint16_t machine) {796auto [s, wasInserted] = insert(name, nullptr);797s->isUsedInRegularObj = true;798if (wasInserted || isa<Undefined>(s) || s->isLazy()) {799replaceSymbol<DefinedImportThunk>(s, ctx, name, id, machine);800return s;801}802803reportDuplicate(s, id->file);804return nullptr;805}806807void SymbolTable::addLibcall(StringRef name) {808Symbol *sym = findUnderscore(name);809if (!sym)810return;811812if (auto *l = dyn_cast<LazyArchive>(sym)) {813MemoryBufferRef mb = l->getMemberBuffer();814if (isBitcode(mb))815addUndefined(sym->getName());816} else if (LazyObject *o = dyn_cast<LazyObject>(sym)) {817if (isBitcode(o->file->mb))818addUndefined(sym->getName());819}820}821822std::vector<Chunk *> SymbolTable::getChunks() const {823std::vector<Chunk *> res;824for (ObjFile *file : ctx.objFileInstances) {825ArrayRef<Chunk *> v = file->getChunks();826res.insert(res.end(), v.begin(), v.end());827}828return res;829}830831Symbol *SymbolTable::find(StringRef name) const {832return symMap.lookup(CachedHashStringRef(name));833}834835Symbol *SymbolTable::findUnderscore(StringRef name) const {836if (ctx.config.machine == I386)837return find(("_" + name).str());838return find(name);839}840841// Return all symbols that start with Prefix, possibly ignoring the first842// character of Prefix or the first character symbol.843std::vector<Symbol *> SymbolTable::getSymsWithPrefix(StringRef prefix) {844std::vector<Symbol *> syms;845for (auto pair : symMap) {846StringRef name = pair.first.val();847if (name.starts_with(prefix) || name.starts_with(prefix.drop_front()) ||848name.drop_front().starts_with(prefix) ||849name.drop_front().starts_with(prefix.drop_front())) {850syms.push_back(pair.second);851}852}853return syms;854}855856Symbol *SymbolTable::findMangle(StringRef name) {857if (Symbol *sym = find(name)) {858if (auto *u = dyn_cast<Undefined>(sym)) {859// We're specifically looking for weak aliases that ultimately resolve to860// defined symbols, hence the call to getWeakAlias() instead of just using861// the weakAlias member variable. This matches link.exe's behavior.862if (Symbol *weakAlias = u->getWeakAlias())863return weakAlias;864} else {865return sym;866}867}868869// Efficient fuzzy string lookup is impossible with a hash table, so iterate870// the symbol table once and collect all possibly matching symbols into this871// vector. Then compare each possibly matching symbol with each possible872// mangling.873std::vector<Symbol *> syms = getSymsWithPrefix(name);874auto findByPrefix = [&syms](const Twine &t) -> Symbol * {875std::string prefix = t.str();876for (auto *s : syms)877if (s->getName().starts_with(prefix))878return s;879return nullptr;880};881882// For non-x86, just look for C++ functions.883if (ctx.config.machine != I386)884return findByPrefix("?" + name + "@@Y");885886if (!name.starts_with("_"))887return nullptr;888// Search for x86 stdcall function.889if (Symbol *s = findByPrefix(name + "@"))890return s;891// Search for x86 fastcall function.892if (Symbol *s = findByPrefix("@" + name.substr(1) + "@"))893return s;894// Search for x86 vectorcall function.895if (Symbol *s = findByPrefix(name.substr(1) + "@@"))896return s;897// Search for x86 C++ non-member function.898return findByPrefix("?" + name.substr(1) + "@@Y");899}900901Symbol *SymbolTable::addUndefined(StringRef name) {902return addUndefined(name, nullptr, false);903}904905void SymbolTable::compileBitcodeFiles() {906ltoCompilationDone = true;907if (ctx.bitcodeFileInstances.empty())908return;909910llvm::TimeTraceScope timeScope("Compile bitcode");911ScopedTimer t(ctx.ltoTimer);912lto.reset(new BitcodeCompiler(ctx));913for (BitcodeFile *f : ctx.bitcodeFileInstances)914lto->add(*f);915for (InputFile *newObj : lto->compile()) {916ObjFile *obj = cast<ObjFile>(newObj);917obj->parse();918ctx.objFileInstances.push_back(obj);919}920}921922} // namespace lld::coff923924925