xref: /freebsd/contrib/llvm-project/lld/COFF/SymbolTable.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===- SymbolTable.cpp ----------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "SymbolTable.h"
10349cc55cSDimitry Andric #include "COFFLinkerContext.h"
110b57cec5SDimitry Andric #include "Config.h"
120b57cec5SDimitry Andric #include "Driver.h"
130b57cec5SDimitry Andric #include "LTO.h"
140b57cec5SDimitry Andric #include "PDB.h"
150b57cec5SDimitry Andric #include "Symbols.h"
160b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h"
170b57cec5SDimitry Andric #include "lld/Common/Memory.h"
180b57cec5SDimitry Andric #include "lld/Common/Timer.h"
190eae32dcSDimitry Andric #include "llvm/DebugInfo/DIContext.h"
200b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h"
21480093f4SDimitry Andric #include "llvm/LTO/LTO.h"
220b57cec5SDimitry Andric #include "llvm/Object/WindowsMachineFlag.h"
230b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
250b57cec5SDimitry Andric #include <utility>
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric using namespace llvm;
280b57cec5SDimitry Andric 
29bdd1243dSDimitry Andric namespace lld::coff {
300b57cec5SDimitry Andric 
31fe6060f1SDimitry Andric StringRef ltrim1(StringRef s, const char *chars) {
32fe6060f1SDimitry Andric   if (!s.empty() && strchr(chars, s[0]))
33fe6060f1SDimitry Andric     return s.substr(1);
34fe6060f1SDimitry Andric   return s;
35fe6060f1SDimitry Andric }
36fe6060f1SDimitry Andric 
37*06c3fb27SDimitry Andric static bool compatibleMachineType(COFFLinkerContext &ctx, MachineTypes mt) {
38*06c3fb27SDimitry Andric   if (mt == IMAGE_FILE_MACHINE_UNKNOWN)
39*06c3fb27SDimitry Andric     return true;
40*06c3fb27SDimitry Andric   switch (ctx.config.machine) {
41*06c3fb27SDimitry Andric   case ARM64:
42*06c3fb27SDimitry Andric     return mt == ARM64 || mt == ARM64X;
43*06c3fb27SDimitry Andric   case ARM64EC:
44*06c3fb27SDimitry Andric     return COFF::isArm64EC(mt) || mt == AMD64;
45*06c3fb27SDimitry Andric   case ARM64X:
46*06c3fb27SDimitry Andric     return COFF::isAnyArm64(mt) || mt == AMD64;
47*06c3fb27SDimitry Andric   default:
48*06c3fb27SDimitry Andric     return ctx.config.machine == mt;
49*06c3fb27SDimitry Andric   }
50*06c3fb27SDimitry Andric }
51*06c3fb27SDimitry Andric 
520b57cec5SDimitry Andric void SymbolTable::addFile(InputFile *file) {
530b57cec5SDimitry Andric   log("Reading " + toString(file));
5404eeddc0SDimitry Andric   if (file->lazy) {
5504eeddc0SDimitry Andric     if (auto *f = dyn_cast<BitcodeFile>(file))
5604eeddc0SDimitry Andric       f->parseLazy();
5704eeddc0SDimitry Andric     else
5804eeddc0SDimitry Andric       cast<ObjFile>(file)->parseLazy();
5904eeddc0SDimitry Andric   } else {
600b57cec5SDimitry Andric     file->parse();
6104eeddc0SDimitry Andric     if (auto *f = dyn_cast<ObjFile>(file)) {
6204eeddc0SDimitry Andric       ctx.objFileInstances.push_back(f);
6304eeddc0SDimitry Andric     } else if (auto *f = dyn_cast<BitcodeFile>(file)) {
6404eeddc0SDimitry Andric       ctx.bitcodeFileInstances.push_back(f);
6504eeddc0SDimitry Andric     } else if (auto *f = dyn_cast<ImportFile>(file)) {
6604eeddc0SDimitry Andric       ctx.importFileInstances.push_back(f);
6704eeddc0SDimitry Andric     }
6804eeddc0SDimitry Andric   }
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   MachineTypes mt = file->getMachineType();
71bdd1243dSDimitry Andric   if (ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN) {
72bdd1243dSDimitry Andric     ctx.config.machine = mt;
73bdd1243dSDimitry Andric     ctx.driver.addWinSysRootLibSearchPaths();
74*06c3fb27SDimitry Andric   } else if (!compatibleMachineType(ctx, mt)) {
750b57cec5SDimitry Andric     error(toString(file) + ": machine type " + machineToStr(mt) +
76bdd1243dSDimitry Andric           " conflicts with " + machineToStr(ctx.config.machine));
770b57cec5SDimitry Andric     return;
780b57cec5SDimitry Andric   }
790b57cec5SDimitry Andric 
80bdd1243dSDimitry Andric   ctx.driver.parseDirectives(file);
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric 
83bdd1243dSDimitry Andric static void errorOrWarn(const Twine &s, bool forceUnresolved) {
84bdd1243dSDimitry Andric   if (forceUnresolved)
850b57cec5SDimitry Andric     warn(s);
860b57cec5SDimitry Andric   else
870b57cec5SDimitry Andric     error(s);
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric 
9085868e8aSDimitry Andric // Causes the file associated with a lazy symbol to be linked in.
9185868e8aSDimitry Andric static void forceLazy(Symbol *s) {
9285868e8aSDimitry Andric   s->pendingArchiveLoad = true;
9385868e8aSDimitry Andric   switch (s->kind()) {
9485868e8aSDimitry Andric   case Symbol::Kind::LazyArchiveKind: {
9585868e8aSDimitry Andric     auto *l = cast<LazyArchive>(s);
9685868e8aSDimitry Andric     l->file->addMember(l->sym);
9785868e8aSDimitry Andric     break;
9885868e8aSDimitry Andric   }
9904eeddc0SDimitry Andric   case Symbol::Kind::LazyObjectKind: {
10004eeddc0SDimitry Andric     InputFile *file = cast<LazyObject>(s)->file;
10104eeddc0SDimitry Andric     file->ctx.symtab.addFile(file);
10285868e8aSDimitry Andric     break;
10304eeddc0SDimitry Andric   }
104fe6060f1SDimitry Andric   case Symbol::Kind::LazyDLLSymbolKind: {
105fe6060f1SDimitry Andric     auto *l = cast<LazyDLLSymbol>(s);
106fe6060f1SDimitry Andric     l->file->makeImport(l->sym);
107fe6060f1SDimitry Andric     break;
108fe6060f1SDimitry Andric   }
10985868e8aSDimitry Andric   default:
11085868e8aSDimitry Andric     llvm_unreachable(
11185868e8aSDimitry Andric         "symbol passed to forceLazy is not a LazyArchive or LazyObject");
11285868e8aSDimitry Andric   }
11385868e8aSDimitry Andric }
11485868e8aSDimitry Andric 
1150b57cec5SDimitry Andric // Returns the symbol in SC whose value is <= Addr that is closest to Addr.
1160b57cec5SDimitry Andric // This is generally the global variable or function whose definition contains
1170b57cec5SDimitry Andric // Addr.
1180b57cec5SDimitry Andric static Symbol *getSymbol(SectionChunk *sc, uint32_t addr) {
1190b57cec5SDimitry Andric   DefinedRegular *candidate = nullptr;
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   for (Symbol *s : sc->file->getSymbols()) {
1220b57cec5SDimitry Andric     auto *d = dyn_cast_or_null<DefinedRegular>(s);
12385868e8aSDimitry Andric     if (!d || !d->data || d->file != sc->file || d->getChunk() != sc ||
12485868e8aSDimitry Andric         d->getValue() > addr ||
1250b57cec5SDimitry Andric         (candidate && d->getValue() < candidate->getValue()))
1260b57cec5SDimitry Andric       continue;
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric     candidate = d;
1290b57cec5SDimitry Andric   }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   return candidate;
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric 
13485868e8aSDimitry Andric static std::vector<std::string> getSymbolLocations(BitcodeFile *file) {
13585868e8aSDimitry Andric   std::string res("\n>>> referenced by ");
13685868e8aSDimitry Andric   StringRef source = file->obj->getSourceFileName();
13785868e8aSDimitry Andric   if (!source.empty())
13885868e8aSDimitry Andric     res += source.str() + "\n>>>               ";
13985868e8aSDimitry Andric   res += toString(file);
14085868e8aSDimitry Andric   return {res};
14185868e8aSDimitry Andric }
14285868e8aSDimitry Andric 
143bdd1243dSDimitry Andric static std::optional<std::pair<StringRef, uint32_t>>
14485868e8aSDimitry Andric getFileLineDwarf(const SectionChunk *c, uint32_t addr) {
145bdd1243dSDimitry Andric   std::optional<DILineInfo> optionalLineInfo =
14685868e8aSDimitry Andric       c->file->getDILineInfo(addr, c->getSectionNumber() - 1);
14785868e8aSDimitry Andric   if (!optionalLineInfo)
148bdd1243dSDimitry Andric     return std::nullopt;
14985868e8aSDimitry Andric   const DILineInfo &lineInfo = *optionalLineInfo;
15085868e8aSDimitry Andric   if (lineInfo.FileName == DILineInfo::BadString)
151bdd1243dSDimitry Andric     return std::nullopt;
15204eeddc0SDimitry Andric   return std::make_pair(saver().save(lineInfo.FileName), lineInfo.Line);
15385868e8aSDimitry Andric }
15485868e8aSDimitry Andric 
155bdd1243dSDimitry Andric static std::optional<std::pair<StringRef, uint32_t>>
15685868e8aSDimitry Andric getFileLine(const SectionChunk *c, uint32_t addr) {
15785868e8aSDimitry Andric   // MinGW can optionally use codeview, even if the default is dwarf.
158bdd1243dSDimitry Andric   std::optional<std::pair<StringRef, uint32_t>> fileLine =
15985868e8aSDimitry Andric       getFileLineCodeView(c, addr);
16085868e8aSDimitry Andric   // If codeview didn't yield any result, check dwarf in MinGW mode.
161bdd1243dSDimitry Andric   if (!fileLine && c->file->ctx.config.mingw)
16285868e8aSDimitry Andric     fileLine = getFileLineDwarf(c, addr);
16385868e8aSDimitry Andric   return fileLine;
16485868e8aSDimitry Andric }
16585868e8aSDimitry Andric 
1660b57cec5SDimitry Andric // Given a file and the index of a symbol in that file, returns a description
1670b57cec5SDimitry Andric // of all references to that symbol from that file. If no debug information is
1680b57cec5SDimitry Andric // available, returns just the name of the file, else one string per actual
1690b57cec5SDimitry Andric // reference as described in the debug info.
170590d96feSDimitry Andric // Returns up to maxStrings string descriptions, along with the total number of
171590d96feSDimitry Andric // locations found.
172590d96feSDimitry Andric static std::pair<std::vector<std::string>, size_t>
173590d96feSDimitry Andric getSymbolLocations(ObjFile *file, uint32_t symIndex, size_t maxStrings) {
1740b57cec5SDimitry Andric   struct Location {
1750b57cec5SDimitry Andric     Symbol *sym;
1760b57cec5SDimitry Andric     std::pair<StringRef, uint32_t> fileLine;
1770b57cec5SDimitry Andric   };
1780b57cec5SDimitry Andric   std::vector<Location> locations;
179590d96feSDimitry Andric   size_t numLocations = 0;
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric   for (Chunk *c : file->getChunks()) {
1820b57cec5SDimitry Andric     auto *sc = dyn_cast<SectionChunk>(c);
1830b57cec5SDimitry Andric     if (!sc)
1840b57cec5SDimitry Andric       continue;
1850b57cec5SDimitry Andric     for (const coff_relocation &r : sc->getRelocs()) {
1860b57cec5SDimitry Andric       if (r.SymbolTableIndex != symIndex)
1870b57cec5SDimitry Andric         continue;
188590d96feSDimitry Andric       numLocations++;
189590d96feSDimitry Andric       if (locations.size() >= maxStrings)
190590d96feSDimitry Andric         continue;
191590d96feSDimitry Andric 
192bdd1243dSDimitry Andric       std::optional<std::pair<StringRef, uint32_t>> fileLine =
1930b57cec5SDimitry Andric           getFileLine(sc, r.VirtualAddress);
1940b57cec5SDimitry Andric       Symbol *sym = getSymbol(sc, r.VirtualAddress);
19585868e8aSDimitry Andric       if (fileLine)
19685868e8aSDimitry Andric         locations.push_back({sym, *fileLine});
19785868e8aSDimitry Andric       else if (sym)
19885868e8aSDimitry Andric         locations.push_back({sym, {"", 0}});
1990b57cec5SDimitry Andric     }
2000b57cec5SDimitry Andric   }
2010b57cec5SDimitry Andric 
202590d96feSDimitry Andric   if (maxStrings == 0)
203590d96feSDimitry Andric     return std::make_pair(std::vector<std::string>(), numLocations);
204590d96feSDimitry Andric 
205590d96feSDimitry Andric   if (numLocations == 0)
206590d96feSDimitry Andric     return std::make_pair(
207590d96feSDimitry Andric         std::vector<std::string>{"\n>>> referenced by " + toString(file)}, 1);
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric   std::vector<std::string> symbolLocations(locations.size());
2100b57cec5SDimitry Andric   size_t i = 0;
2110b57cec5SDimitry Andric   for (Location loc : locations) {
2120b57cec5SDimitry Andric     llvm::raw_string_ostream os(symbolLocations[i++]);
2130b57cec5SDimitry Andric     os << "\n>>> referenced by ";
2140b57cec5SDimitry Andric     if (!loc.fileLine.first.empty())
2150b57cec5SDimitry Andric       os << loc.fileLine.first << ":" << loc.fileLine.second
2160b57cec5SDimitry Andric          << "\n>>>               ";
2170b57cec5SDimitry Andric     os << toString(file);
2180b57cec5SDimitry Andric     if (loc.sym)
219bdd1243dSDimitry Andric       os << ":(" << toString(file->ctx, *loc.sym) << ')';
2200b57cec5SDimitry Andric   }
221590d96feSDimitry Andric   return std::make_pair(symbolLocations, numLocations);
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric 
224590d96feSDimitry Andric std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {
225590d96feSDimitry Andric   return getSymbolLocations(file, symIndex, SIZE_MAX).first;
226590d96feSDimitry Andric }
227590d96feSDimitry Andric 
228590d96feSDimitry Andric static std::pair<std::vector<std::string>, size_t>
229590d96feSDimitry Andric getSymbolLocations(InputFile *file, uint32_t symIndex, size_t maxStrings) {
23085868e8aSDimitry Andric   if (auto *o = dyn_cast<ObjFile>(file))
231590d96feSDimitry Andric     return getSymbolLocations(o, symIndex, maxStrings);
232590d96feSDimitry Andric   if (auto *b = dyn_cast<BitcodeFile>(file)) {
233590d96feSDimitry Andric     std::vector<std::string> symbolLocations = getSymbolLocations(b);
234590d96feSDimitry Andric     size_t numLocations = symbolLocations.size();
235590d96feSDimitry Andric     if (symbolLocations.size() > maxStrings)
236590d96feSDimitry Andric       symbolLocations.resize(maxStrings);
237590d96feSDimitry Andric     return std::make_pair(symbolLocations, numLocations);
238590d96feSDimitry Andric   }
23985868e8aSDimitry Andric   llvm_unreachable("unsupported file type passed to getSymbolLocations");
240590d96feSDimitry Andric   return std::make_pair(std::vector<std::string>(), (size_t)0);
24185868e8aSDimitry Andric }
24285868e8aSDimitry Andric 
2430b57cec5SDimitry Andric // For an undefined symbol, stores all files referencing it and the index of
2440b57cec5SDimitry Andric // the undefined symbol in each file.
2450b57cec5SDimitry Andric struct UndefinedDiag {
2460b57cec5SDimitry Andric   Symbol *sym;
2470b57cec5SDimitry Andric   struct File {
24885868e8aSDimitry Andric     InputFile *file;
24985868e8aSDimitry Andric     uint32_t symIndex;
2500b57cec5SDimitry Andric   };
2510b57cec5SDimitry Andric   std::vector<File> files;
2520b57cec5SDimitry Andric };
2530b57cec5SDimitry Andric 
254bdd1243dSDimitry Andric static void reportUndefinedSymbol(const COFFLinkerContext &ctx,
255bdd1243dSDimitry Andric                                   const UndefinedDiag &undefDiag) {
2560b57cec5SDimitry Andric   std::string out;
2570b57cec5SDimitry Andric   llvm::raw_string_ostream os(out);
258bdd1243dSDimitry Andric   os << "undefined symbol: " << toString(ctx, *undefDiag.sym);
2590b57cec5SDimitry Andric 
2605ffd83dbSDimitry Andric   const size_t maxUndefReferences = 3;
261590d96feSDimitry Andric   size_t numDisplayedRefs = 0, numRefs = 0;
2620b57cec5SDimitry Andric   for (const UndefinedDiag::File &ref : undefDiag.files) {
263bdd1243dSDimitry Andric     auto [symbolLocations, totalLocations] = getSymbolLocations(
264590d96feSDimitry Andric         ref.file, ref.symIndex, maxUndefReferences - numDisplayedRefs);
265590d96feSDimitry Andric 
266590d96feSDimitry Andric     numRefs += totalLocations;
267590d96feSDimitry Andric     numDisplayedRefs += symbolLocations.size();
2680b57cec5SDimitry Andric     for (const std::string &s : symbolLocations) {
2690b57cec5SDimitry Andric       os << s;
2700b57cec5SDimitry Andric     }
2710b57cec5SDimitry Andric   }
272590d96feSDimitry Andric   if (numDisplayedRefs < numRefs)
273590d96feSDimitry Andric     os << "\n>>> referenced " << numRefs - numDisplayedRefs << " more times";
274bdd1243dSDimitry Andric   errorOrWarn(os.str(), ctx.config.forceUnresolved);
2750b57cec5SDimitry Andric }
2760b57cec5SDimitry Andric 
277fe6060f1SDimitry Andric void SymbolTable::loadMinGWSymbols() {
2780b57cec5SDimitry Andric   for (auto &i : symMap) {
2790b57cec5SDimitry Andric     Symbol *sym = i.second;
2800b57cec5SDimitry Andric     auto *undef = dyn_cast<Undefined>(sym);
2810b57cec5SDimitry Andric     if (!undef)
2820b57cec5SDimitry Andric       continue;
28385868e8aSDimitry Andric     if (undef->getWeakAlias())
28485868e8aSDimitry Andric       continue;
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric     StringRef name = undef->getName();
2870b57cec5SDimitry Andric 
288bdd1243dSDimitry Andric     if (ctx.config.machine == I386 && ctx.config.stdcallFixup) {
289fe6060f1SDimitry Andric       // Check if we can resolve an undefined decorated symbol by finding
290349cc55cSDimitry Andric       // the intended target as an undecorated symbol (only with a leading
291fe6060f1SDimitry Andric       // underscore).
292fe6060f1SDimitry Andric       StringRef origName = name;
293fe6060f1SDimitry Andric       StringRef baseName = name;
294fe6060f1SDimitry Andric       // Trim down stdcall/fastcall/vectorcall symbols to the base name.
295fe6060f1SDimitry Andric       baseName = ltrim1(baseName, "_@");
296fe6060f1SDimitry Andric       baseName = baseName.substr(0, baseName.find('@'));
297fe6060f1SDimitry Andric       // Add a leading underscore, as it would be in cdecl form.
298fe6060f1SDimitry Andric       std::string newName = ("_" + baseName).str();
299fe6060f1SDimitry Andric       Symbol *l;
300fe6060f1SDimitry Andric       if (newName != origName && (l = find(newName)) != nullptr) {
301fe6060f1SDimitry Andric         // If we found a symbol and it is lazy; load it.
302fe6060f1SDimitry Andric         if (l->isLazy() && !l->pendingArchiveLoad) {
303fe6060f1SDimitry Andric           log("Loading lazy " + l->getName() + " from " +
304fe6060f1SDimitry Andric               l->getFile()->getName() + " for stdcall fixup");
305fe6060f1SDimitry Andric           forceLazy(l);
306fe6060f1SDimitry Andric         }
307fe6060f1SDimitry Andric         // If it's lazy or already defined, hook it up as weak alias.
308fe6060f1SDimitry Andric         if (l->isLazy() || isa<Defined>(l)) {
309bdd1243dSDimitry Andric           if (ctx.config.warnStdcallFixup)
310fe6060f1SDimitry Andric             warn("Resolving " + origName + " by linking to " + newName);
311fe6060f1SDimitry Andric           else
312fe6060f1SDimitry Andric             log("Resolving " + origName + " by linking to " + newName);
313fe6060f1SDimitry Andric           undef->weakAlias = l;
314fe6060f1SDimitry Andric           continue;
315fe6060f1SDimitry Andric         }
316fe6060f1SDimitry Andric       }
317fe6060f1SDimitry Andric     }
318fe6060f1SDimitry Andric 
319bdd1243dSDimitry Andric     if (ctx.config.autoImport) {
320*06c3fb27SDimitry Andric       if (name.starts_with("__imp_"))
3210b57cec5SDimitry Andric         continue;
32285868e8aSDimitry Andric       // If we have an undefined symbol, but we have a lazy symbol we could
32385868e8aSDimitry Andric       // load, load it.
32485868e8aSDimitry Andric       Symbol *l = find(("__imp_" + name).str());
32585868e8aSDimitry Andric       if (!l || l->pendingArchiveLoad || !l->isLazy())
3260b57cec5SDimitry Andric         continue;
3270b57cec5SDimitry Andric 
32885868e8aSDimitry Andric       log("Loading lazy " + l->getName() + " from " + l->getFile()->getName() +
3290b57cec5SDimitry Andric           " for automatic import");
33085868e8aSDimitry Andric       forceLazy(l);
3310b57cec5SDimitry Andric     }
3320b57cec5SDimitry Andric   }
333fe6060f1SDimitry Andric }
3340b57cec5SDimitry Andric 
33585868e8aSDimitry Andric Defined *SymbolTable::impSymbol(StringRef name) {
336*06c3fb27SDimitry Andric   if (name.starts_with("__imp_"))
33785868e8aSDimitry Andric     return nullptr;
33885868e8aSDimitry Andric   return dyn_cast_or_null<Defined>(find(("__imp_" + name).str()));
33985868e8aSDimitry Andric }
34085868e8aSDimitry Andric 
3410b57cec5SDimitry Andric bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {
34285868e8aSDimitry Andric   Defined *imp = impSymbol(name);
3430b57cec5SDimitry Andric   if (!imp)
3440b57cec5SDimitry Andric     return false;
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric   // Replace the reference directly to a variable with a reference
3470b57cec5SDimitry Andric   // to the import address table instead. This obviously isn't right,
3480b57cec5SDimitry Andric   // but we mark the symbol as isRuntimePseudoReloc, and a later pass
3490b57cec5SDimitry Andric   // will add runtime pseudo relocations for every relocation against
3500b57cec5SDimitry Andric   // this Symbol. The runtime pseudo relocation framework expects the
3510b57cec5SDimitry Andric   // reference itself to point at the IAT entry.
3520b57cec5SDimitry Andric   size_t impSize = 0;
3530b57cec5SDimitry Andric   if (isa<DefinedImportData>(imp)) {
3540b57cec5SDimitry Andric     log("Automatically importing " + name + " from " +
3550b57cec5SDimitry Andric         cast<DefinedImportData>(imp)->getDLLName());
3560b57cec5SDimitry Andric     impSize = sizeof(DefinedImportData);
3570b57cec5SDimitry Andric   } else if (isa<DefinedRegular>(imp)) {
3580b57cec5SDimitry Andric     log("Automatically importing " + name + " from " +
3590b57cec5SDimitry Andric         toString(cast<DefinedRegular>(imp)->file));
3600b57cec5SDimitry Andric     impSize = sizeof(DefinedRegular);
3610b57cec5SDimitry Andric   } else {
3620b57cec5SDimitry Andric     warn("unable to automatically import " + name + " from " + imp->getName() +
3630b57cec5SDimitry Andric          " from " + toString(cast<DefinedRegular>(imp)->file) +
3640b57cec5SDimitry Andric          "; unexpected symbol type");
3650b57cec5SDimitry Andric     return false;
3660b57cec5SDimitry Andric   }
3670b57cec5SDimitry Andric   sym->replaceKeepingName(imp, impSize);
3680b57cec5SDimitry Andric   sym->isRuntimePseudoReloc = true;
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric   // There may exist symbols named .refptr.<name> which only consist
3710b57cec5SDimitry Andric   // of a single pointer to <name>. If it turns out <name> is
3720b57cec5SDimitry Andric   // automatically imported, we don't need to keep the .refptr.<name>
3730b57cec5SDimitry Andric   // pointer at all, but redirect all accesses to it to the IAT entry
3740b57cec5SDimitry Andric   // for __imp_<name> instead, and drop the whole .refptr.<name> chunk.
3750b57cec5SDimitry Andric   DefinedRegular *refptr =
3760b57cec5SDimitry Andric       dyn_cast_or_null<DefinedRegular>(find((".refptr." + name).str()));
377bdd1243dSDimitry Andric   if (refptr && refptr->getChunk()->getSize() == ctx.config.wordsize) {
3780b57cec5SDimitry Andric     SectionChunk *sc = dyn_cast_or_null<SectionChunk>(refptr->getChunk());
3790b57cec5SDimitry Andric     if (sc && sc->getRelocs().size() == 1 && *sc->symbols().begin() == sym) {
3800b57cec5SDimitry Andric       log("Replacing .refptr." + name + " with " + imp->getName());
3810b57cec5SDimitry Andric       refptr->getChunk()->live = false;
3820b57cec5SDimitry Andric       refptr->replaceKeepingName(imp, impSize);
3830b57cec5SDimitry Andric     }
3840b57cec5SDimitry Andric   }
3850b57cec5SDimitry Andric   return true;
3860b57cec5SDimitry Andric }
3870b57cec5SDimitry Andric 
38885868e8aSDimitry Andric /// Helper function for reportUnresolvable and resolveRemainingUndefines.
38985868e8aSDimitry Andric /// This function emits an "undefined symbol" diagnostic for each symbol in
39085868e8aSDimitry Andric /// undefs. If localImports is not nullptr, it also emits a "locally
39185868e8aSDimitry Andric /// defined symbol imported" diagnostic for symbols in localImports.
39285868e8aSDimitry Andric /// objFiles and bitcodeFiles (if not nullptr) are used to report where
39385868e8aSDimitry Andric /// undefined symbols are referenced.
394349cc55cSDimitry Andric static void reportProblemSymbols(
395349cc55cSDimitry Andric     const COFFLinkerContext &ctx, const SmallPtrSetImpl<Symbol *> &undefs,
396349cc55cSDimitry Andric     const DenseMap<Symbol *, Symbol *> *localImports, bool needBitcodeFiles) {
39785868e8aSDimitry Andric   // Return early if there is nothing to report (which should be
39885868e8aSDimitry Andric   // the common case).
39985868e8aSDimitry Andric   if (undefs.empty() && (!localImports || localImports->empty()))
40085868e8aSDimitry Andric     return;
40185868e8aSDimitry Andric 
402bdd1243dSDimitry Andric   for (Symbol *b : ctx.config.gcroot) {
40385868e8aSDimitry Andric     if (undefs.count(b))
404bdd1243dSDimitry Andric       errorOrWarn("<root>: undefined symbol: " + toString(ctx, *b),
405bdd1243dSDimitry Andric                   ctx.config.forceUnresolved);
40685868e8aSDimitry Andric     if (localImports)
40785868e8aSDimitry Andric       if (Symbol *imp = localImports->lookup(b))
408bdd1243dSDimitry Andric         warn("<root>: locally defined symbol imported: " + toString(ctx, *imp) +
40985868e8aSDimitry Andric              " (defined in " + toString(imp->getFile()) + ") [LNK4217]");
41085868e8aSDimitry Andric   }
41185868e8aSDimitry Andric 
41285868e8aSDimitry Andric   std::vector<UndefinedDiag> undefDiags;
41385868e8aSDimitry Andric   DenseMap<Symbol *, int> firstDiag;
41485868e8aSDimitry Andric 
41585868e8aSDimitry Andric   auto processFile = [&](InputFile *file, ArrayRef<Symbol *> symbols) {
41685868e8aSDimitry Andric     uint32_t symIndex = (uint32_t)-1;
41785868e8aSDimitry Andric     for (Symbol *sym : symbols) {
41885868e8aSDimitry Andric       ++symIndex;
41985868e8aSDimitry Andric       if (!sym)
42085868e8aSDimitry Andric         continue;
42185868e8aSDimitry Andric       if (undefs.count(sym)) {
42285868e8aSDimitry Andric         auto it = firstDiag.find(sym);
42385868e8aSDimitry Andric         if (it == firstDiag.end()) {
42485868e8aSDimitry Andric           firstDiag[sym] = undefDiags.size();
42585868e8aSDimitry Andric           undefDiags.push_back({sym, {{file, symIndex}}});
42685868e8aSDimitry Andric         } else {
42785868e8aSDimitry Andric           undefDiags[it->second].files.push_back({file, symIndex});
42885868e8aSDimitry Andric         }
42985868e8aSDimitry Andric       }
43085868e8aSDimitry Andric       if (localImports)
43185868e8aSDimitry Andric         if (Symbol *imp = localImports->lookup(sym))
43285868e8aSDimitry Andric           warn(toString(file) +
433bdd1243dSDimitry Andric                ": locally defined symbol imported: " + toString(ctx, *imp) +
43485868e8aSDimitry Andric                " (defined in " + toString(imp->getFile()) + ") [LNK4217]");
43585868e8aSDimitry Andric     }
43685868e8aSDimitry Andric   };
43785868e8aSDimitry Andric 
438349cc55cSDimitry Andric   for (ObjFile *file : ctx.objFileInstances)
43985868e8aSDimitry Andric     processFile(file, file->getSymbols());
44085868e8aSDimitry Andric 
441349cc55cSDimitry Andric   if (needBitcodeFiles)
442349cc55cSDimitry Andric     for (BitcodeFile *file : ctx.bitcodeFileInstances)
44385868e8aSDimitry Andric       processFile(file, file->getSymbols());
44485868e8aSDimitry Andric 
44585868e8aSDimitry Andric   for (const UndefinedDiag &undefDiag : undefDiags)
446bdd1243dSDimitry Andric     reportUndefinedSymbol(ctx, undefDiag);
44785868e8aSDimitry Andric }
44885868e8aSDimitry Andric 
44985868e8aSDimitry Andric void SymbolTable::reportUnresolvable() {
45085868e8aSDimitry Andric   SmallPtrSet<Symbol *, 8> undefs;
45185868e8aSDimitry Andric   for (auto &i : symMap) {
45285868e8aSDimitry Andric     Symbol *sym = i.second;
45385868e8aSDimitry Andric     auto *undef = dyn_cast<Undefined>(sym);
454e8d8bef9SDimitry Andric     if (!undef || sym->deferUndefined)
45585868e8aSDimitry Andric       continue;
45685868e8aSDimitry Andric     if (undef->getWeakAlias())
45785868e8aSDimitry Andric       continue;
45885868e8aSDimitry Andric     StringRef name = undef->getName();
459*06c3fb27SDimitry Andric     if (name.starts_with("__imp_")) {
46085868e8aSDimitry Andric       Symbol *imp = find(name.substr(strlen("__imp_")));
46185868e8aSDimitry Andric       if (imp && isa<Defined>(imp))
46285868e8aSDimitry Andric         continue;
46385868e8aSDimitry Andric     }
46485868e8aSDimitry Andric     if (name.contains("_PchSym_"))
46585868e8aSDimitry Andric       continue;
466bdd1243dSDimitry Andric     if (ctx.config.autoImport && impSymbol(name))
46785868e8aSDimitry Andric       continue;
46885868e8aSDimitry Andric     undefs.insert(sym);
46985868e8aSDimitry Andric   }
47085868e8aSDimitry Andric 
471349cc55cSDimitry Andric   reportProblemSymbols(ctx, undefs,
472349cc55cSDimitry Andric                        /* localImports */ nullptr, true);
47385868e8aSDimitry Andric }
47485868e8aSDimitry Andric 
47585868e8aSDimitry Andric void SymbolTable::resolveRemainingUndefines() {
4760b57cec5SDimitry Andric   SmallPtrSet<Symbol *, 8> undefs;
4770b57cec5SDimitry Andric   DenseMap<Symbol *, Symbol *> localImports;
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric   for (auto &i : symMap) {
4800b57cec5SDimitry Andric     Symbol *sym = i.second;
4810b57cec5SDimitry Andric     auto *undef = dyn_cast<Undefined>(sym);
4820b57cec5SDimitry Andric     if (!undef)
4830b57cec5SDimitry Andric       continue;
4840b57cec5SDimitry Andric     if (!sym->isUsedInRegularObj)
4850b57cec5SDimitry Andric       continue;
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric     StringRef name = undef->getName();
4880b57cec5SDimitry Andric 
4890b57cec5SDimitry Andric     // A weak alias may have been resolved, so check for that.
4900b57cec5SDimitry Andric     if (Defined *d = undef->getWeakAlias()) {
4910b57cec5SDimitry Andric       // We want to replace Sym with D. However, we can't just blindly
4920b57cec5SDimitry Andric       // copy sizeof(SymbolUnion) bytes from D to Sym because D may be an
4930b57cec5SDimitry Andric       // internal symbol, and internal symbols are stored as "unparented"
4940b57cec5SDimitry Andric       // Symbols. For that reason we need to check which type of symbol we
4950b57cec5SDimitry Andric       // are dealing with and copy the correct number of bytes.
4960b57cec5SDimitry Andric       if (isa<DefinedRegular>(d))
4970b57cec5SDimitry Andric         memcpy(sym, d, sizeof(DefinedRegular));
4980b57cec5SDimitry Andric       else if (isa<DefinedAbsolute>(d))
4990b57cec5SDimitry Andric         memcpy(sym, d, sizeof(DefinedAbsolute));
5000b57cec5SDimitry Andric       else
5010b57cec5SDimitry Andric         memcpy(sym, d, sizeof(SymbolUnion));
5020b57cec5SDimitry Andric       continue;
5030b57cec5SDimitry Andric     }
5040b57cec5SDimitry Andric 
5050b57cec5SDimitry Andric     // If we can resolve a symbol by removing __imp_ prefix, do that.
5060b57cec5SDimitry Andric     // This odd rule is for compatibility with MSVC linker.
507*06c3fb27SDimitry Andric     if (name.starts_with("__imp_")) {
5080b57cec5SDimitry Andric       Symbol *imp = find(name.substr(strlen("__imp_")));
5090b57cec5SDimitry Andric       if (imp && isa<Defined>(imp)) {
5100b57cec5SDimitry Andric         auto *d = cast<Defined>(imp);
511bdd1243dSDimitry Andric         replaceSymbol<DefinedLocalImport>(sym, ctx, name, d);
5120b57cec5SDimitry Andric         localImportChunks.push_back(cast<DefinedLocalImport>(sym)->getChunk());
5130b57cec5SDimitry Andric         localImports[sym] = d;
5140b57cec5SDimitry Andric         continue;
5150b57cec5SDimitry Andric       }
5160b57cec5SDimitry Andric     }
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric     // We don't want to report missing Microsoft precompiled headers symbols.
5190b57cec5SDimitry Andric     // A proper message will be emitted instead in PDBLinker::aquirePrecompObj
5200b57cec5SDimitry Andric     if (name.contains("_PchSym_"))
5210b57cec5SDimitry Andric       continue;
5220b57cec5SDimitry Andric 
523bdd1243dSDimitry Andric     if (ctx.config.autoImport && handleMinGWAutomaticImport(sym, name))
5240b57cec5SDimitry Andric       continue;
5250b57cec5SDimitry Andric 
5260b57cec5SDimitry Andric     // Remaining undefined symbols are not fatal if /force is specified.
5270b57cec5SDimitry Andric     // They are replaced with dummy defined symbols.
528bdd1243dSDimitry Andric     if (ctx.config.forceUnresolved)
529bdd1243dSDimitry Andric       replaceSymbol<DefinedAbsolute>(sym, ctx, name, 0);
5300b57cec5SDimitry Andric     undefs.insert(sym);
5310b57cec5SDimitry Andric   }
5320b57cec5SDimitry Andric 
53385868e8aSDimitry Andric   reportProblemSymbols(
534bdd1243dSDimitry Andric       ctx, undefs,
535bdd1243dSDimitry Andric       ctx.config.warnLocallyDefinedImported ? &localImports : nullptr, false);
5360b57cec5SDimitry Andric }
5370b57cec5SDimitry Andric 
5380b57cec5SDimitry Andric std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
5390b57cec5SDimitry Andric   bool inserted = false;
5400b57cec5SDimitry Andric   Symbol *&sym = symMap[CachedHashStringRef(name)];
5410b57cec5SDimitry Andric   if (!sym) {
5420b57cec5SDimitry Andric     sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
5430b57cec5SDimitry Andric     sym->isUsedInRegularObj = false;
5440b57cec5SDimitry Andric     sym->pendingArchiveLoad = false;
545e8d8bef9SDimitry Andric     sym->canInline = true;
5460b57cec5SDimitry Andric     inserted = true;
5470b57cec5SDimitry Andric   }
5480b57cec5SDimitry Andric   return {sym, inserted};
5490b57cec5SDimitry Andric }
5500b57cec5SDimitry Andric 
5510b57cec5SDimitry Andric std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, InputFile *file) {
5520b57cec5SDimitry Andric   std::pair<Symbol *, bool> result = insert(name);
5530b57cec5SDimitry Andric   if (!file || !isa<BitcodeFile>(file))
5540b57cec5SDimitry Andric     result.first->isUsedInRegularObj = true;
5550b57cec5SDimitry Andric   return result;
5560b57cec5SDimitry Andric }
5570b57cec5SDimitry Andric 
5580b57cec5SDimitry Andric Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f,
5590b57cec5SDimitry Andric                                   bool isWeakAlias) {
560bdd1243dSDimitry Andric   auto [s, wasInserted] = insert(name, f);
56185868e8aSDimitry Andric   if (wasInserted || (s->isLazy() && isWeakAlias)) {
5620b57cec5SDimitry Andric     replaceSymbol<Undefined>(s, name);
5630b57cec5SDimitry Andric     return s;
5640b57cec5SDimitry Andric   }
56585868e8aSDimitry Andric   if (s->isLazy())
56685868e8aSDimitry Andric     forceLazy(s);
5670b57cec5SDimitry Andric   return s;
5680b57cec5SDimitry Andric }
5690b57cec5SDimitry Andric 
57085868e8aSDimitry Andric void SymbolTable::addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym) {
5710b57cec5SDimitry Andric   StringRef name = sym.getName();
572bdd1243dSDimitry Andric   auto [s, wasInserted] = insert(name);
5730b57cec5SDimitry Andric   if (wasInserted) {
57485868e8aSDimitry Andric     replaceSymbol<LazyArchive>(s, f, sym);
5750b57cec5SDimitry Andric     return;
5760b57cec5SDimitry Andric   }
5770b57cec5SDimitry Andric   auto *u = dyn_cast<Undefined>(s);
5780b57cec5SDimitry Andric   if (!u || u->weakAlias || s->pendingArchiveLoad)
5790b57cec5SDimitry Andric     return;
5800b57cec5SDimitry Andric   s->pendingArchiveLoad = true;
5810b57cec5SDimitry Andric   f->addMember(sym);
5820b57cec5SDimitry Andric }
5830b57cec5SDimitry Andric 
58404eeddc0SDimitry Andric void SymbolTable::addLazyObject(InputFile *f, StringRef n) {
58504eeddc0SDimitry Andric   assert(f->lazy);
586bdd1243dSDimitry Andric   auto [s, wasInserted] = insert(n, f);
58785868e8aSDimitry Andric   if (wasInserted) {
58885868e8aSDimitry Andric     replaceSymbol<LazyObject>(s, f, n);
58985868e8aSDimitry Andric     return;
59085868e8aSDimitry Andric   }
59185868e8aSDimitry Andric   auto *u = dyn_cast<Undefined>(s);
59285868e8aSDimitry Andric   if (!u || u->weakAlias || s->pendingArchiveLoad)
59385868e8aSDimitry Andric     return;
59485868e8aSDimitry Andric   s->pendingArchiveLoad = true;
59504eeddc0SDimitry Andric   f->lazy = false;
59604eeddc0SDimitry Andric   addFile(f);
59785868e8aSDimitry Andric }
59885868e8aSDimitry Andric 
599fe6060f1SDimitry Andric void SymbolTable::addLazyDLLSymbol(DLLFile *f, DLLFile::Symbol *sym,
600fe6060f1SDimitry Andric                                    StringRef n) {
601bdd1243dSDimitry Andric   auto [s, wasInserted] = insert(n);
602fe6060f1SDimitry Andric   if (wasInserted) {
603fe6060f1SDimitry Andric     replaceSymbol<LazyDLLSymbol>(s, f, sym, n);
604fe6060f1SDimitry Andric     return;
605fe6060f1SDimitry Andric   }
606fe6060f1SDimitry Andric   auto *u = dyn_cast<Undefined>(s);
607fe6060f1SDimitry Andric   if (!u || u->weakAlias || s->pendingArchiveLoad)
608fe6060f1SDimitry Andric     return;
609fe6060f1SDimitry Andric   s->pendingArchiveLoad = true;
610fe6060f1SDimitry Andric   f->makeImport(sym);
611fe6060f1SDimitry Andric }
612fe6060f1SDimitry Andric 
61385868e8aSDimitry Andric static std::string getSourceLocationBitcode(BitcodeFile *file) {
61485868e8aSDimitry Andric   std::string res("\n>>> defined at ");
61585868e8aSDimitry Andric   StringRef source = file->obj->getSourceFileName();
61685868e8aSDimitry Andric   if (!source.empty())
61785868e8aSDimitry Andric     res += source.str() + "\n>>>            ";
61885868e8aSDimitry Andric   res += toString(file);
61985868e8aSDimitry Andric   return res;
62085868e8aSDimitry Andric }
62185868e8aSDimitry Andric 
62285868e8aSDimitry Andric static std::string getSourceLocationObj(ObjFile *file, SectionChunk *sc,
62385868e8aSDimitry Andric                                         uint32_t offset, StringRef name) {
624bdd1243dSDimitry Andric   std::optional<std::pair<StringRef, uint32_t>> fileLine;
62585868e8aSDimitry Andric   if (sc)
62685868e8aSDimitry Andric     fileLine = getFileLine(sc, offset);
62785868e8aSDimitry Andric   if (!fileLine)
62885868e8aSDimitry Andric     fileLine = file->getVariableLocation(name);
62985868e8aSDimitry Andric 
63085868e8aSDimitry Andric   std::string res;
63185868e8aSDimitry Andric   llvm::raw_string_ostream os(res);
63285868e8aSDimitry Andric   os << "\n>>> defined at ";
63385868e8aSDimitry Andric   if (fileLine)
63485868e8aSDimitry Andric     os << fileLine->first << ":" << fileLine->second << "\n>>>            ";
63585868e8aSDimitry Andric   os << toString(file);
63685868e8aSDimitry Andric   return os.str();
63785868e8aSDimitry Andric }
63885868e8aSDimitry Andric 
63985868e8aSDimitry Andric static std::string getSourceLocation(InputFile *file, SectionChunk *sc,
64085868e8aSDimitry Andric                                      uint32_t offset, StringRef name) {
641480093f4SDimitry Andric   if (!file)
642480093f4SDimitry Andric     return "";
64385868e8aSDimitry Andric   if (auto *o = dyn_cast<ObjFile>(file))
64485868e8aSDimitry Andric     return getSourceLocationObj(o, sc, offset, name);
64585868e8aSDimitry Andric   if (auto *b = dyn_cast<BitcodeFile>(file))
64685868e8aSDimitry Andric     return getSourceLocationBitcode(b);
64785868e8aSDimitry Andric   return "\n>>> defined at " + toString(file);
64885868e8aSDimitry Andric }
64985868e8aSDimitry Andric 
65085868e8aSDimitry Andric // Construct and print an error message in the form of:
65185868e8aSDimitry Andric //
65285868e8aSDimitry Andric //   lld-link: error: duplicate symbol: foo
65385868e8aSDimitry Andric //   >>> defined at bar.c:30
65485868e8aSDimitry Andric //   >>>            bar.o
65585868e8aSDimitry Andric //   >>> defined at baz.c:563
65685868e8aSDimitry Andric //   >>>            baz.o
65785868e8aSDimitry Andric void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile,
65885868e8aSDimitry Andric                                   SectionChunk *newSc,
65985868e8aSDimitry Andric                                   uint32_t newSectionOffset) {
66085868e8aSDimitry Andric   std::string msg;
66185868e8aSDimitry Andric   llvm::raw_string_ostream os(msg);
662bdd1243dSDimitry Andric   os << "duplicate symbol: " << toString(ctx, *existing);
66385868e8aSDimitry Andric 
664480093f4SDimitry Andric   DefinedRegular *d = dyn_cast<DefinedRegular>(existing);
66585868e8aSDimitry Andric   if (d && isa<ObjFile>(d->getFile())) {
66685868e8aSDimitry Andric     os << getSourceLocation(d->getFile(), d->getChunk(), d->getValue(),
66785868e8aSDimitry Andric                             existing->getName());
66885868e8aSDimitry Andric   } else {
66985868e8aSDimitry Andric     os << getSourceLocation(existing->getFile(), nullptr, 0, "");
67085868e8aSDimitry Andric   }
67185868e8aSDimitry Andric   os << getSourceLocation(newFile, newSc, newSectionOffset,
67285868e8aSDimitry Andric                           existing->getName());
6730b57cec5SDimitry Andric 
674bdd1243dSDimitry Andric   if (ctx.config.forceMultiple)
67585868e8aSDimitry Andric     warn(os.str());
6760b57cec5SDimitry Andric   else
67785868e8aSDimitry Andric     error(os.str());
6780b57cec5SDimitry Andric }
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) {
681bdd1243dSDimitry Andric   auto [s, wasInserted] = insert(n, nullptr);
6820b57cec5SDimitry Andric   s->isUsedInRegularObj = true;
68385868e8aSDimitry Andric   if (wasInserted || isa<Undefined>(s) || s->isLazy())
684bdd1243dSDimitry Andric     replaceSymbol<DefinedAbsolute>(s, ctx, n, sym);
685480093f4SDimitry Andric   else if (auto *da = dyn_cast<DefinedAbsolute>(s)) {
686480093f4SDimitry Andric     if (da->getVA() != sym.getValue())
687480093f4SDimitry Andric       reportDuplicate(s, nullptr);
688480093f4SDimitry Andric   } else if (!isa<DefinedCOFF>(s))
6890b57cec5SDimitry Andric     reportDuplicate(s, nullptr);
6900b57cec5SDimitry Andric   return s;
6910b57cec5SDimitry Andric }
6920b57cec5SDimitry Andric 
6930b57cec5SDimitry Andric Symbol *SymbolTable::addAbsolute(StringRef n, uint64_t va) {
694bdd1243dSDimitry Andric   auto [s, wasInserted] = insert(n, nullptr);
6950b57cec5SDimitry Andric   s->isUsedInRegularObj = true;
69685868e8aSDimitry Andric   if (wasInserted || isa<Undefined>(s) || s->isLazy())
697bdd1243dSDimitry Andric     replaceSymbol<DefinedAbsolute>(s, ctx, n, va);
698480093f4SDimitry Andric   else if (auto *da = dyn_cast<DefinedAbsolute>(s)) {
699480093f4SDimitry Andric     if (da->getVA() != va)
700480093f4SDimitry Andric       reportDuplicate(s, nullptr);
701480093f4SDimitry Andric   } else if (!isa<DefinedCOFF>(s))
7020b57cec5SDimitry Andric     reportDuplicate(s, nullptr);
7030b57cec5SDimitry Andric   return s;
7040b57cec5SDimitry Andric }
7050b57cec5SDimitry Andric 
7060b57cec5SDimitry Andric Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) {
707bdd1243dSDimitry Andric   auto [s, wasInserted] = insert(n, nullptr);
7080b57cec5SDimitry Andric   s->isUsedInRegularObj = true;
70985868e8aSDimitry Andric   if (wasInserted || isa<Undefined>(s) || s->isLazy())
7100b57cec5SDimitry Andric     replaceSymbol<DefinedSynthetic>(s, n, c);
7110b57cec5SDimitry Andric   else if (!isa<DefinedCOFF>(s))
7120b57cec5SDimitry Andric     reportDuplicate(s, nullptr);
7130b57cec5SDimitry Andric   return s;
7140b57cec5SDimitry Andric }
7150b57cec5SDimitry Andric 
7160b57cec5SDimitry Andric Symbol *SymbolTable::addRegular(InputFile *f, StringRef n,
71785868e8aSDimitry Andric                                 const coff_symbol_generic *sym, SectionChunk *c,
718bdd1243dSDimitry Andric                                 uint32_t sectionOffset, bool isWeak) {
719bdd1243dSDimitry Andric   auto [s, wasInserted] = insert(n, f);
720bdd1243dSDimitry Andric   if (wasInserted || !isa<DefinedRegular>(s) || s->isWeak)
7210b57cec5SDimitry Andric     replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ false,
722bdd1243dSDimitry Andric                                   /*IsExternal*/ true, sym, c, isWeak);
723bdd1243dSDimitry Andric   else if (!isWeak)
72485868e8aSDimitry Andric     reportDuplicate(s, f, c, sectionOffset);
7250b57cec5SDimitry Andric   return s;
7260b57cec5SDimitry Andric }
7270b57cec5SDimitry Andric 
7280b57cec5SDimitry Andric std::pair<DefinedRegular *, bool>
7290b57cec5SDimitry Andric SymbolTable::addComdat(InputFile *f, StringRef n,
7300b57cec5SDimitry Andric                        const coff_symbol_generic *sym) {
731bdd1243dSDimitry Andric   auto [s, wasInserted] = insert(n, f);
7320b57cec5SDimitry Andric   if (wasInserted || !isa<DefinedRegular>(s)) {
7330b57cec5SDimitry Andric     replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ true,
7340b57cec5SDimitry Andric                                   /*IsExternal*/ true, sym, nullptr);
7350b57cec5SDimitry Andric     return {cast<DefinedRegular>(s), true};
7360b57cec5SDimitry Andric   }
7370b57cec5SDimitry Andric   auto *existingSymbol = cast<DefinedRegular>(s);
7380b57cec5SDimitry Andric   if (!existingSymbol->isCOMDAT)
7390b57cec5SDimitry Andric     reportDuplicate(s, f);
7400b57cec5SDimitry Andric   return {existingSymbol, false};
7410b57cec5SDimitry Andric }
7420b57cec5SDimitry Andric 
7430b57cec5SDimitry Andric Symbol *SymbolTable::addCommon(InputFile *f, StringRef n, uint64_t size,
7440b57cec5SDimitry Andric                                const coff_symbol_generic *sym, CommonChunk *c) {
745bdd1243dSDimitry Andric   auto [s, wasInserted] = insert(n, f);
7460b57cec5SDimitry Andric   if (wasInserted || !isa<DefinedCOFF>(s))
7470b57cec5SDimitry Andric     replaceSymbol<DefinedCommon>(s, f, n, size, sym, c);
7480b57cec5SDimitry Andric   else if (auto *dc = dyn_cast<DefinedCommon>(s))
7490b57cec5SDimitry Andric     if (size > dc->getSize())
7500b57cec5SDimitry Andric       replaceSymbol<DefinedCommon>(s, f, n, size, sym, c);
7510b57cec5SDimitry Andric   return s;
7520b57cec5SDimitry Andric }
7530b57cec5SDimitry Andric 
7540b57cec5SDimitry Andric Symbol *SymbolTable::addImportData(StringRef n, ImportFile *f) {
755bdd1243dSDimitry Andric   auto [s, wasInserted] = insert(n, nullptr);
7560b57cec5SDimitry Andric   s->isUsedInRegularObj = true;
75785868e8aSDimitry Andric   if (wasInserted || isa<Undefined>(s) || s->isLazy()) {
7580b57cec5SDimitry Andric     replaceSymbol<DefinedImportData>(s, n, f);
7590b57cec5SDimitry Andric     return s;
7600b57cec5SDimitry Andric   }
7610b57cec5SDimitry Andric 
7620b57cec5SDimitry Andric   reportDuplicate(s, f);
7630b57cec5SDimitry Andric   return nullptr;
7640b57cec5SDimitry Andric }
7650b57cec5SDimitry Andric 
7660b57cec5SDimitry Andric Symbol *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id,
7670b57cec5SDimitry Andric                                     uint16_t machine) {
768bdd1243dSDimitry Andric   auto [s, wasInserted] = insert(name, nullptr);
7690b57cec5SDimitry Andric   s->isUsedInRegularObj = true;
77085868e8aSDimitry Andric   if (wasInserted || isa<Undefined>(s) || s->isLazy()) {
771bdd1243dSDimitry Andric     replaceSymbol<DefinedImportThunk>(s, ctx, name, id, machine);
7720b57cec5SDimitry Andric     return s;
7730b57cec5SDimitry Andric   }
7740b57cec5SDimitry Andric 
7750b57cec5SDimitry Andric   reportDuplicate(s, id->file);
7760b57cec5SDimitry Andric   return nullptr;
7770b57cec5SDimitry Andric }
7780b57cec5SDimitry Andric 
7790b57cec5SDimitry Andric void SymbolTable::addLibcall(StringRef name) {
7800b57cec5SDimitry Andric   Symbol *sym = findUnderscore(name);
7810b57cec5SDimitry Andric   if (!sym)
7820b57cec5SDimitry Andric     return;
7830b57cec5SDimitry Andric 
78485868e8aSDimitry Andric   if (auto *l = dyn_cast<LazyArchive>(sym)) {
7850b57cec5SDimitry Andric     MemoryBufferRef mb = l->getMemberBuffer();
78685868e8aSDimitry Andric     if (isBitcode(mb))
78785868e8aSDimitry Andric       addUndefined(sym->getName());
78885868e8aSDimitry Andric   } else if (LazyObject *o = dyn_cast<LazyObject>(sym)) {
78985868e8aSDimitry Andric     if (isBitcode(o->file->mb))
7900b57cec5SDimitry Andric       addUndefined(sym->getName());
7910b57cec5SDimitry Andric   }
7920b57cec5SDimitry Andric }
7930b57cec5SDimitry Andric 
794349cc55cSDimitry Andric std::vector<Chunk *> SymbolTable::getChunks() const {
7950b57cec5SDimitry Andric   std::vector<Chunk *> res;
796349cc55cSDimitry Andric   for (ObjFile *file : ctx.objFileInstances) {
7970b57cec5SDimitry Andric     ArrayRef<Chunk *> v = file->getChunks();
7980b57cec5SDimitry Andric     res.insert(res.end(), v.begin(), v.end());
7990b57cec5SDimitry Andric   }
8000b57cec5SDimitry Andric   return res;
8010b57cec5SDimitry Andric }
8020b57cec5SDimitry Andric 
803349cc55cSDimitry Andric Symbol *SymbolTable::find(StringRef name) const {
8040b57cec5SDimitry Andric   return symMap.lookup(CachedHashStringRef(name));
8050b57cec5SDimitry Andric }
8060b57cec5SDimitry Andric 
807349cc55cSDimitry Andric Symbol *SymbolTable::findUnderscore(StringRef name) const {
808bdd1243dSDimitry Andric   if (ctx.config.machine == I386)
8090b57cec5SDimitry Andric     return find(("_" + name).str());
8100b57cec5SDimitry Andric   return find(name);
8110b57cec5SDimitry Andric }
8120b57cec5SDimitry Andric 
8130b57cec5SDimitry Andric // Return all symbols that start with Prefix, possibly ignoring the first
8140b57cec5SDimitry Andric // character of Prefix or the first character symbol.
8150b57cec5SDimitry Andric std::vector<Symbol *> SymbolTable::getSymsWithPrefix(StringRef prefix) {
8160b57cec5SDimitry Andric   std::vector<Symbol *> syms;
8170b57cec5SDimitry Andric   for (auto pair : symMap) {
8180b57cec5SDimitry Andric     StringRef name = pair.first.val();
819*06c3fb27SDimitry Andric     if (name.starts_with(prefix) || name.starts_with(prefix.drop_front()) ||
820*06c3fb27SDimitry Andric         name.drop_front().starts_with(prefix) ||
821*06c3fb27SDimitry Andric         name.drop_front().starts_with(prefix.drop_front())) {
8220b57cec5SDimitry Andric       syms.push_back(pair.second);
8230b57cec5SDimitry Andric     }
8240b57cec5SDimitry Andric   }
8250b57cec5SDimitry Andric   return syms;
8260b57cec5SDimitry Andric }
8270b57cec5SDimitry Andric 
8280b57cec5SDimitry Andric Symbol *SymbolTable::findMangle(StringRef name) {
829bdd1243dSDimitry Andric   if (Symbol *sym = find(name)) {
830bdd1243dSDimitry Andric     if (auto *u = dyn_cast<Undefined>(sym)) {
831bdd1243dSDimitry Andric       // We're specifically looking for weak aliases that ultimately resolve to
832bdd1243dSDimitry Andric       // defined symbols, hence the call to getWeakAlias() instead of just using
833bdd1243dSDimitry Andric       // the weakAlias member variable. This matches link.exe's behavior.
834bdd1243dSDimitry Andric       if (Symbol *weakAlias = u->getWeakAlias())
835bdd1243dSDimitry Andric         return weakAlias;
836bdd1243dSDimitry Andric     } else {
8370b57cec5SDimitry Andric       return sym;
838bdd1243dSDimitry Andric     }
839bdd1243dSDimitry Andric   }
8400b57cec5SDimitry Andric 
8410b57cec5SDimitry Andric   // Efficient fuzzy string lookup is impossible with a hash table, so iterate
8420b57cec5SDimitry Andric   // the symbol table once and collect all possibly matching symbols into this
8430b57cec5SDimitry Andric   // vector. Then compare each possibly matching symbol with each possible
8440b57cec5SDimitry Andric   // mangling.
8450b57cec5SDimitry Andric   std::vector<Symbol *> syms = getSymsWithPrefix(name);
8460b57cec5SDimitry Andric   auto findByPrefix = [&syms](const Twine &t) -> Symbol * {
8470b57cec5SDimitry Andric     std::string prefix = t.str();
8480b57cec5SDimitry Andric     for (auto *s : syms)
849*06c3fb27SDimitry Andric       if (s->getName().starts_with(prefix))
8500b57cec5SDimitry Andric         return s;
8510b57cec5SDimitry Andric     return nullptr;
8520b57cec5SDimitry Andric   };
8530b57cec5SDimitry Andric 
8540b57cec5SDimitry Andric   // For non-x86, just look for C++ functions.
855bdd1243dSDimitry Andric   if (ctx.config.machine != I386)
8560b57cec5SDimitry Andric     return findByPrefix("?" + name + "@@Y");
8570b57cec5SDimitry Andric 
858*06c3fb27SDimitry Andric   if (!name.starts_with("_"))
8590b57cec5SDimitry Andric     return nullptr;
8600b57cec5SDimitry Andric   // Search for x86 stdcall function.
8610b57cec5SDimitry Andric   if (Symbol *s = findByPrefix(name + "@"))
8620b57cec5SDimitry Andric     return s;
8630b57cec5SDimitry Andric   // Search for x86 fastcall function.
8640b57cec5SDimitry Andric   if (Symbol *s = findByPrefix("@" + name.substr(1) + "@"))
8650b57cec5SDimitry Andric     return s;
8660b57cec5SDimitry Andric   // Search for x86 vectorcall function.
8670b57cec5SDimitry Andric   if (Symbol *s = findByPrefix(name.substr(1) + "@@"))
8680b57cec5SDimitry Andric     return s;
8690b57cec5SDimitry Andric   // Search for x86 C++ non-member function.
8700b57cec5SDimitry Andric   return findByPrefix("?" + name.substr(1) + "@@Y");
8710b57cec5SDimitry Andric }
8720b57cec5SDimitry Andric 
8730b57cec5SDimitry Andric Symbol *SymbolTable::addUndefined(StringRef name) {
8740b57cec5SDimitry Andric   return addUndefined(name, nullptr, false);
8750b57cec5SDimitry Andric }
8760b57cec5SDimitry Andric 
877349cc55cSDimitry Andric void SymbolTable::compileBitcodeFiles() {
878349cc55cSDimitry Andric   if (ctx.bitcodeFileInstances.empty())
8790b57cec5SDimitry Andric     return;
8800b57cec5SDimitry Andric 
881349cc55cSDimitry Andric   ScopedTimer t(ctx.ltoTimer);
882bdd1243dSDimitry Andric   lto.reset(new BitcodeCompiler(ctx));
883349cc55cSDimitry Andric   for (BitcodeFile *f : ctx.bitcodeFileInstances)
8845ffd83dbSDimitry Andric     lto->add(*f);
885bdd1243dSDimitry Andric   for (InputFile *newObj : lto->compile()) {
8865ffd83dbSDimitry Andric     ObjFile *obj = cast<ObjFile>(newObj);
8870b57cec5SDimitry Andric     obj->parse();
888349cc55cSDimitry Andric     ctx.objFileInstances.push_back(obj);
8890b57cec5SDimitry Andric   }
8900b57cec5SDimitry Andric }
8910b57cec5SDimitry Andric 
892bdd1243dSDimitry Andric } // namespace lld::coff
893