xref: /openbsd-src/gnu/llvm/lld/COFF/SymbolTable.cpp (revision dfe94b169149f14cc1aee2cf6dad58a8d9a1860c)
1ece8a530Spatrick //===- SymbolTable.cpp ----------------------------------------------------===//
2ece8a530Spatrick //
3ece8a530Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ece8a530Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ece8a530Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ece8a530Spatrick //
7ece8a530Spatrick //===----------------------------------------------------------------------===//
8ece8a530Spatrick 
9ece8a530Spatrick #include "SymbolTable.h"
10*dfe94b16Srobert #include "COFFLinkerContext.h"
11ece8a530Spatrick #include "Config.h"
12ece8a530Spatrick #include "Driver.h"
13ece8a530Spatrick #include "LTO.h"
14ece8a530Spatrick #include "PDB.h"
15ece8a530Spatrick #include "Symbols.h"
16ece8a530Spatrick #include "lld/Common/ErrorHandler.h"
17ece8a530Spatrick #include "lld/Common/Memory.h"
18ece8a530Spatrick #include "lld/Common/Timer.h"
19*dfe94b16Srobert #include "llvm/DebugInfo/DIContext.h"
20ece8a530Spatrick #include "llvm/IR/LLVMContext.h"
21ece8a530Spatrick #include "llvm/LTO/LTO.h"
22ece8a530Spatrick #include "llvm/Object/WindowsMachineFlag.h"
23ece8a530Spatrick #include "llvm/Support/Debug.h"
24ece8a530Spatrick #include "llvm/Support/raw_ostream.h"
25ece8a530Spatrick #include <utility>
26ece8a530Spatrick 
27ece8a530Spatrick using namespace llvm;
28ece8a530Spatrick 
29*dfe94b16Srobert namespace lld::coff {
30ece8a530Spatrick 
ltrim1(StringRef s,const char * chars)311cf9926bSpatrick StringRef ltrim1(StringRef s, const char *chars) {
321cf9926bSpatrick   if (!s.empty() && strchr(chars, s[0]))
331cf9926bSpatrick     return s.substr(1);
341cf9926bSpatrick   return s;
351cf9926bSpatrick }
361cf9926bSpatrick 
addFile(InputFile * file)37ece8a530Spatrick void SymbolTable::addFile(InputFile *file) {
38ece8a530Spatrick   log("Reading " + toString(file));
39*dfe94b16Srobert   if (file->lazy) {
40*dfe94b16Srobert     if (auto *f = dyn_cast<BitcodeFile>(file))
41*dfe94b16Srobert       f->parseLazy();
42*dfe94b16Srobert     else
43*dfe94b16Srobert       cast<ObjFile>(file)->parseLazy();
44*dfe94b16Srobert   } else {
45ece8a530Spatrick     file->parse();
46*dfe94b16Srobert     if (auto *f = dyn_cast<ObjFile>(file)) {
47*dfe94b16Srobert       ctx.objFileInstances.push_back(f);
48*dfe94b16Srobert     } else if (auto *f = dyn_cast<BitcodeFile>(file)) {
49*dfe94b16Srobert       ctx.bitcodeFileInstances.push_back(f);
50*dfe94b16Srobert     } else if (auto *f = dyn_cast<ImportFile>(file)) {
51*dfe94b16Srobert       ctx.importFileInstances.push_back(f);
52*dfe94b16Srobert     }
53*dfe94b16Srobert   }
54ece8a530Spatrick 
55ece8a530Spatrick   MachineTypes mt = file->getMachineType();
56*dfe94b16Srobert   if (ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN) {
57*dfe94b16Srobert     ctx.config.machine = mt;
58*dfe94b16Srobert     ctx.driver.addWinSysRootLibSearchPaths();
59*dfe94b16Srobert   } else if (mt != IMAGE_FILE_MACHINE_UNKNOWN && ctx.config.machine != mt) {
60ece8a530Spatrick     error(toString(file) + ": machine type " + machineToStr(mt) +
61*dfe94b16Srobert           " conflicts with " + machineToStr(ctx.config.machine));
62ece8a530Spatrick     return;
63ece8a530Spatrick   }
64ece8a530Spatrick 
65*dfe94b16Srobert   ctx.driver.parseDirectives(file);
66ece8a530Spatrick }
67ece8a530Spatrick 
errorOrWarn(const Twine & s,bool forceUnresolved)68*dfe94b16Srobert static void errorOrWarn(const Twine &s, bool forceUnresolved) {
69*dfe94b16Srobert   if (forceUnresolved)
70ece8a530Spatrick     warn(s);
71ece8a530Spatrick   else
72ece8a530Spatrick     error(s);
73ece8a530Spatrick }
74ece8a530Spatrick 
75ece8a530Spatrick // Causes the file associated with a lazy symbol to be linked in.
forceLazy(Symbol * s)76ece8a530Spatrick static void forceLazy(Symbol *s) {
77ece8a530Spatrick   s->pendingArchiveLoad = true;
78ece8a530Spatrick   switch (s->kind()) {
79ece8a530Spatrick   case Symbol::Kind::LazyArchiveKind: {
80ece8a530Spatrick     auto *l = cast<LazyArchive>(s);
81ece8a530Spatrick     l->file->addMember(l->sym);
82ece8a530Spatrick     break;
83ece8a530Spatrick   }
84*dfe94b16Srobert   case Symbol::Kind::LazyObjectKind: {
85*dfe94b16Srobert     InputFile *file = cast<LazyObject>(s)->file;
86*dfe94b16Srobert     file->ctx.symtab.addFile(file);
87ece8a530Spatrick     break;
88*dfe94b16Srobert   }
891cf9926bSpatrick   case Symbol::Kind::LazyDLLSymbolKind: {
901cf9926bSpatrick     auto *l = cast<LazyDLLSymbol>(s);
911cf9926bSpatrick     l->file->makeImport(l->sym);
921cf9926bSpatrick     break;
931cf9926bSpatrick   }
94ece8a530Spatrick   default:
95ece8a530Spatrick     llvm_unreachable(
96ece8a530Spatrick         "symbol passed to forceLazy is not a LazyArchive or LazyObject");
97ece8a530Spatrick   }
98ece8a530Spatrick }
99ece8a530Spatrick 
100ece8a530Spatrick // Returns the symbol in SC whose value is <= Addr that is closest to Addr.
101ece8a530Spatrick // This is generally the global variable or function whose definition contains
102ece8a530Spatrick // Addr.
getSymbol(SectionChunk * sc,uint32_t addr)103ece8a530Spatrick static Symbol *getSymbol(SectionChunk *sc, uint32_t addr) {
104ece8a530Spatrick   DefinedRegular *candidate = nullptr;
105ece8a530Spatrick 
106ece8a530Spatrick   for (Symbol *s : sc->file->getSymbols()) {
107ece8a530Spatrick     auto *d = dyn_cast_or_null<DefinedRegular>(s);
108ece8a530Spatrick     if (!d || !d->data || d->file != sc->file || d->getChunk() != sc ||
109ece8a530Spatrick         d->getValue() > addr ||
110ece8a530Spatrick         (candidate && d->getValue() < candidate->getValue()))
111ece8a530Spatrick       continue;
112ece8a530Spatrick 
113ece8a530Spatrick     candidate = d;
114ece8a530Spatrick   }
115ece8a530Spatrick 
116ece8a530Spatrick   return candidate;
117ece8a530Spatrick }
118ece8a530Spatrick 
getSymbolLocations(BitcodeFile * file)119ece8a530Spatrick static std::vector<std::string> getSymbolLocations(BitcodeFile *file) {
120ece8a530Spatrick   std::string res("\n>>> referenced by ");
121ece8a530Spatrick   StringRef source = file->obj->getSourceFileName();
122ece8a530Spatrick   if (!source.empty())
123ece8a530Spatrick     res += source.str() + "\n>>>               ";
124ece8a530Spatrick   res += toString(file);
125ece8a530Spatrick   return {res};
126ece8a530Spatrick }
127ece8a530Spatrick 
128*dfe94b16Srobert static std::optional<std::pair<StringRef, uint32_t>>
getFileLineDwarf(const SectionChunk * c,uint32_t addr)129ece8a530Spatrick getFileLineDwarf(const SectionChunk *c, uint32_t addr) {
130*dfe94b16Srobert   std::optional<DILineInfo> optionalLineInfo =
131ece8a530Spatrick       c->file->getDILineInfo(addr, c->getSectionNumber() - 1);
132ece8a530Spatrick   if (!optionalLineInfo)
133*dfe94b16Srobert     return std::nullopt;
134ece8a530Spatrick   const DILineInfo &lineInfo = *optionalLineInfo;
135ece8a530Spatrick   if (lineInfo.FileName == DILineInfo::BadString)
136*dfe94b16Srobert     return std::nullopt;
137*dfe94b16Srobert   return std::make_pair(saver().save(lineInfo.FileName), lineInfo.Line);
138ece8a530Spatrick }
139ece8a530Spatrick 
140*dfe94b16Srobert static std::optional<std::pair<StringRef, uint32_t>>
getFileLine(const SectionChunk * c,uint32_t addr)141ece8a530Spatrick getFileLine(const SectionChunk *c, uint32_t addr) {
142ece8a530Spatrick   // MinGW can optionally use codeview, even if the default is dwarf.
143*dfe94b16Srobert   std::optional<std::pair<StringRef, uint32_t>> fileLine =
144ece8a530Spatrick       getFileLineCodeView(c, addr);
145ece8a530Spatrick   // If codeview didn't yield any result, check dwarf in MinGW mode.
146*dfe94b16Srobert   if (!fileLine && c->file->ctx.config.mingw)
147ece8a530Spatrick     fileLine = getFileLineDwarf(c, addr);
148ece8a530Spatrick   return fileLine;
149ece8a530Spatrick }
150ece8a530Spatrick 
151ece8a530Spatrick // Given a file and the index of a symbol in that file, returns a description
152ece8a530Spatrick // of all references to that symbol from that file. If no debug information is
153ece8a530Spatrick // available, returns just the name of the file, else one string per actual
154ece8a530Spatrick // reference as described in the debug info.
155bb684c34Spatrick // Returns up to maxStrings string descriptions, along with the total number of
156bb684c34Spatrick // locations found.
157bb684c34Spatrick static std::pair<std::vector<std::string>, size_t>
getSymbolLocations(ObjFile * file,uint32_t symIndex,size_t maxStrings)158bb684c34Spatrick getSymbolLocations(ObjFile *file, uint32_t symIndex, size_t maxStrings) {
159ece8a530Spatrick   struct Location {
160ece8a530Spatrick     Symbol *sym;
161ece8a530Spatrick     std::pair<StringRef, uint32_t> fileLine;
162ece8a530Spatrick   };
163ece8a530Spatrick   std::vector<Location> locations;
164bb684c34Spatrick   size_t numLocations = 0;
165ece8a530Spatrick 
166ece8a530Spatrick   for (Chunk *c : file->getChunks()) {
167ece8a530Spatrick     auto *sc = dyn_cast<SectionChunk>(c);
168ece8a530Spatrick     if (!sc)
169ece8a530Spatrick       continue;
170ece8a530Spatrick     for (const coff_relocation &r : sc->getRelocs()) {
171ece8a530Spatrick       if (r.SymbolTableIndex != symIndex)
172ece8a530Spatrick         continue;
173bb684c34Spatrick       numLocations++;
174bb684c34Spatrick       if (locations.size() >= maxStrings)
175bb684c34Spatrick         continue;
176bb684c34Spatrick 
177*dfe94b16Srobert       std::optional<std::pair<StringRef, uint32_t>> fileLine =
178ece8a530Spatrick           getFileLine(sc, r.VirtualAddress);
179ece8a530Spatrick       Symbol *sym = getSymbol(sc, r.VirtualAddress);
180ece8a530Spatrick       if (fileLine)
181ece8a530Spatrick         locations.push_back({sym, *fileLine});
182ece8a530Spatrick       else if (sym)
183ece8a530Spatrick         locations.push_back({sym, {"", 0}});
184ece8a530Spatrick     }
185ece8a530Spatrick   }
186ece8a530Spatrick 
187bb684c34Spatrick   if (maxStrings == 0)
188bb684c34Spatrick     return std::make_pair(std::vector<std::string>(), numLocations);
189bb684c34Spatrick 
190bb684c34Spatrick   if (numLocations == 0)
191bb684c34Spatrick     return std::make_pair(
192bb684c34Spatrick         std::vector<std::string>{"\n>>> referenced by " + toString(file)}, 1);
193ece8a530Spatrick 
194ece8a530Spatrick   std::vector<std::string> symbolLocations(locations.size());
195ece8a530Spatrick   size_t i = 0;
196ece8a530Spatrick   for (Location loc : locations) {
197ece8a530Spatrick     llvm::raw_string_ostream os(symbolLocations[i++]);
198ece8a530Spatrick     os << "\n>>> referenced by ";
199ece8a530Spatrick     if (!loc.fileLine.first.empty())
200ece8a530Spatrick       os << loc.fileLine.first << ":" << loc.fileLine.second
201ece8a530Spatrick          << "\n>>>               ";
202ece8a530Spatrick     os << toString(file);
203ece8a530Spatrick     if (loc.sym)
204*dfe94b16Srobert       os << ":(" << toString(file->ctx, *loc.sym) << ')';
205ece8a530Spatrick   }
206bb684c34Spatrick   return std::make_pair(symbolLocations, numLocations);
207ece8a530Spatrick }
208ece8a530Spatrick 
getSymbolLocations(ObjFile * file,uint32_t symIndex)209bb684c34Spatrick std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {
210bb684c34Spatrick   return getSymbolLocations(file, symIndex, SIZE_MAX).first;
211bb684c34Spatrick }
212bb684c34Spatrick 
213bb684c34Spatrick static std::pair<std::vector<std::string>, size_t>
getSymbolLocations(InputFile * file,uint32_t symIndex,size_t maxStrings)214bb684c34Spatrick getSymbolLocations(InputFile *file, uint32_t symIndex, size_t maxStrings) {
215ece8a530Spatrick   if (auto *o = dyn_cast<ObjFile>(file))
216bb684c34Spatrick     return getSymbolLocations(o, symIndex, maxStrings);
217bb684c34Spatrick   if (auto *b = dyn_cast<BitcodeFile>(file)) {
218bb684c34Spatrick     std::vector<std::string> symbolLocations = getSymbolLocations(b);
219bb684c34Spatrick     size_t numLocations = symbolLocations.size();
220bb684c34Spatrick     if (symbolLocations.size() > maxStrings)
221bb684c34Spatrick       symbolLocations.resize(maxStrings);
222bb684c34Spatrick     return std::make_pair(symbolLocations, numLocations);
223bb684c34Spatrick   }
224ece8a530Spatrick   llvm_unreachable("unsupported file type passed to getSymbolLocations");
225bb684c34Spatrick   return std::make_pair(std::vector<std::string>(), (size_t)0);
226ece8a530Spatrick }
227ece8a530Spatrick 
228ece8a530Spatrick // For an undefined symbol, stores all files referencing it and the index of
229ece8a530Spatrick // the undefined symbol in each file.
230ece8a530Spatrick struct UndefinedDiag {
231ece8a530Spatrick   Symbol *sym;
232ece8a530Spatrick   struct File {
233ece8a530Spatrick     InputFile *file;
234ece8a530Spatrick     uint32_t symIndex;
235ece8a530Spatrick   };
236ece8a530Spatrick   std::vector<File> files;
237ece8a530Spatrick };
238ece8a530Spatrick 
reportUndefinedSymbol(const COFFLinkerContext & ctx,const UndefinedDiag & undefDiag)239*dfe94b16Srobert static void reportUndefinedSymbol(const COFFLinkerContext &ctx,
240*dfe94b16Srobert                                   const UndefinedDiag &undefDiag) {
241ece8a530Spatrick   std::string out;
242ece8a530Spatrick   llvm::raw_string_ostream os(out);
243*dfe94b16Srobert   os << "undefined symbol: " << toString(ctx, *undefDiag.sym);
244ece8a530Spatrick 
245bb684c34Spatrick   const size_t maxUndefReferences = 3;
246bb684c34Spatrick   size_t numDisplayedRefs = 0, numRefs = 0;
247ece8a530Spatrick   for (const UndefinedDiag::File &ref : undefDiag.files) {
248*dfe94b16Srobert     auto [symbolLocations, totalLocations] = getSymbolLocations(
249bb684c34Spatrick         ref.file, ref.symIndex, maxUndefReferences - numDisplayedRefs);
250bb684c34Spatrick 
251bb684c34Spatrick     numRefs += totalLocations;
252bb684c34Spatrick     numDisplayedRefs += symbolLocations.size();
253ece8a530Spatrick     for (const std::string &s : symbolLocations) {
254ece8a530Spatrick       os << s;
255ece8a530Spatrick     }
256ece8a530Spatrick   }
257bb684c34Spatrick   if (numDisplayedRefs < numRefs)
258bb684c34Spatrick     os << "\n>>> referenced " << numRefs - numDisplayedRefs << " more times";
259*dfe94b16Srobert   errorOrWarn(os.str(), ctx.config.forceUnresolved);
260ece8a530Spatrick }
261ece8a530Spatrick 
loadMinGWSymbols()2621cf9926bSpatrick void SymbolTable::loadMinGWSymbols() {
263ece8a530Spatrick   for (auto &i : symMap) {
264ece8a530Spatrick     Symbol *sym = i.second;
265ece8a530Spatrick     auto *undef = dyn_cast<Undefined>(sym);
266ece8a530Spatrick     if (!undef)
267ece8a530Spatrick       continue;
268ece8a530Spatrick     if (undef->getWeakAlias())
269ece8a530Spatrick       continue;
270ece8a530Spatrick 
271ece8a530Spatrick     StringRef name = undef->getName();
272ece8a530Spatrick 
273*dfe94b16Srobert     if (ctx.config.machine == I386 && ctx.config.stdcallFixup) {
2741cf9926bSpatrick       // Check if we can resolve an undefined decorated symbol by finding
275*dfe94b16Srobert       // the intended target as an undecorated symbol (only with a leading
2761cf9926bSpatrick       // underscore).
2771cf9926bSpatrick       StringRef origName = name;
2781cf9926bSpatrick       StringRef baseName = name;
2791cf9926bSpatrick       // Trim down stdcall/fastcall/vectorcall symbols to the base name.
2801cf9926bSpatrick       baseName = ltrim1(baseName, "_@");
2811cf9926bSpatrick       baseName = baseName.substr(0, baseName.find('@'));
2821cf9926bSpatrick       // Add a leading underscore, as it would be in cdecl form.
2831cf9926bSpatrick       std::string newName = ("_" + baseName).str();
2841cf9926bSpatrick       Symbol *l;
2851cf9926bSpatrick       if (newName != origName && (l = find(newName)) != nullptr) {
2861cf9926bSpatrick         // If we found a symbol and it is lazy; load it.
2871cf9926bSpatrick         if (l->isLazy() && !l->pendingArchiveLoad) {
2881cf9926bSpatrick           log("Loading lazy " + l->getName() + " from " +
2891cf9926bSpatrick               l->getFile()->getName() + " for stdcall fixup");
2901cf9926bSpatrick           forceLazy(l);
2911cf9926bSpatrick         }
2921cf9926bSpatrick         // If it's lazy or already defined, hook it up as weak alias.
2931cf9926bSpatrick         if (l->isLazy() || isa<Defined>(l)) {
294*dfe94b16Srobert           if (ctx.config.warnStdcallFixup)
2951cf9926bSpatrick             warn("Resolving " + origName + " by linking to " + newName);
2961cf9926bSpatrick           else
2971cf9926bSpatrick             log("Resolving " + origName + " by linking to " + newName);
2981cf9926bSpatrick           undef->weakAlias = l;
2991cf9926bSpatrick           continue;
3001cf9926bSpatrick         }
3011cf9926bSpatrick       }
3021cf9926bSpatrick     }
3031cf9926bSpatrick 
304*dfe94b16Srobert     if (ctx.config.autoImport) {
305ece8a530Spatrick       if (name.startswith("__imp_"))
306ece8a530Spatrick         continue;
307ece8a530Spatrick       // If we have an undefined symbol, but we have a lazy symbol we could
308ece8a530Spatrick       // load, load it.
309ece8a530Spatrick       Symbol *l = find(("__imp_" + name).str());
310ece8a530Spatrick       if (!l || l->pendingArchiveLoad || !l->isLazy())
311ece8a530Spatrick         continue;
312ece8a530Spatrick 
313ece8a530Spatrick       log("Loading lazy " + l->getName() + " from " + l->getFile()->getName() +
314ece8a530Spatrick           " for automatic import");
315ece8a530Spatrick       forceLazy(l);
316ece8a530Spatrick     }
317ece8a530Spatrick   }
3181cf9926bSpatrick }
319ece8a530Spatrick 
impSymbol(StringRef name)320ece8a530Spatrick Defined *SymbolTable::impSymbol(StringRef name) {
321ece8a530Spatrick   if (name.startswith("__imp_"))
322ece8a530Spatrick     return nullptr;
323ece8a530Spatrick   return dyn_cast_or_null<Defined>(find(("__imp_" + name).str()));
324ece8a530Spatrick }
325ece8a530Spatrick 
handleMinGWAutomaticImport(Symbol * sym,StringRef name)326ece8a530Spatrick bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {
327ece8a530Spatrick   Defined *imp = impSymbol(name);
328ece8a530Spatrick   if (!imp)
329ece8a530Spatrick     return false;
330ece8a530Spatrick 
331ece8a530Spatrick   // Replace the reference directly to a variable with a reference
332ece8a530Spatrick   // to the import address table instead. This obviously isn't right,
333ece8a530Spatrick   // but we mark the symbol as isRuntimePseudoReloc, and a later pass
334ece8a530Spatrick   // will add runtime pseudo relocations for every relocation against
335ece8a530Spatrick   // this Symbol. The runtime pseudo relocation framework expects the
336ece8a530Spatrick   // reference itself to point at the IAT entry.
337ece8a530Spatrick   size_t impSize = 0;
338ece8a530Spatrick   if (isa<DefinedImportData>(imp)) {
339ece8a530Spatrick     log("Automatically importing " + name + " from " +
340ece8a530Spatrick         cast<DefinedImportData>(imp)->getDLLName());
341ece8a530Spatrick     impSize = sizeof(DefinedImportData);
342ece8a530Spatrick   } else if (isa<DefinedRegular>(imp)) {
343ece8a530Spatrick     log("Automatically importing " + name + " from " +
344ece8a530Spatrick         toString(cast<DefinedRegular>(imp)->file));
345ece8a530Spatrick     impSize = sizeof(DefinedRegular);
346ece8a530Spatrick   } else {
347ece8a530Spatrick     warn("unable to automatically import " + name + " from " + imp->getName() +
348ece8a530Spatrick          " from " + toString(cast<DefinedRegular>(imp)->file) +
349ece8a530Spatrick          "; unexpected symbol type");
350ece8a530Spatrick     return false;
351ece8a530Spatrick   }
352ece8a530Spatrick   sym->replaceKeepingName(imp, impSize);
353ece8a530Spatrick   sym->isRuntimePseudoReloc = true;
354ece8a530Spatrick 
355ece8a530Spatrick   // There may exist symbols named .refptr.<name> which only consist
356ece8a530Spatrick   // of a single pointer to <name>. If it turns out <name> is
357ece8a530Spatrick   // automatically imported, we don't need to keep the .refptr.<name>
358ece8a530Spatrick   // pointer at all, but redirect all accesses to it to the IAT entry
359ece8a530Spatrick   // for __imp_<name> instead, and drop the whole .refptr.<name> chunk.
360ece8a530Spatrick   DefinedRegular *refptr =
361ece8a530Spatrick       dyn_cast_or_null<DefinedRegular>(find((".refptr." + name).str()));
362*dfe94b16Srobert   if (refptr && refptr->getChunk()->getSize() == ctx.config.wordsize) {
363ece8a530Spatrick     SectionChunk *sc = dyn_cast_or_null<SectionChunk>(refptr->getChunk());
364ece8a530Spatrick     if (sc && sc->getRelocs().size() == 1 && *sc->symbols().begin() == sym) {
365ece8a530Spatrick       log("Replacing .refptr." + name + " with " + imp->getName());
366ece8a530Spatrick       refptr->getChunk()->live = false;
367ece8a530Spatrick       refptr->replaceKeepingName(imp, impSize);
368ece8a530Spatrick     }
369ece8a530Spatrick   }
370ece8a530Spatrick   return true;
371ece8a530Spatrick }
372ece8a530Spatrick 
373ece8a530Spatrick /// Helper function for reportUnresolvable and resolveRemainingUndefines.
374ece8a530Spatrick /// This function emits an "undefined symbol" diagnostic for each symbol in
375ece8a530Spatrick /// undefs. If localImports is not nullptr, it also emits a "locally
376ece8a530Spatrick /// defined symbol imported" diagnostic for symbols in localImports.
377ece8a530Spatrick /// objFiles and bitcodeFiles (if not nullptr) are used to report where
378ece8a530Spatrick /// undefined symbols are referenced.
reportProblemSymbols(const COFFLinkerContext & ctx,const SmallPtrSetImpl<Symbol * > & undefs,const DenseMap<Symbol *,Symbol * > * localImports,bool needBitcodeFiles)379*dfe94b16Srobert static void reportProblemSymbols(
380*dfe94b16Srobert     const COFFLinkerContext &ctx, const SmallPtrSetImpl<Symbol *> &undefs,
381*dfe94b16Srobert     const DenseMap<Symbol *, Symbol *> *localImports, bool needBitcodeFiles) {
382ece8a530Spatrick   // Return early if there is nothing to report (which should be
383ece8a530Spatrick   // the common case).
384ece8a530Spatrick   if (undefs.empty() && (!localImports || localImports->empty()))
385ece8a530Spatrick     return;
386ece8a530Spatrick 
387*dfe94b16Srobert   for (Symbol *b : ctx.config.gcroot) {
388ece8a530Spatrick     if (undefs.count(b))
389*dfe94b16Srobert       errorOrWarn("<root>: undefined symbol: " + toString(ctx, *b),
390*dfe94b16Srobert                   ctx.config.forceUnresolved);
391ece8a530Spatrick     if (localImports)
392ece8a530Spatrick       if (Symbol *imp = localImports->lookup(b))
393*dfe94b16Srobert         warn("<root>: locally defined symbol imported: " + toString(ctx, *imp) +
394ece8a530Spatrick              " (defined in " + toString(imp->getFile()) + ") [LNK4217]");
395ece8a530Spatrick   }
396ece8a530Spatrick 
397ece8a530Spatrick   std::vector<UndefinedDiag> undefDiags;
398ece8a530Spatrick   DenseMap<Symbol *, int> firstDiag;
399ece8a530Spatrick 
400ece8a530Spatrick   auto processFile = [&](InputFile *file, ArrayRef<Symbol *> symbols) {
401ece8a530Spatrick     uint32_t symIndex = (uint32_t)-1;
402ece8a530Spatrick     for (Symbol *sym : symbols) {
403ece8a530Spatrick       ++symIndex;
404ece8a530Spatrick       if (!sym)
405ece8a530Spatrick         continue;
406ece8a530Spatrick       if (undefs.count(sym)) {
407ece8a530Spatrick         auto it = firstDiag.find(sym);
408ece8a530Spatrick         if (it == firstDiag.end()) {
409ece8a530Spatrick           firstDiag[sym] = undefDiags.size();
410ece8a530Spatrick           undefDiags.push_back({sym, {{file, symIndex}}});
411ece8a530Spatrick         } else {
412ece8a530Spatrick           undefDiags[it->second].files.push_back({file, symIndex});
413ece8a530Spatrick         }
414ece8a530Spatrick       }
415ece8a530Spatrick       if (localImports)
416ece8a530Spatrick         if (Symbol *imp = localImports->lookup(sym))
417ece8a530Spatrick           warn(toString(file) +
418*dfe94b16Srobert                ": locally defined symbol imported: " + toString(ctx, *imp) +
419ece8a530Spatrick                " (defined in " + toString(imp->getFile()) + ") [LNK4217]");
420ece8a530Spatrick     }
421ece8a530Spatrick   };
422ece8a530Spatrick 
423*dfe94b16Srobert   for (ObjFile *file : ctx.objFileInstances)
424ece8a530Spatrick     processFile(file, file->getSymbols());
425ece8a530Spatrick 
426*dfe94b16Srobert   if (needBitcodeFiles)
427*dfe94b16Srobert     for (BitcodeFile *file : ctx.bitcodeFileInstances)
428ece8a530Spatrick       processFile(file, file->getSymbols());
429ece8a530Spatrick 
430ece8a530Spatrick   for (const UndefinedDiag &undefDiag : undefDiags)
431*dfe94b16Srobert     reportUndefinedSymbol(ctx, undefDiag);
432ece8a530Spatrick }
433ece8a530Spatrick 
reportUnresolvable()434ece8a530Spatrick void SymbolTable::reportUnresolvable() {
435ece8a530Spatrick   SmallPtrSet<Symbol *, 8> undefs;
436ece8a530Spatrick   for (auto &i : symMap) {
437ece8a530Spatrick     Symbol *sym = i.second;
438ece8a530Spatrick     auto *undef = dyn_cast<Undefined>(sym);
4391cf9926bSpatrick     if (!undef || sym->deferUndefined)
440ece8a530Spatrick       continue;
441ece8a530Spatrick     if (undef->getWeakAlias())
442ece8a530Spatrick       continue;
443ece8a530Spatrick     StringRef name = undef->getName();
444ece8a530Spatrick     if (name.startswith("__imp_")) {
445ece8a530Spatrick       Symbol *imp = find(name.substr(strlen("__imp_")));
446ece8a530Spatrick       if (imp && isa<Defined>(imp))
447ece8a530Spatrick         continue;
448ece8a530Spatrick     }
449ece8a530Spatrick     if (name.contains("_PchSym_"))
450ece8a530Spatrick       continue;
451*dfe94b16Srobert     if (ctx.config.autoImport && impSymbol(name))
452ece8a530Spatrick       continue;
453ece8a530Spatrick     undefs.insert(sym);
454ece8a530Spatrick   }
455ece8a530Spatrick 
456*dfe94b16Srobert   reportProblemSymbols(ctx, undefs,
457*dfe94b16Srobert                        /* localImports */ nullptr, true);
458ece8a530Spatrick }
459ece8a530Spatrick 
resolveRemainingUndefines()460ece8a530Spatrick void SymbolTable::resolveRemainingUndefines() {
461ece8a530Spatrick   SmallPtrSet<Symbol *, 8> undefs;
462ece8a530Spatrick   DenseMap<Symbol *, Symbol *> localImports;
463ece8a530Spatrick 
464ece8a530Spatrick   for (auto &i : symMap) {
465ece8a530Spatrick     Symbol *sym = i.second;
466ece8a530Spatrick     auto *undef = dyn_cast<Undefined>(sym);
467ece8a530Spatrick     if (!undef)
468ece8a530Spatrick       continue;
469ece8a530Spatrick     if (!sym->isUsedInRegularObj)
470ece8a530Spatrick       continue;
471ece8a530Spatrick 
472ece8a530Spatrick     StringRef name = undef->getName();
473ece8a530Spatrick 
474ece8a530Spatrick     // A weak alias may have been resolved, so check for that.
475ece8a530Spatrick     if (Defined *d = undef->getWeakAlias()) {
476ece8a530Spatrick       // We want to replace Sym with D. However, we can't just blindly
477ece8a530Spatrick       // copy sizeof(SymbolUnion) bytes from D to Sym because D may be an
478ece8a530Spatrick       // internal symbol, and internal symbols are stored as "unparented"
479ece8a530Spatrick       // Symbols. For that reason we need to check which type of symbol we
480ece8a530Spatrick       // are dealing with and copy the correct number of bytes.
481ece8a530Spatrick       if (isa<DefinedRegular>(d))
482ece8a530Spatrick         memcpy(sym, d, sizeof(DefinedRegular));
483ece8a530Spatrick       else if (isa<DefinedAbsolute>(d))
484ece8a530Spatrick         memcpy(sym, d, sizeof(DefinedAbsolute));
485ece8a530Spatrick       else
486ece8a530Spatrick         memcpy(sym, d, sizeof(SymbolUnion));
487ece8a530Spatrick       continue;
488ece8a530Spatrick     }
489ece8a530Spatrick 
490ece8a530Spatrick     // If we can resolve a symbol by removing __imp_ prefix, do that.
491ece8a530Spatrick     // This odd rule is for compatibility with MSVC linker.
492ece8a530Spatrick     if (name.startswith("__imp_")) {
493ece8a530Spatrick       Symbol *imp = find(name.substr(strlen("__imp_")));
494ece8a530Spatrick       if (imp && isa<Defined>(imp)) {
495ece8a530Spatrick         auto *d = cast<Defined>(imp);
496*dfe94b16Srobert         replaceSymbol<DefinedLocalImport>(sym, ctx, name, d);
497ece8a530Spatrick         localImportChunks.push_back(cast<DefinedLocalImport>(sym)->getChunk());
498ece8a530Spatrick         localImports[sym] = d;
499ece8a530Spatrick         continue;
500ece8a530Spatrick       }
501ece8a530Spatrick     }
502ece8a530Spatrick 
503ece8a530Spatrick     // We don't want to report missing Microsoft precompiled headers symbols.
504ece8a530Spatrick     // A proper message will be emitted instead in PDBLinker::aquirePrecompObj
505ece8a530Spatrick     if (name.contains("_PchSym_"))
506ece8a530Spatrick       continue;
507ece8a530Spatrick 
508*dfe94b16Srobert     if (ctx.config.autoImport && handleMinGWAutomaticImport(sym, name))
509ece8a530Spatrick       continue;
510ece8a530Spatrick 
511ece8a530Spatrick     // Remaining undefined symbols are not fatal if /force is specified.
512ece8a530Spatrick     // They are replaced with dummy defined symbols.
513*dfe94b16Srobert     if (ctx.config.forceUnresolved)
514*dfe94b16Srobert       replaceSymbol<DefinedAbsolute>(sym, ctx, name, 0);
515ece8a530Spatrick     undefs.insert(sym);
516ece8a530Spatrick   }
517ece8a530Spatrick 
518ece8a530Spatrick   reportProblemSymbols(
519*dfe94b16Srobert       ctx, undefs,
520*dfe94b16Srobert       ctx.config.warnLocallyDefinedImported ? &localImports : nullptr, false);
521ece8a530Spatrick }
522ece8a530Spatrick 
insert(StringRef name)523ece8a530Spatrick std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
524ece8a530Spatrick   bool inserted = false;
525ece8a530Spatrick   Symbol *&sym = symMap[CachedHashStringRef(name)];
526ece8a530Spatrick   if (!sym) {
527ece8a530Spatrick     sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
528ece8a530Spatrick     sym->isUsedInRegularObj = false;
529ece8a530Spatrick     sym->pendingArchiveLoad = false;
5301cf9926bSpatrick     sym->canInline = true;
531ece8a530Spatrick     inserted = true;
532ece8a530Spatrick   }
533ece8a530Spatrick   return {sym, inserted};
534ece8a530Spatrick }
535ece8a530Spatrick 
insert(StringRef name,InputFile * file)536ece8a530Spatrick std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, InputFile *file) {
537ece8a530Spatrick   std::pair<Symbol *, bool> result = insert(name);
538ece8a530Spatrick   if (!file || !isa<BitcodeFile>(file))
539ece8a530Spatrick     result.first->isUsedInRegularObj = true;
540ece8a530Spatrick   return result;
541ece8a530Spatrick }
542ece8a530Spatrick 
addUndefined(StringRef name,InputFile * f,bool isWeakAlias)543ece8a530Spatrick Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f,
544ece8a530Spatrick                                   bool isWeakAlias) {
545*dfe94b16Srobert   auto [s, wasInserted] = insert(name, f);
546ece8a530Spatrick   if (wasInserted || (s->isLazy() && isWeakAlias)) {
547ece8a530Spatrick     replaceSymbol<Undefined>(s, name);
548ece8a530Spatrick     return s;
549ece8a530Spatrick   }
550ece8a530Spatrick   if (s->isLazy())
551ece8a530Spatrick     forceLazy(s);
552ece8a530Spatrick   return s;
553ece8a530Spatrick }
554ece8a530Spatrick 
addLazyArchive(ArchiveFile * f,const Archive::Symbol & sym)555ece8a530Spatrick void SymbolTable::addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym) {
556ece8a530Spatrick   StringRef name = sym.getName();
557*dfe94b16Srobert   auto [s, wasInserted] = insert(name);
558ece8a530Spatrick   if (wasInserted) {
559ece8a530Spatrick     replaceSymbol<LazyArchive>(s, f, sym);
560ece8a530Spatrick     return;
561ece8a530Spatrick   }
562ece8a530Spatrick   auto *u = dyn_cast<Undefined>(s);
563ece8a530Spatrick   if (!u || u->weakAlias || s->pendingArchiveLoad)
564ece8a530Spatrick     return;
565ece8a530Spatrick   s->pendingArchiveLoad = true;
566ece8a530Spatrick   f->addMember(sym);
567ece8a530Spatrick }
568ece8a530Spatrick 
addLazyObject(InputFile * f,StringRef n)569*dfe94b16Srobert void SymbolTable::addLazyObject(InputFile *f, StringRef n) {
570*dfe94b16Srobert   assert(f->lazy);
571*dfe94b16Srobert   auto [s, wasInserted] = insert(n, f);
572ece8a530Spatrick   if (wasInserted) {
573ece8a530Spatrick     replaceSymbol<LazyObject>(s, f, n);
574ece8a530Spatrick     return;
575ece8a530Spatrick   }
576ece8a530Spatrick   auto *u = dyn_cast<Undefined>(s);
577ece8a530Spatrick   if (!u || u->weakAlias || s->pendingArchiveLoad)
578ece8a530Spatrick     return;
579ece8a530Spatrick   s->pendingArchiveLoad = true;
580*dfe94b16Srobert   f->lazy = false;
581*dfe94b16Srobert   addFile(f);
582ece8a530Spatrick }
583ece8a530Spatrick 
addLazyDLLSymbol(DLLFile * f,DLLFile::Symbol * sym,StringRef n)5841cf9926bSpatrick void SymbolTable::addLazyDLLSymbol(DLLFile *f, DLLFile::Symbol *sym,
5851cf9926bSpatrick                                    StringRef n) {
586*dfe94b16Srobert   auto [s, wasInserted] = insert(n);
5871cf9926bSpatrick   if (wasInserted) {
5881cf9926bSpatrick     replaceSymbol<LazyDLLSymbol>(s, f, sym, n);
5891cf9926bSpatrick     return;
5901cf9926bSpatrick   }
5911cf9926bSpatrick   auto *u = dyn_cast<Undefined>(s);
5921cf9926bSpatrick   if (!u || u->weakAlias || s->pendingArchiveLoad)
5931cf9926bSpatrick     return;
5941cf9926bSpatrick   s->pendingArchiveLoad = true;
5951cf9926bSpatrick   f->makeImport(sym);
5961cf9926bSpatrick }
5971cf9926bSpatrick 
getSourceLocationBitcode(BitcodeFile * file)598ece8a530Spatrick static std::string getSourceLocationBitcode(BitcodeFile *file) {
599ece8a530Spatrick   std::string res("\n>>> defined at ");
600ece8a530Spatrick   StringRef source = file->obj->getSourceFileName();
601ece8a530Spatrick   if (!source.empty())
602ece8a530Spatrick     res += source.str() + "\n>>>            ";
603ece8a530Spatrick   res += toString(file);
604ece8a530Spatrick   return res;
605ece8a530Spatrick }
606ece8a530Spatrick 
getSourceLocationObj(ObjFile * file,SectionChunk * sc,uint32_t offset,StringRef name)607ece8a530Spatrick static std::string getSourceLocationObj(ObjFile *file, SectionChunk *sc,
608ece8a530Spatrick                                         uint32_t offset, StringRef name) {
609*dfe94b16Srobert   std::optional<std::pair<StringRef, uint32_t>> fileLine;
610ece8a530Spatrick   if (sc)
611ece8a530Spatrick     fileLine = getFileLine(sc, offset);
612ece8a530Spatrick   if (!fileLine)
613ece8a530Spatrick     fileLine = file->getVariableLocation(name);
614ece8a530Spatrick 
615ece8a530Spatrick   std::string res;
616ece8a530Spatrick   llvm::raw_string_ostream os(res);
617ece8a530Spatrick   os << "\n>>> defined at ";
618ece8a530Spatrick   if (fileLine)
619ece8a530Spatrick     os << fileLine->first << ":" << fileLine->second << "\n>>>            ";
620ece8a530Spatrick   os << toString(file);
621ece8a530Spatrick   return os.str();
622ece8a530Spatrick }
623ece8a530Spatrick 
getSourceLocation(InputFile * file,SectionChunk * sc,uint32_t offset,StringRef name)624ece8a530Spatrick static std::string getSourceLocation(InputFile *file, SectionChunk *sc,
625ece8a530Spatrick                                      uint32_t offset, StringRef name) {
626ece8a530Spatrick   if (!file)
627ece8a530Spatrick     return "";
628ece8a530Spatrick   if (auto *o = dyn_cast<ObjFile>(file))
629ece8a530Spatrick     return getSourceLocationObj(o, sc, offset, name);
630ece8a530Spatrick   if (auto *b = dyn_cast<BitcodeFile>(file))
631ece8a530Spatrick     return getSourceLocationBitcode(b);
632ece8a530Spatrick   return "\n>>> defined at " + toString(file);
633ece8a530Spatrick }
634ece8a530Spatrick 
635ece8a530Spatrick // Construct and print an error message in the form of:
636ece8a530Spatrick //
637ece8a530Spatrick //   lld-link: error: duplicate symbol: foo
638ece8a530Spatrick //   >>> defined at bar.c:30
639ece8a530Spatrick //   >>>            bar.o
640ece8a530Spatrick //   >>> defined at baz.c:563
641ece8a530Spatrick //   >>>            baz.o
reportDuplicate(Symbol * existing,InputFile * newFile,SectionChunk * newSc,uint32_t newSectionOffset)642ece8a530Spatrick void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile,
643ece8a530Spatrick                                   SectionChunk *newSc,
644ece8a530Spatrick                                   uint32_t newSectionOffset) {
645ece8a530Spatrick   std::string msg;
646ece8a530Spatrick   llvm::raw_string_ostream os(msg);
647*dfe94b16Srobert   os << "duplicate symbol: " << toString(ctx, *existing);
648ece8a530Spatrick 
649ece8a530Spatrick   DefinedRegular *d = dyn_cast<DefinedRegular>(existing);
650ece8a530Spatrick   if (d && isa<ObjFile>(d->getFile())) {
651ece8a530Spatrick     os << getSourceLocation(d->getFile(), d->getChunk(), d->getValue(),
652ece8a530Spatrick                             existing->getName());
653ece8a530Spatrick   } else {
654ece8a530Spatrick     os << getSourceLocation(existing->getFile(), nullptr, 0, "");
655ece8a530Spatrick   }
656ece8a530Spatrick   os << getSourceLocation(newFile, newSc, newSectionOffset,
657ece8a530Spatrick                           existing->getName());
658ece8a530Spatrick 
659*dfe94b16Srobert   if (ctx.config.forceMultiple)
660ece8a530Spatrick     warn(os.str());
661ece8a530Spatrick   else
662ece8a530Spatrick     error(os.str());
663ece8a530Spatrick }
664ece8a530Spatrick 
addAbsolute(StringRef n,COFFSymbolRef sym)665ece8a530Spatrick Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) {
666*dfe94b16Srobert   auto [s, wasInserted] = insert(n, nullptr);
667ece8a530Spatrick   s->isUsedInRegularObj = true;
668ece8a530Spatrick   if (wasInserted || isa<Undefined>(s) || s->isLazy())
669*dfe94b16Srobert     replaceSymbol<DefinedAbsolute>(s, ctx, n, sym);
670ece8a530Spatrick   else if (auto *da = dyn_cast<DefinedAbsolute>(s)) {
671ece8a530Spatrick     if (da->getVA() != sym.getValue())
672ece8a530Spatrick       reportDuplicate(s, nullptr);
673ece8a530Spatrick   } else if (!isa<DefinedCOFF>(s))
674ece8a530Spatrick     reportDuplicate(s, nullptr);
675ece8a530Spatrick   return s;
676ece8a530Spatrick }
677ece8a530Spatrick 
addAbsolute(StringRef n,uint64_t va)678ece8a530Spatrick Symbol *SymbolTable::addAbsolute(StringRef n, uint64_t va) {
679*dfe94b16Srobert   auto [s, wasInserted] = insert(n, nullptr);
680ece8a530Spatrick   s->isUsedInRegularObj = true;
681ece8a530Spatrick   if (wasInserted || isa<Undefined>(s) || s->isLazy())
682*dfe94b16Srobert     replaceSymbol<DefinedAbsolute>(s, ctx, n, va);
683ece8a530Spatrick   else if (auto *da = dyn_cast<DefinedAbsolute>(s)) {
684ece8a530Spatrick     if (da->getVA() != va)
685ece8a530Spatrick       reportDuplicate(s, nullptr);
686ece8a530Spatrick   } else if (!isa<DefinedCOFF>(s))
687ece8a530Spatrick     reportDuplicate(s, nullptr);
688ece8a530Spatrick   return s;
689ece8a530Spatrick }
690ece8a530Spatrick 
addSynthetic(StringRef n,Chunk * c)691ece8a530Spatrick Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) {
692*dfe94b16Srobert   auto [s, wasInserted] = insert(n, nullptr);
693ece8a530Spatrick   s->isUsedInRegularObj = true;
694ece8a530Spatrick   if (wasInserted || isa<Undefined>(s) || s->isLazy())
695ece8a530Spatrick     replaceSymbol<DefinedSynthetic>(s, n, c);
696ece8a530Spatrick   else if (!isa<DefinedCOFF>(s))
697ece8a530Spatrick     reportDuplicate(s, nullptr);
698ece8a530Spatrick   return s;
699ece8a530Spatrick }
700ece8a530Spatrick 
addRegular(InputFile * f,StringRef n,const coff_symbol_generic * sym,SectionChunk * c,uint32_t sectionOffset,bool isWeak)701ece8a530Spatrick Symbol *SymbolTable::addRegular(InputFile *f, StringRef n,
702ece8a530Spatrick                                 const coff_symbol_generic *sym, SectionChunk *c,
703*dfe94b16Srobert                                 uint32_t sectionOffset, bool isWeak) {
704*dfe94b16Srobert   auto [s, wasInserted] = insert(n, f);
705*dfe94b16Srobert   if (wasInserted || !isa<DefinedRegular>(s) || s->isWeak)
706ece8a530Spatrick     replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ false,
707*dfe94b16Srobert                                   /*IsExternal*/ true, sym, c, isWeak);
708*dfe94b16Srobert   else if (!isWeak)
709ece8a530Spatrick     reportDuplicate(s, f, c, sectionOffset);
710ece8a530Spatrick   return s;
711ece8a530Spatrick }
712ece8a530Spatrick 
713ece8a530Spatrick std::pair<DefinedRegular *, bool>
addComdat(InputFile * f,StringRef n,const coff_symbol_generic * sym)714ece8a530Spatrick SymbolTable::addComdat(InputFile *f, StringRef n,
715ece8a530Spatrick                        const coff_symbol_generic *sym) {
716*dfe94b16Srobert   auto [s, wasInserted] = insert(n, f);
717ece8a530Spatrick   if (wasInserted || !isa<DefinedRegular>(s)) {
718ece8a530Spatrick     replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ true,
719ece8a530Spatrick                                   /*IsExternal*/ true, sym, nullptr);
720ece8a530Spatrick     return {cast<DefinedRegular>(s), true};
721ece8a530Spatrick   }
722ece8a530Spatrick   auto *existingSymbol = cast<DefinedRegular>(s);
723ece8a530Spatrick   if (!existingSymbol->isCOMDAT)
724ece8a530Spatrick     reportDuplicate(s, f);
725ece8a530Spatrick   return {existingSymbol, false};
726ece8a530Spatrick }
727ece8a530Spatrick 
addCommon(InputFile * f,StringRef n,uint64_t size,const coff_symbol_generic * sym,CommonChunk * c)728ece8a530Spatrick Symbol *SymbolTable::addCommon(InputFile *f, StringRef n, uint64_t size,
729ece8a530Spatrick                                const coff_symbol_generic *sym, CommonChunk *c) {
730*dfe94b16Srobert   auto [s, wasInserted] = insert(n, f);
731ece8a530Spatrick   if (wasInserted || !isa<DefinedCOFF>(s))
732ece8a530Spatrick     replaceSymbol<DefinedCommon>(s, f, n, size, sym, c);
733ece8a530Spatrick   else if (auto *dc = dyn_cast<DefinedCommon>(s))
734ece8a530Spatrick     if (size > dc->getSize())
735ece8a530Spatrick       replaceSymbol<DefinedCommon>(s, f, n, size, sym, c);
736ece8a530Spatrick   return s;
737ece8a530Spatrick }
738ece8a530Spatrick 
addImportData(StringRef n,ImportFile * f)739ece8a530Spatrick Symbol *SymbolTable::addImportData(StringRef n, ImportFile *f) {
740*dfe94b16Srobert   auto [s, wasInserted] = insert(n, nullptr);
741ece8a530Spatrick   s->isUsedInRegularObj = true;
742ece8a530Spatrick   if (wasInserted || isa<Undefined>(s) || s->isLazy()) {
743ece8a530Spatrick     replaceSymbol<DefinedImportData>(s, n, f);
744ece8a530Spatrick     return s;
745ece8a530Spatrick   }
746ece8a530Spatrick 
747ece8a530Spatrick   reportDuplicate(s, f);
748ece8a530Spatrick   return nullptr;
749ece8a530Spatrick }
750ece8a530Spatrick 
addImportThunk(StringRef name,DefinedImportData * id,uint16_t machine)751ece8a530Spatrick Symbol *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id,
752ece8a530Spatrick                                     uint16_t machine) {
753*dfe94b16Srobert   auto [s, wasInserted] = insert(name, nullptr);
754ece8a530Spatrick   s->isUsedInRegularObj = true;
755ece8a530Spatrick   if (wasInserted || isa<Undefined>(s) || s->isLazy()) {
756*dfe94b16Srobert     replaceSymbol<DefinedImportThunk>(s, ctx, name, id, machine);
757ece8a530Spatrick     return s;
758ece8a530Spatrick   }
759ece8a530Spatrick 
760ece8a530Spatrick   reportDuplicate(s, id->file);
761ece8a530Spatrick   return nullptr;
762ece8a530Spatrick }
763ece8a530Spatrick 
addLibcall(StringRef name)764ece8a530Spatrick void SymbolTable::addLibcall(StringRef name) {
765ece8a530Spatrick   Symbol *sym = findUnderscore(name);
766ece8a530Spatrick   if (!sym)
767ece8a530Spatrick     return;
768ece8a530Spatrick 
769ece8a530Spatrick   if (auto *l = dyn_cast<LazyArchive>(sym)) {
770ece8a530Spatrick     MemoryBufferRef mb = l->getMemberBuffer();
771ece8a530Spatrick     if (isBitcode(mb))
772ece8a530Spatrick       addUndefined(sym->getName());
773ece8a530Spatrick   } else if (LazyObject *o = dyn_cast<LazyObject>(sym)) {
774ece8a530Spatrick     if (isBitcode(o->file->mb))
775ece8a530Spatrick       addUndefined(sym->getName());
776ece8a530Spatrick   }
777ece8a530Spatrick }
778ece8a530Spatrick 
getChunks() const779*dfe94b16Srobert std::vector<Chunk *> SymbolTable::getChunks() const {
780ece8a530Spatrick   std::vector<Chunk *> res;
781*dfe94b16Srobert   for (ObjFile *file : ctx.objFileInstances) {
782ece8a530Spatrick     ArrayRef<Chunk *> v = file->getChunks();
783ece8a530Spatrick     res.insert(res.end(), v.begin(), v.end());
784ece8a530Spatrick   }
785ece8a530Spatrick   return res;
786ece8a530Spatrick }
787ece8a530Spatrick 
find(StringRef name) const788*dfe94b16Srobert Symbol *SymbolTable::find(StringRef name) const {
789ece8a530Spatrick   return symMap.lookup(CachedHashStringRef(name));
790ece8a530Spatrick }
791ece8a530Spatrick 
findUnderscore(StringRef name) const792*dfe94b16Srobert Symbol *SymbolTable::findUnderscore(StringRef name) const {
793*dfe94b16Srobert   if (ctx.config.machine == I386)
794ece8a530Spatrick     return find(("_" + name).str());
795ece8a530Spatrick   return find(name);
796ece8a530Spatrick }
797ece8a530Spatrick 
798ece8a530Spatrick // Return all symbols that start with Prefix, possibly ignoring the first
799ece8a530Spatrick // character of Prefix or the first character symbol.
getSymsWithPrefix(StringRef prefix)800ece8a530Spatrick std::vector<Symbol *> SymbolTable::getSymsWithPrefix(StringRef prefix) {
801ece8a530Spatrick   std::vector<Symbol *> syms;
802ece8a530Spatrick   for (auto pair : symMap) {
803ece8a530Spatrick     StringRef name = pair.first.val();
804ece8a530Spatrick     if (name.startswith(prefix) || name.startswith(prefix.drop_front()) ||
805ece8a530Spatrick         name.drop_front().startswith(prefix) ||
806ece8a530Spatrick         name.drop_front().startswith(prefix.drop_front())) {
807ece8a530Spatrick       syms.push_back(pair.second);
808ece8a530Spatrick     }
809ece8a530Spatrick   }
810ece8a530Spatrick   return syms;
811ece8a530Spatrick }
812ece8a530Spatrick 
findMangle(StringRef name)813ece8a530Spatrick Symbol *SymbolTable::findMangle(StringRef name) {
814*dfe94b16Srobert   if (Symbol *sym = find(name)) {
815*dfe94b16Srobert     if (auto *u = dyn_cast<Undefined>(sym)) {
816*dfe94b16Srobert       // We're specifically looking for weak aliases that ultimately resolve to
817*dfe94b16Srobert       // defined symbols, hence the call to getWeakAlias() instead of just using
818*dfe94b16Srobert       // the weakAlias member variable. This matches link.exe's behavior.
819*dfe94b16Srobert       if (Symbol *weakAlias = u->getWeakAlias())
820*dfe94b16Srobert         return weakAlias;
821*dfe94b16Srobert     } else {
822ece8a530Spatrick       return sym;
823*dfe94b16Srobert     }
824*dfe94b16Srobert   }
825ece8a530Spatrick 
826ece8a530Spatrick   // Efficient fuzzy string lookup is impossible with a hash table, so iterate
827ece8a530Spatrick   // the symbol table once and collect all possibly matching symbols into this
828ece8a530Spatrick   // vector. Then compare each possibly matching symbol with each possible
829ece8a530Spatrick   // mangling.
830ece8a530Spatrick   std::vector<Symbol *> syms = getSymsWithPrefix(name);
831ece8a530Spatrick   auto findByPrefix = [&syms](const Twine &t) -> Symbol * {
832ece8a530Spatrick     std::string prefix = t.str();
833ece8a530Spatrick     for (auto *s : syms)
834ece8a530Spatrick       if (s->getName().startswith(prefix))
835ece8a530Spatrick         return s;
836ece8a530Spatrick     return nullptr;
837ece8a530Spatrick   };
838ece8a530Spatrick 
839ece8a530Spatrick   // For non-x86, just look for C++ functions.
840*dfe94b16Srobert   if (ctx.config.machine != I386)
841ece8a530Spatrick     return findByPrefix("?" + name + "@@Y");
842ece8a530Spatrick 
843ece8a530Spatrick   if (!name.startswith("_"))
844ece8a530Spatrick     return nullptr;
845ece8a530Spatrick   // Search for x86 stdcall function.
846ece8a530Spatrick   if (Symbol *s = findByPrefix(name + "@"))
847ece8a530Spatrick     return s;
848ece8a530Spatrick   // Search for x86 fastcall function.
849ece8a530Spatrick   if (Symbol *s = findByPrefix("@" + name.substr(1) + "@"))
850ece8a530Spatrick     return s;
851ece8a530Spatrick   // Search for x86 vectorcall function.
852ece8a530Spatrick   if (Symbol *s = findByPrefix(name.substr(1) + "@@"))
853ece8a530Spatrick     return s;
854ece8a530Spatrick   // Search for x86 C++ non-member function.
855ece8a530Spatrick   return findByPrefix("?" + name.substr(1) + "@@Y");
856ece8a530Spatrick }
857ece8a530Spatrick 
addUndefined(StringRef name)858ece8a530Spatrick Symbol *SymbolTable::addUndefined(StringRef name) {
859ece8a530Spatrick   return addUndefined(name, nullptr, false);
860ece8a530Spatrick }
861ece8a530Spatrick 
compileBitcodeFiles()862*dfe94b16Srobert void SymbolTable::compileBitcodeFiles() {
863*dfe94b16Srobert   if (ctx.bitcodeFileInstances.empty())
864ece8a530Spatrick     return;
865ece8a530Spatrick 
866*dfe94b16Srobert   ScopedTimer t(ctx.ltoTimer);
867*dfe94b16Srobert   lto.reset(new BitcodeCompiler(ctx));
868*dfe94b16Srobert   for (BitcodeFile *f : ctx.bitcodeFileInstances)
869bb684c34Spatrick     lto->add(*f);
870bb684c34Spatrick   for (InputFile *newObj : lto->compile()) {
871bb684c34Spatrick     ObjFile *obj = cast<ObjFile>(newObj);
872ece8a530Spatrick     obj->parse();
873*dfe94b16Srobert     ctx.objFileInstances.push_back(obj);
874ece8a530Spatrick   }
875ece8a530Spatrick }
876ece8a530Spatrick 
877*dfe94b16Srobert } // namespace lld::coff
878