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/Support/Debug.h"
23*0fca6ea1SDimitry Andric #include "llvm/Support/TimeProfiler.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
ltrim1(StringRef s,const char * chars)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
compatibleMachineType(COFFLinkerContext & ctx,MachineTypes mt)3706c3fb27SDimitry Andric static bool compatibleMachineType(COFFLinkerContext &ctx, MachineTypes mt) {
3806c3fb27SDimitry Andric if (mt == IMAGE_FILE_MACHINE_UNKNOWN)
3906c3fb27SDimitry Andric return true;
4006c3fb27SDimitry Andric switch (ctx.config.machine) {
4106c3fb27SDimitry Andric case ARM64:
4206c3fb27SDimitry Andric return mt == ARM64 || mt == ARM64X;
4306c3fb27SDimitry Andric case ARM64EC:
4406c3fb27SDimitry Andric return COFF::isArm64EC(mt) || mt == AMD64;
4506c3fb27SDimitry Andric case ARM64X:
4606c3fb27SDimitry Andric return COFF::isAnyArm64(mt) || mt == AMD64;
4706c3fb27SDimitry Andric default:
4806c3fb27SDimitry Andric return ctx.config.machine == mt;
4906c3fb27SDimitry Andric }
5006c3fb27SDimitry Andric }
5106c3fb27SDimitry Andric
addFile(InputFile * file)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)) {
645f757f3fSDimitry Andric if (ltoCompilationDone) {
655f757f3fSDimitry Andric error("LTO object file " + toString(file) + " linked in after "
665f757f3fSDimitry Andric "doing LTO compilation.");
675f757f3fSDimitry Andric }
6804eeddc0SDimitry Andric ctx.bitcodeFileInstances.push_back(f);
6904eeddc0SDimitry Andric } else if (auto *f = dyn_cast<ImportFile>(file)) {
7004eeddc0SDimitry Andric ctx.importFileInstances.push_back(f);
7104eeddc0SDimitry Andric }
7204eeddc0SDimitry Andric }
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric MachineTypes mt = file->getMachineType();
75bdd1243dSDimitry Andric if (ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN) {
76bdd1243dSDimitry Andric ctx.config.machine = mt;
77bdd1243dSDimitry Andric ctx.driver.addWinSysRootLibSearchPaths();
7806c3fb27SDimitry Andric } else if (!compatibleMachineType(ctx, mt)) {
790b57cec5SDimitry Andric error(toString(file) + ": machine type " + machineToStr(mt) +
80bdd1243dSDimitry Andric " conflicts with " + machineToStr(ctx.config.machine));
810b57cec5SDimitry Andric return;
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric
84bdd1243dSDimitry Andric ctx.driver.parseDirectives(file);
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric
errorOrWarn(const Twine & s,bool forceUnresolved)87bdd1243dSDimitry Andric static void errorOrWarn(const Twine &s, bool forceUnresolved) {
88bdd1243dSDimitry Andric if (forceUnresolved)
890b57cec5SDimitry Andric warn(s);
900b57cec5SDimitry Andric else
910b57cec5SDimitry Andric error(s);
920b57cec5SDimitry Andric }
930b57cec5SDimitry Andric
9485868e8aSDimitry Andric // Causes the file associated with a lazy symbol to be linked in.
forceLazy(Symbol * s)9585868e8aSDimitry Andric static void forceLazy(Symbol *s) {
9685868e8aSDimitry Andric s->pendingArchiveLoad = true;
9785868e8aSDimitry Andric switch (s->kind()) {
9885868e8aSDimitry Andric case Symbol::Kind::LazyArchiveKind: {
9985868e8aSDimitry Andric auto *l = cast<LazyArchive>(s);
10085868e8aSDimitry Andric l->file->addMember(l->sym);
10185868e8aSDimitry Andric break;
10285868e8aSDimitry Andric }
10304eeddc0SDimitry Andric case Symbol::Kind::LazyObjectKind: {
10404eeddc0SDimitry Andric InputFile *file = cast<LazyObject>(s)->file;
10504eeddc0SDimitry Andric file->ctx.symtab.addFile(file);
10685868e8aSDimitry Andric break;
10704eeddc0SDimitry Andric }
108fe6060f1SDimitry Andric case Symbol::Kind::LazyDLLSymbolKind: {
109fe6060f1SDimitry Andric auto *l = cast<LazyDLLSymbol>(s);
110fe6060f1SDimitry Andric l->file->makeImport(l->sym);
111fe6060f1SDimitry Andric break;
112fe6060f1SDimitry Andric }
11385868e8aSDimitry Andric default:
11485868e8aSDimitry Andric llvm_unreachable(
11585868e8aSDimitry Andric "symbol passed to forceLazy is not a LazyArchive or LazyObject");
11685868e8aSDimitry Andric }
11785868e8aSDimitry Andric }
11885868e8aSDimitry Andric
1190b57cec5SDimitry Andric // Returns the symbol in SC whose value is <= Addr that is closest to Addr.
1200b57cec5SDimitry Andric // This is generally the global variable or function whose definition contains
1210b57cec5SDimitry Andric // Addr.
getSymbol(SectionChunk * sc,uint32_t addr)1220b57cec5SDimitry Andric static Symbol *getSymbol(SectionChunk *sc, uint32_t addr) {
1230b57cec5SDimitry Andric DefinedRegular *candidate = nullptr;
1240b57cec5SDimitry Andric
1250b57cec5SDimitry Andric for (Symbol *s : sc->file->getSymbols()) {
1260b57cec5SDimitry Andric auto *d = dyn_cast_or_null<DefinedRegular>(s);
12785868e8aSDimitry Andric if (!d || !d->data || d->file != sc->file || d->getChunk() != sc ||
12885868e8aSDimitry Andric d->getValue() > addr ||
1290b57cec5SDimitry Andric (candidate && d->getValue() < candidate->getValue()))
1300b57cec5SDimitry Andric continue;
1310b57cec5SDimitry Andric
1320b57cec5SDimitry Andric candidate = d;
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric
1350b57cec5SDimitry Andric return candidate;
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric
getSymbolLocations(BitcodeFile * file)13885868e8aSDimitry Andric static std::vector<std::string> getSymbolLocations(BitcodeFile *file) {
13985868e8aSDimitry Andric std::string res("\n>>> referenced by ");
14085868e8aSDimitry Andric StringRef source = file->obj->getSourceFileName();
14185868e8aSDimitry Andric if (!source.empty())
14285868e8aSDimitry Andric res += source.str() + "\n>>> ";
14385868e8aSDimitry Andric res += toString(file);
14485868e8aSDimitry Andric return {res};
14585868e8aSDimitry Andric }
14685868e8aSDimitry Andric
147bdd1243dSDimitry Andric static std::optional<std::pair<StringRef, uint32_t>>
getFileLineDwarf(const SectionChunk * c,uint32_t addr)14885868e8aSDimitry Andric getFileLineDwarf(const SectionChunk *c, uint32_t addr) {
149bdd1243dSDimitry Andric std::optional<DILineInfo> optionalLineInfo =
15085868e8aSDimitry Andric c->file->getDILineInfo(addr, c->getSectionNumber() - 1);
15185868e8aSDimitry Andric if (!optionalLineInfo)
152bdd1243dSDimitry Andric return std::nullopt;
15385868e8aSDimitry Andric const DILineInfo &lineInfo = *optionalLineInfo;
15485868e8aSDimitry Andric if (lineInfo.FileName == DILineInfo::BadString)
155bdd1243dSDimitry Andric return std::nullopt;
15604eeddc0SDimitry Andric return std::make_pair(saver().save(lineInfo.FileName), lineInfo.Line);
15785868e8aSDimitry Andric }
15885868e8aSDimitry Andric
159bdd1243dSDimitry Andric static std::optional<std::pair<StringRef, uint32_t>>
getFileLine(const SectionChunk * c,uint32_t addr)16085868e8aSDimitry Andric getFileLine(const SectionChunk *c, uint32_t addr) {
16185868e8aSDimitry Andric // MinGW can optionally use codeview, even if the default is dwarf.
162bdd1243dSDimitry Andric std::optional<std::pair<StringRef, uint32_t>> fileLine =
16385868e8aSDimitry Andric getFileLineCodeView(c, addr);
16485868e8aSDimitry Andric // If codeview didn't yield any result, check dwarf in MinGW mode.
165bdd1243dSDimitry Andric if (!fileLine && c->file->ctx.config.mingw)
16685868e8aSDimitry Andric fileLine = getFileLineDwarf(c, addr);
16785868e8aSDimitry Andric return fileLine;
16885868e8aSDimitry Andric }
16985868e8aSDimitry Andric
1700b57cec5SDimitry Andric // Given a file and the index of a symbol in that file, returns a description
1710b57cec5SDimitry Andric // of all references to that symbol from that file. If no debug information is
1720b57cec5SDimitry Andric // available, returns just the name of the file, else one string per actual
1730b57cec5SDimitry Andric // reference as described in the debug info.
174590d96feSDimitry Andric // Returns up to maxStrings string descriptions, along with the total number of
175590d96feSDimitry Andric // locations found.
176590d96feSDimitry Andric static std::pair<std::vector<std::string>, size_t>
getSymbolLocations(ObjFile * file,uint32_t symIndex,size_t maxStrings)177590d96feSDimitry Andric getSymbolLocations(ObjFile *file, uint32_t symIndex, size_t maxStrings) {
1780b57cec5SDimitry Andric struct Location {
1790b57cec5SDimitry Andric Symbol *sym;
1800b57cec5SDimitry Andric std::pair<StringRef, uint32_t> fileLine;
1810b57cec5SDimitry Andric };
1820b57cec5SDimitry Andric std::vector<Location> locations;
183590d96feSDimitry Andric size_t numLocations = 0;
1840b57cec5SDimitry Andric
1850b57cec5SDimitry Andric for (Chunk *c : file->getChunks()) {
1860b57cec5SDimitry Andric auto *sc = dyn_cast<SectionChunk>(c);
1870b57cec5SDimitry Andric if (!sc)
1880b57cec5SDimitry Andric continue;
1890b57cec5SDimitry Andric for (const coff_relocation &r : sc->getRelocs()) {
1900b57cec5SDimitry Andric if (r.SymbolTableIndex != symIndex)
1910b57cec5SDimitry Andric continue;
192590d96feSDimitry Andric numLocations++;
193590d96feSDimitry Andric if (locations.size() >= maxStrings)
194590d96feSDimitry Andric continue;
195590d96feSDimitry Andric
196bdd1243dSDimitry Andric std::optional<std::pair<StringRef, uint32_t>> fileLine =
1970b57cec5SDimitry Andric getFileLine(sc, r.VirtualAddress);
1980b57cec5SDimitry Andric Symbol *sym = getSymbol(sc, r.VirtualAddress);
19985868e8aSDimitry Andric if (fileLine)
20085868e8aSDimitry Andric locations.push_back({sym, *fileLine});
20185868e8aSDimitry Andric else if (sym)
20285868e8aSDimitry Andric locations.push_back({sym, {"", 0}});
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric
206590d96feSDimitry Andric if (maxStrings == 0)
207590d96feSDimitry Andric return std::make_pair(std::vector<std::string>(), numLocations);
208590d96feSDimitry Andric
209590d96feSDimitry Andric if (numLocations == 0)
210590d96feSDimitry Andric return std::make_pair(
211590d96feSDimitry Andric std::vector<std::string>{"\n>>> referenced by " + toString(file)}, 1);
2120b57cec5SDimitry Andric
2130b57cec5SDimitry Andric std::vector<std::string> symbolLocations(locations.size());
2140b57cec5SDimitry Andric size_t i = 0;
2150b57cec5SDimitry Andric for (Location loc : locations) {
2160b57cec5SDimitry Andric llvm::raw_string_ostream os(symbolLocations[i++]);
2170b57cec5SDimitry Andric os << "\n>>> referenced by ";
2180b57cec5SDimitry Andric if (!loc.fileLine.first.empty())
2190b57cec5SDimitry Andric os << loc.fileLine.first << ":" << loc.fileLine.second
2200b57cec5SDimitry Andric << "\n>>> ";
2210b57cec5SDimitry Andric os << toString(file);
2220b57cec5SDimitry Andric if (loc.sym)
223bdd1243dSDimitry Andric os << ":(" << toString(file->ctx, *loc.sym) << ')';
2240b57cec5SDimitry Andric }
225590d96feSDimitry Andric return std::make_pair(symbolLocations, numLocations);
2260b57cec5SDimitry Andric }
2270b57cec5SDimitry Andric
getSymbolLocations(ObjFile * file,uint32_t symIndex)228590d96feSDimitry Andric std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {
229590d96feSDimitry Andric return getSymbolLocations(file, symIndex, SIZE_MAX).first;
230590d96feSDimitry Andric }
231590d96feSDimitry Andric
232590d96feSDimitry Andric static std::pair<std::vector<std::string>, size_t>
getSymbolLocations(InputFile * file,uint32_t symIndex,size_t maxStrings)233590d96feSDimitry Andric getSymbolLocations(InputFile *file, uint32_t symIndex, size_t maxStrings) {
23485868e8aSDimitry Andric if (auto *o = dyn_cast<ObjFile>(file))
235590d96feSDimitry Andric return getSymbolLocations(o, symIndex, maxStrings);
236590d96feSDimitry Andric if (auto *b = dyn_cast<BitcodeFile>(file)) {
237590d96feSDimitry Andric std::vector<std::string> symbolLocations = getSymbolLocations(b);
238590d96feSDimitry Andric size_t numLocations = symbolLocations.size();
239590d96feSDimitry Andric if (symbolLocations.size() > maxStrings)
240590d96feSDimitry Andric symbolLocations.resize(maxStrings);
241590d96feSDimitry Andric return std::make_pair(symbolLocations, numLocations);
242590d96feSDimitry Andric }
24385868e8aSDimitry Andric llvm_unreachable("unsupported file type passed to getSymbolLocations");
244590d96feSDimitry Andric return std::make_pair(std::vector<std::string>(), (size_t)0);
24585868e8aSDimitry Andric }
24685868e8aSDimitry Andric
2470b57cec5SDimitry Andric // For an undefined symbol, stores all files referencing it and the index of
2480b57cec5SDimitry Andric // the undefined symbol in each file.
2490b57cec5SDimitry Andric struct UndefinedDiag {
2500b57cec5SDimitry Andric Symbol *sym;
2510b57cec5SDimitry Andric struct File {
25285868e8aSDimitry Andric InputFile *file;
25385868e8aSDimitry Andric uint32_t symIndex;
2540b57cec5SDimitry Andric };
2550b57cec5SDimitry Andric std::vector<File> files;
2560b57cec5SDimitry Andric };
2570b57cec5SDimitry Andric
reportUndefinedSymbol(const COFFLinkerContext & ctx,const UndefinedDiag & undefDiag)258bdd1243dSDimitry Andric static void reportUndefinedSymbol(const COFFLinkerContext &ctx,
259bdd1243dSDimitry Andric const UndefinedDiag &undefDiag) {
2600b57cec5SDimitry Andric std::string out;
2610b57cec5SDimitry Andric llvm::raw_string_ostream os(out);
262bdd1243dSDimitry Andric os << "undefined symbol: " << toString(ctx, *undefDiag.sym);
2630b57cec5SDimitry Andric
2645ffd83dbSDimitry Andric const size_t maxUndefReferences = 3;
265590d96feSDimitry Andric size_t numDisplayedRefs = 0, numRefs = 0;
2660b57cec5SDimitry Andric for (const UndefinedDiag::File &ref : undefDiag.files) {
267bdd1243dSDimitry Andric auto [symbolLocations, totalLocations] = getSymbolLocations(
268590d96feSDimitry Andric ref.file, ref.symIndex, maxUndefReferences - numDisplayedRefs);
269590d96feSDimitry Andric
270590d96feSDimitry Andric numRefs += totalLocations;
271590d96feSDimitry Andric numDisplayedRefs += symbolLocations.size();
2720b57cec5SDimitry Andric for (const std::string &s : symbolLocations) {
2730b57cec5SDimitry Andric os << s;
2740b57cec5SDimitry Andric }
2750b57cec5SDimitry Andric }
276590d96feSDimitry Andric if (numDisplayedRefs < numRefs)
277590d96feSDimitry Andric os << "\n>>> referenced " << numRefs - numDisplayedRefs << " more times";
278bdd1243dSDimitry Andric errorOrWarn(os.str(), ctx.config.forceUnresolved);
2790b57cec5SDimitry Andric }
2800b57cec5SDimitry Andric
loadMinGWSymbols()281fe6060f1SDimitry Andric void SymbolTable::loadMinGWSymbols() {
2820b57cec5SDimitry Andric for (auto &i : symMap) {
2830b57cec5SDimitry Andric Symbol *sym = i.second;
2840b57cec5SDimitry Andric auto *undef = dyn_cast<Undefined>(sym);
2850b57cec5SDimitry Andric if (!undef)
2860b57cec5SDimitry Andric continue;
28785868e8aSDimitry Andric if (undef->getWeakAlias())
28885868e8aSDimitry Andric continue;
2890b57cec5SDimitry Andric
2900b57cec5SDimitry Andric StringRef name = undef->getName();
2910b57cec5SDimitry Andric
292bdd1243dSDimitry Andric if (ctx.config.machine == I386 && ctx.config.stdcallFixup) {
293fe6060f1SDimitry Andric // Check if we can resolve an undefined decorated symbol by finding
294349cc55cSDimitry Andric // the intended target as an undecorated symbol (only with a leading
295fe6060f1SDimitry Andric // underscore).
296fe6060f1SDimitry Andric StringRef origName = name;
297fe6060f1SDimitry Andric StringRef baseName = name;
298fe6060f1SDimitry Andric // Trim down stdcall/fastcall/vectorcall symbols to the base name.
299fe6060f1SDimitry Andric baseName = ltrim1(baseName, "_@");
300fe6060f1SDimitry Andric baseName = baseName.substr(0, baseName.find('@'));
301fe6060f1SDimitry Andric // Add a leading underscore, as it would be in cdecl form.
302fe6060f1SDimitry Andric std::string newName = ("_" + baseName).str();
303fe6060f1SDimitry Andric Symbol *l;
304fe6060f1SDimitry Andric if (newName != origName && (l = find(newName)) != nullptr) {
305fe6060f1SDimitry Andric // If we found a symbol and it is lazy; load it.
306fe6060f1SDimitry Andric if (l->isLazy() && !l->pendingArchiveLoad) {
307fe6060f1SDimitry Andric log("Loading lazy " + l->getName() + " from " +
308fe6060f1SDimitry Andric l->getFile()->getName() + " for stdcall fixup");
309fe6060f1SDimitry Andric forceLazy(l);
310fe6060f1SDimitry Andric }
311fe6060f1SDimitry Andric // If it's lazy or already defined, hook it up as weak alias.
312fe6060f1SDimitry Andric if (l->isLazy() || isa<Defined>(l)) {
313bdd1243dSDimitry Andric if (ctx.config.warnStdcallFixup)
314fe6060f1SDimitry Andric warn("Resolving " + origName + " by linking to " + newName);
315fe6060f1SDimitry Andric else
316fe6060f1SDimitry Andric log("Resolving " + origName + " by linking to " + newName);
317fe6060f1SDimitry Andric undef->weakAlias = l;
318fe6060f1SDimitry Andric continue;
319fe6060f1SDimitry Andric }
320fe6060f1SDimitry Andric }
321fe6060f1SDimitry Andric }
322fe6060f1SDimitry Andric
323bdd1243dSDimitry Andric if (ctx.config.autoImport) {
32406c3fb27SDimitry Andric if (name.starts_with("__imp_"))
3250b57cec5SDimitry Andric continue;
32685868e8aSDimitry Andric // If we have an undefined symbol, but we have a lazy symbol we could
32785868e8aSDimitry Andric // load, load it.
32885868e8aSDimitry Andric Symbol *l = find(("__imp_" + name).str());
32985868e8aSDimitry Andric if (!l || l->pendingArchiveLoad || !l->isLazy())
3300b57cec5SDimitry Andric continue;
3310b57cec5SDimitry Andric
33285868e8aSDimitry Andric log("Loading lazy " + l->getName() + " from " + l->getFile()->getName() +
3330b57cec5SDimitry Andric " for automatic import");
33485868e8aSDimitry Andric forceLazy(l);
3350b57cec5SDimitry Andric }
3360b57cec5SDimitry Andric }
337fe6060f1SDimitry Andric }
3380b57cec5SDimitry Andric
impSymbol(StringRef name)33985868e8aSDimitry Andric Defined *SymbolTable::impSymbol(StringRef name) {
34006c3fb27SDimitry Andric if (name.starts_with("__imp_"))
34185868e8aSDimitry Andric return nullptr;
34285868e8aSDimitry Andric return dyn_cast_or_null<Defined>(find(("__imp_" + name).str()));
34385868e8aSDimitry Andric }
34485868e8aSDimitry Andric
handleMinGWAutomaticImport(Symbol * sym,StringRef name)3450b57cec5SDimitry Andric bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {
34685868e8aSDimitry Andric Defined *imp = impSymbol(name);
3470b57cec5SDimitry Andric if (!imp)
3480b57cec5SDimitry Andric return false;
3490b57cec5SDimitry Andric
3500b57cec5SDimitry Andric // Replace the reference directly to a variable with a reference
3510b57cec5SDimitry Andric // to the import address table instead. This obviously isn't right,
3520b57cec5SDimitry Andric // but we mark the symbol as isRuntimePseudoReloc, and a later pass
3530b57cec5SDimitry Andric // will add runtime pseudo relocations for every relocation against
3540b57cec5SDimitry Andric // this Symbol. The runtime pseudo relocation framework expects the
3550b57cec5SDimitry Andric // reference itself to point at the IAT entry.
3560b57cec5SDimitry Andric size_t impSize = 0;
3570b57cec5SDimitry Andric if (isa<DefinedImportData>(imp)) {
3580b57cec5SDimitry Andric log("Automatically importing " + name + " from " +
3590b57cec5SDimitry Andric cast<DefinedImportData>(imp)->getDLLName());
3600b57cec5SDimitry Andric impSize = sizeof(DefinedImportData);
3610b57cec5SDimitry Andric } else if (isa<DefinedRegular>(imp)) {
3620b57cec5SDimitry Andric log("Automatically importing " + name + " from " +
3630b57cec5SDimitry Andric toString(cast<DefinedRegular>(imp)->file));
3640b57cec5SDimitry Andric impSize = sizeof(DefinedRegular);
3650b57cec5SDimitry Andric } else {
3660b57cec5SDimitry Andric warn("unable to automatically import " + name + " from " + imp->getName() +
3670b57cec5SDimitry Andric " from " + toString(cast<DefinedRegular>(imp)->file) +
3680b57cec5SDimitry Andric "; unexpected symbol type");
3690b57cec5SDimitry Andric return false;
3700b57cec5SDimitry Andric }
3710b57cec5SDimitry Andric sym->replaceKeepingName(imp, impSize);
3720b57cec5SDimitry Andric sym->isRuntimePseudoReloc = true;
3730b57cec5SDimitry Andric
3740b57cec5SDimitry Andric // There may exist symbols named .refptr.<name> which only consist
3750b57cec5SDimitry Andric // of a single pointer to <name>. If it turns out <name> is
3760b57cec5SDimitry Andric // automatically imported, we don't need to keep the .refptr.<name>
3770b57cec5SDimitry Andric // pointer at all, but redirect all accesses to it to the IAT entry
3780b57cec5SDimitry Andric // for __imp_<name> instead, and drop the whole .refptr.<name> chunk.
3790b57cec5SDimitry Andric DefinedRegular *refptr =
3800b57cec5SDimitry Andric dyn_cast_or_null<DefinedRegular>(find((".refptr." + name).str()));
381bdd1243dSDimitry Andric if (refptr && refptr->getChunk()->getSize() == ctx.config.wordsize) {
3820b57cec5SDimitry Andric SectionChunk *sc = dyn_cast_or_null<SectionChunk>(refptr->getChunk());
3830b57cec5SDimitry Andric if (sc && sc->getRelocs().size() == 1 && *sc->symbols().begin() == sym) {
3840b57cec5SDimitry Andric log("Replacing .refptr." + name + " with " + imp->getName());
3850b57cec5SDimitry Andric refptr->getChunk()->live = false;
3860b57cec5SDimitry Andric refptr->replaceKeepingName(imp, impSize);
3870b57cec5SDimitry Andric }
3880b57cec5SDimitry Andric }
3890b57cec5SDimitry Andric return true;
3900b57cec5SDimitry Andric }
3910b57cec5SDimitry Andric
39285868e8aSDimitry Andric /// Helper function for reportUnresolvable and resolveRemainingUndefines.
39385868e8aSDimitry Andric /// This function emits an "undefined symbol" diagnostic for each symbol in
39485868e8aSDimitry Andric /// undefs. If localImports is not nullptr, it also emits a "locally
39585868e8aSDimitry Andric /// defined symbol imported" diagnostic for symbols in localImports.
39685868e8aSDimitry Andric /// objFiles and bitcodeFiles (if not nullptr) are used to report where
39785868e8aSDimitry Andric /// undefined symbols are referenced.
reportProblemSymbols(const COFFLinkerContext & ctx,const SmallPtrSetImpl<Symbol * > & undefs,const DenseMap<Symbol *,Symbol * > * localImports,bool needBitcodeFiles)398349cc55cSDimitry Andric static void reportProblemSymbols(
399349cc55cSDimitry Andric const COFFLinkerContext &ctx, const SmallPtrSetImpl<Symbol *> &undefs,
400349cc55cSDimitry Andric const DenseMap<Symbol *, Symbol *> *localImports, bool needBitcodeFiles) {
40185868e8aSDimitry Andric // Return early if there is nothing to report (which should be
40285868e8aSDimitry Andric // the common case).
40385868e8aSDimitry Andric if (undefs.empty() && (!localImports || localImports->empty()))
40485868e8aSDimitry Andric return;
40585868e8aSDimitry Andric
406bdd1243dSDimitry Andric for (Symbol *b : ctx.config.gcroot) {
40785868e8aSDimitry Andric if (undefs.count(b))
408bdd1243dSDimitry Andric errorOrWarn("<root>: undefined symbol: " + toString(ctx, *b),
409bdd1243dSDimitry Andric ctx.config.forceUnresolved);
41085868e8aSDimitry Andric if (localImports)
41185868e8aSDimitry Andric if (Symbol *imp = localImports->lookup(b))
412bdd1243dSDimitry Andric warn("<root>: locally defined symbol imported: " + toString(ctx, *imp) +
41385868e8aSDimitry Andric " (defined in " + toString(imp->getFile()) + ") [LNK4217]");
41485868e8aSDimitry Andric }
41585868e8aSDimitry Andric
41685868e8aSDimitry Andric std::vector<UndefinedDiag> undefDiags;
41785868e8aSDimitry Andric DenseMap<Symbol *, int> firstDiag;
41885868e8aSDimitry Andric
41985868e8aSDimitry Andric auto processFile = [&](InputFile *file, ArrayRef<Symbol *> symbols) {
42085868e8aSDimitry Andric uint32_t symIndex = (uint32_t)-1;
42185868e8aSDimitry Andric for (Symbol *sym : symbols) {
42285868e8aSDimitry Andric ++symIndex;
42385868e8aSDimitry Andric if (!sym)
42485868e8aSDimitry Andric continue;
42585868e8aSDimitry Andric if (undefs.count(sym)) {
42685868e8aSDimitry Andric auto it = firstDiag.find(sym);
42785868e8aSDimitry Andric if (it == firstDiag.end()) {
42885868e8aSDimitry Andric firstDiag[sym] = undefDiags.size();
42985868e8aSDimitry Andric undefDiags.push_back({sym, {{file, symIndex}}});
43085868e8aSDimitry Andric } else {
43185868e8aSDimitry Andric undefDiags[it->second].files.push_back({file, symIndex});
43285868e8aSDimitry Andric }
43385868e8aSDimitry Andric }
43485868e8aSDimitry Andric if (localImports)
43585868e8aSDimitry Andric if (Symbol *imp = localImports->lookup(sym))
43685868e8aSDimitry Andric warn(toString(file) +
437bdd1243dSDimitry Andric ": locally defined symbol imported: " + toString(ctx, *imp) +
43885868e8aSDimitry Andric " (defined in " + toString(imp->getFile()) + ") [LNK4217]");
43985868e8aSDimitry Andric }
44085868e8aSDimitry Andric };
44185868e8aSDimitry Andric
442349cc55cSDimitry Andric for (ObjFile *file : ctx.objFileInstances)
44385868e8aSDimitry Andric processFile(file, file->getSymbols());
44485868e8aSDimitry Andric
445349cc55cSDimitry Andric if (needBitcodeFiles)
446349cc55cSDimitry Andric for (BitcodeFile *file : ctx.bitcodeFileInstances)
44785868e8aSDimitry Andric processFile(file, file->getSymbols());
44885868e8aSDimitry Andric
44985868e8aSDimitry Andric for (const UndefinedDiag &undefDiag : undefDiags)
450bdd1243dSDimitry Andric reportUndefinedSymbol(ctx, undefDiag);
45185868e8aSDimitry Andric }
45285868e8aSDimitry Andric
reportUnresolvable()45385868e8aSDimitry Andric void SymbolTable::reportUnresolvable() {
45485868e8aSDimitry Andric SmallPtrSet<Symbol *, 8> undefs;
45585868e8aSDimitry Andric for (auto &i : symMap) {
45685868e8aSDimitry Andric Symbol *sym = i.second;
45785868e8aSDimitry Andric auto *undef = dyn_cast<Undefined>(sym);
458e8d8bef9SDimitry Andric if (!undef || sym->deferUndefined)
45985868e8aSDimitry Andric continue;
46085868e8aSDimitry Andric if (undef->getWeakAlias())
46185868e8aSDimitry Andric continue;
46285868e8aSDimitry Andric StringRef name = undef->getName();
46306c3fb27SDimitry Andric if (name.starts_with("__imp_")) {
46485868e8aSDimitry Andric Symbol *imp = find(name.substr(strlen("__imp_")));
4655f757f3fSDimitry Andric if (Defined *def = dyn_cast_or_null<Defined>(imp)) {
4665f757f3fSDimitry Andric def->isUsedInRegularObj = true;
46785868e8aSDimitry Andric continue;
46885868e8aSDimitry Andric }
4695f757f3fSDimitry Andric }
47085868e8aSDimitry Andric if (name.contains("_PchSym_"))
47185868e8aSDimitry Andric continue;
472bdd1243dSDimitry Andric if (ctx.config.autoImport && impSymbol(name))
47385868e8aSDimitry Andric continue;
47485868e8aSDimitry Andric undefs.insert(sym);
47585868e8aSDimitry Andric }
47685868e8aSDimitry Andric
477349cc55cSDimitry Andric reportProblemSymbols(ctx, undefs,
478349cc55cSDimitry Andric /* localImports */ nullptr, true);
47985868e8aSDimitry Andric }
48085868e8aSDimitry Andric
resolveRemainingUndefines()48185868e8aSDimitry Andric void SymbolTable::resolveRemainingUndefines() {
4825f757f3fSDimitry Andric llvm::TimeTraceScope timeScope("Resolve remaining undefined symbols");
4830b57cec5SDimitry Andric SmallPtrSet<Symbol *, 8> undefs;
4840b57cec5SDimitry Andric DenseMap<Symbol *, Symbol *> localImports;
4850b57cec5SDimitry Andric
4860b57cec5SDimitry Andric for (auto &i : symMap) {
4870b57cec5SDimitry Andric Symbol *sym = i.second;
4880b57cec5SDimitry Andric auto *undef = dyn_cast<Undefined>(sym);
4890b57cec5SDimitry Andric if (!undef)
4900b57cec5SDimitry Andric continue;
4910b57cec5SDimitry Andric if (!sym->isUsedInRegularObj)
4920b57cec5SDimitry Andric continue;
4930b57cec5SDimitry Andric
4940b57cec5SDimitry Andric StringRef name = undef->getName();
4950b57cec5SDimitry Andric
4960b57cec5SDimitry Andric // A weak alias may have been resolved, so check for that.
4970b57cec5SDimitry Andric if (Defined *d = undef->getWeakAlias()) {
4980b57cec5SDimitry Andric // We want to replace Sym with D. However, we can't just blindly
4990b57cec5SDimitry Andric // copy sizeof(SymbolUnion) bytes from D to Sym because D may be an
5000b57cec5SDimitry Andric // internal symbol, and internal symbols are stored as "unparented"
5010b57cec5SDimitry Andric // Symbols. For that reason we need to check which type of symbol we
5020b57cec5SDimitry Andric // are dealing with and copy the correct number of bytes.
5030b57cec5SDimitry Andric if (isa<DefinedRegular>(d))
5040b57cec5SDimitry Andric memcpy(sym, d, sizeof(DefinedRegular));
5050b57cec5SDimitry Andric else if (isa<DefinedAbsolute>(d))
5060b57cec5SDimitry Andric memcpy(sym, d, sizeof(DefinedAbsolute));
5070b57cec5SDimitry Andric else
5080b57cec5SDimitry Andric memcpy(sym, d, sizeof(SymbolUnion));
5090b57cec5SDimitry Andric continue;
5100b57cec5SDimitry Andric }
5110b57cec5SDimitry Andric
5120b57cec5SDimitry Andric // If we can resolve a symbol by removing __imp_ prefix, do that.
5130b57cec5SDimitry Andric // This odd rule is for compatibility with MSVC linker.
51406c3fb27SDimitry Andric if (name.starts_with("__imp_")) {
5150b57cec5SDimitry Andric Symbol *imp = find(name.substr(strlen("__imp_")));
5160b57cec5SDimitry Andric if (imp && isa<Defined>(imp)) {
5170b57cec5SDimitry Andric auto *d = cast<Defined>(imp);
518bdd1243dSDimitry Andric replaceSymbol<DefinedLocalImport>(sym, ctx, name, d);
5190b57cec5SDimitry Andric localImportChunks.push_back(cast<DefinedLocalImport>(sym)->getChunk());
5200b57cec5SDimitry Andric localImports[sym] = d;
5210b57cec5SDimitry Andric continue;
5220b57cec5SDimitry Andric }
5230b57cec5SDimitry Andric }
5240b57cec5SDimitry Andric
5250b57cec5SDimitry Andric // We don't want to report missing Microsoft precompiled headers symbols.
5260b57cec5SDimitry Andric // A proper message will be emitted instead in PDBLinker::aquirePrecompObj
5270b57cec5SDimitry Andric if (name.contains("_PchSym_"))
5280b57cec5SDimitry Andric continue;
5290b57cec5SDimitry Andric
530bdd1243dSDimitry Andric if (ctx.config.autoImport && handleMinGWAutomaticImport(sym, name))
5310b57cec5SDimitry Andric continue;
5320b57cec5SDimitry Andric
5330b57cec5SDimitry Andric // Remaining undefined symbols are not fatal if /force is specified.
5340b57cec5SDimitry Andric // They are replaced with dummy defined symbols.
535bdd1243dSDimitry Andric if (ctx.config.forceUnresolved)
536bdd1243dSDimitry Andric replaceSymbol<DefinedAbsolute>(sym, ctx, name, 0);
5370b57cec5SDimitry Andric undefs.insert(sym);
5380b57cec5SDimitry Andric }
5390b57cec5SDimitry Andric
54085868e8aSDimitry Andric reportProblemSymbols(
541bdd1243dSDimitry Andric ctx, undefs,
542bdd1243dSDimitry Andric ctx.config.warnLocallyDefinedImported ? &localImports : nullptr, false);
5430b57cec5SDimitry Andric }
5440b57cec5SDimitry Andric
insert(StringRef name)5450b57cec5SDimitry Andric std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
5460b57cec5SDimitry Andric bool inserted = false;
5470b57cec5SDimitry Andric Symbol *&sym = symMap[CachedHashStringRef(name)];
5480b57cec5SDimitry Andric if (!sym) {
5490b57cec5SDimitry Andric sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
5500b57cec5SDimitry Andric sym->isUsedInRegularObj = false;
5510b57cec5SDimitry Andric sym->pendingArchiveLoad = false;
552e8d8bef9SDimitry Andric sym->canInline = true;
5530b57cec5SDimitry Andric inserted = true;
5540b57cec5SDimitry Andric }
5550b57cec5SDimitry Andric return {sym, inserted};
5560b57cec5SDimitry Andric }
5570b57cec5SDimitry Andric
insert(StringRef name,InputFile * file)5580b57cec5SDimitry Andric std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, InputFile *file) {
5590b57cec5SDimitry Andric std::pair<Symbol *, bool> result = insert(name);
5600b57cec5SDimitry Andric if (!file || !isa<BitcodeFile>(file))
5610b57cec5SDimitry Andric result.first->isUsedInRegularObj = true;
5620b57cec5SDimitry Andric return result;
5630b57cec5SDimitry Andric }
5640b57cec5SDimitry Andric
addEntryThunk(Symbol * from,Symbol * to)565*0fca6ea1SDimitry Andric void SymbolTable::addEntryThunk(Symbol *from, Symbol *to) {
566*0fca6ea1SDimitry Andric entryThunks.push_back({from, to});
567*0fca6ea1SDimitry Andric }
568*0fca6ea1SDimitry Andric
initializeEntryThunks()569*0fca6ea1SDimitry Andric void SymbolTable::initializeEntryThunks() {
570*0fca6ea1SDimitry Andric for (auto it : entryThunks) {
571*0fca6ea1SDimitry Andric auto *to = dyn_cast<Defined>(it.second);
572*0fca6ea1SDimitry Andric if (!to)
573*0fca6ea1SDimitry Andric continue;
574*0fca6ea1SDimitry Andric auto *from = dyn_cast<DefinedRegular>(it.first);
575*0fca6ea1SDimitry Andric // We need to be able to add padding to the function and fill it with an
576*0fca6ea1SDimitry Andric // offset to its entry thunks. To ensure that padding the function is
577*0fca6ea1SDimitry Andric // feasible, functions are required to be COMDAT symbols with no offset.
578*0fca6ea1SDimitry Andric if (!from || !from->getChunk()->isCOMDAT() ||
579*0fca6ea1SDimitry Andric cast<DefinedRegular>(from)->getValue()) {
580*0fca6ea1SDimitry Andric error("non COMDAT symbol '" + from->getName() + "' in hybrid map");
581*0fca6ea1SDimitry Andric continue;
582*0fca6ea1SDimitry Andric }
583*0fca6ea1SDimitry Andric from->getChunk()->setEntryThunk(to);
584*0fca6ea1SDimitry Andric }
585*0fca6ea1SDimitry Andric }
586*0fca6ea1SDimitry Andric
addUndefined(StringRef name,InputFile * f,bool isWeakAlias)5870b57cec5SDimitry Andric Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f,
5880b57cec5SDimitry Andric bool isWeakAlias) {
589bdd1243dSDimitry Andric auto [s, wasInserted] = insert(name, f);
59085868e8aSDimitry Andric if (wasInserted || (s->isLazy() && isWeakAlias)) {
5910b57cec5SDimitry Andric replaceSymbol<Undefined>(s, name);
5920b57cec5SDimitry Andric return s;
5930b57cec5SDimitry Andric }
59485868e8aSDimitry Andric if (s->isLazy())
59585868e8aSDimitry Andric forceLazy(s);
5960b57cec5SDimitry Andric return s;
5970b57cec5SDimitry Andric }
5980b57cec5SDimitry Andric
addLazyArchive(ArchiveFile * f,const Archive::Symbol & sym)59985868e8aSDimitry Andric void SymbolTable::addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym) {
6000b57cec5SDimitry Andric StringRef name = sym.getName();
601bdd1243dSDimitry Andric auto [s, wasInserted] = insert(name);
6020b57cec5SDimitry Andric if (wasInserted) {
60385868e8aSDimitry Andric replaceSymbol<LazyArchive>(s, f, sym);
6040b57cec5SDimitry Andric return;
6050b57cec5SDimitry Andric }
6060b57cec5SDimitry Andric auto *u = dyn_cast<Undefined>(s);
6070b57cec5SDimitry Andric if (!u || u->weakAlias || s->pendingArchiveLoad)
6080b57cec5SDimitry Andric return;
6090b57cec5SDimitry Andric s->pendingArchiveLoad = true;
6100b57cec5SDimitry Andric f->addMember(sym);
6110b57cec5SDimitry Andric }
6120b57cec5SDimitry Andric
addLazyObject(InputFile * f,StringRef n)61304eeddc0SDimitry Andric void SymbolTable::addLazyObject(InputFile *f, StringRef n) {
61404eeddc0SDimitry Andric assert(f->lazy);
615bdd1243dSDimitry Andric auto [s, wasInserted] = insert(n, f);
61685868e8aSDimitry Andric if (wasInserted) {
61785868e8aSDimitry Andric replaceSymbol<LazyObject>(s, f, n);
61885868e8aSDimitry Andric return;
61985868e8aSDimitry Andric }
62085868e8aSDimitry Andric auto *u = dyn_cast<Undefined>(s);
62185868e8aSDimitry Andric if (!u || u->weakAlias || s->pendingArchiveLoad)
62285868e8aSDimitry Andric return;
62385868e8aSDimitry Andric s->pendingArchiveLoad = true;
62404eeddc0SDimitry Andric f->lazy = false;
62504eeddc0SDimitry Andric addFile(f);
62685868e8aSDimitry Andric }
62785868e8aSDimitry Andric
addLazyDLLSymbol(DLLFile * f,DLLFile::Symbol * sym,StringRef n)628fe6060f1SDimitry Andric void SymbolTable::addLazyDLLSymbol(DLLFile *f, DLLFile::Symbol *sym,
629fe6060f1SDimitry Andric StringRef n) {
630bdd1243dSDimitry Andric auto [s, wasInserted] = insert(n);
631fe6060f1SDimitry Andric if (wasInserted) {
632fe6060f1SDimitry Andric replaceSymbol<LazyDLLSymbol>(s, f, sym, n);
633fe6060f1SDimitry Andric return;
634fe6060f1SDimitry Andric }
635fe6060f1SDimitry Andric auto *u = dyn_cast<Undefined>(s);
636fe6060f1SDimitry Andric if (!u || u->weakAlias || s->pendingArchiveLoad)
637fe6060f1SDimitry Andric return;
638fe6060f1SDimitry Andric s->pendingArchiveLoad = true;
639fe6060f1SDimitry Andric f->makeImport(sym);
640fe6060f1SDimitry Andric }
641fe6060f1SDimitry Andric
getSourceLocationBitcode(BitcodeFile * file)64285868e8aSDimitry Andric static std::string getSourceLocationBitcode(BitcodeFile *file) {
64385868e8aSDimitry Andric std::string res("\n>>> defined at ");
64485868e8aSDimitry Andric StringRef source = file->obj->getSourceFileName();
64585868e8aSDimitry Andric if (!source.empty())
64685868e8aSDimitry Andric res += source.str() + "\n>>> ";
64785868e8aSDimitry Andric res += toString(file);
64885868e8aSDimitry Andric return res;
64985868e8aSDimitry Andric }
65085868e8aSDimitry Andric
getSourceLocationObj(ObjFile * file,SectionChunk * sc,uint32_t offset,StringRef name)65185868e8aSDimitry Andric static std::string getSourceLocationObj(ObjFile *file, SectionChunk *sc,
65285868e8aSDimitry Andric uint32_t offset, StringRef name) {
653bdd1243dSDimitry Andric std::optional<std::pair<StringRef, uint32_t>> fileLine;
65485868e8aSDimitry Andric if (sc)
65585868e8aSDimitry Andric fileLine = getFileLine(sc, offset);
65685868e8aSDimitry Andric if (!fileLine)
65785868e8aSDimitry Andric fileLine = file->getVariableLocation(name);
65885868e8aSDimitry Andric
65985868e8aSDimitry Andric std::string res;
66085868e8aSDimitry Andric llvm::raw_string_ostream os(res);
66185868e8aSDimitry Andric os << "\n>>> defined at ";
66285868e8aSDimitry Andric if (fileLine)
66385868e8aSDimitry Andric os << fileLine->first << ":" << fileLine->second << "\n>>> ";
66485868e8aSDimitry Andric os << toString(file);
66585868e8aSDimitry Andric return os.str();
66685868e8aSDimitry Andric }
66785868e8aSDimitry Andric
getSourceLocation(InputFile * file,SectionChunk * sc,uint32_t offset,StringRef name)66885868e8aSDimitry Andric static std::string getSourceLocation(InputFile *file, SectionChunk *sc,
66985868e8aSDimitry Andric uint32_t offset, StringRef name) {
670480093f4SDimitry Andric if (!file)
671480093f4SDimitry Andric return "";
67285868e8aSDimitry Andric if (auto *o = dyn_cast<ObjFile>(file))
67385868e8aSDimitry Andric return getSourceLocationObj(o, sc, offset, name);
67485868e8aSDimitry Andric if (auto *b = dyn_cast<BitcodeFile>(file))
67585868e8aSDimitry Andric return getSourceLocationBitcode(b);
67685868e8aSDimitry Andric return "\n>>> defined at " + toString(file);
67785868e8aSDimitry Andric }
67885868e8aSDimitry Andric
67985868e8aSDimitry Andric // Construct and print an error message in the form of:
68085868e8aSDimitry Andric //
68185868e8aSDimitry Andric // lld-link: error: duplicate symbol: foo
68285868e8aSDimitry Andric // >>> defined at bar.c:30
68385868e8aSDimitry Andric // >>> bar.o
68485868e8aSDimitry Andric // >>> defined at baz.c:563
68585868e8aSDimitry Andric // >>> baz.o
reportDuplicate(Symbol * existing,InputFile * newFile,SectionChunk * newSc,uint32_t newSectionOffset)68685868e8aSDimitry Andric void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile,
68785868e8aSDimitry Andric SectionChunk *newSc,
68885868e8aSDimitry Andric uint32_t newSectionOffset) {
68985868e8aSDimitry Andric std::string msg;
69085868e8aSDimitry Andric llvm::raw_string_ostream os(msg);
691bdd1243dSDimitry Andric os << "duplicate symbol: " << toString(ctx, *existing);
69285868e8aSDimitry Andric
693480093f4SDimitry Andric DefinedRegular *d = dyn_cast<DefinedRegular>(existing);
69485868e8aSDimitry Andric if (d && isa<ObjFile>(d->getFile())) {
69585868e8aSDimitry Andric os << getSourceLocation(d->getFile(), d->getChunk(), d->getValue(),
69685868e8aSDimitry Andric existing->getName());
69785868e8aSDimitry Andric } else {
69885868e8aSDimitry Andric os << getSourceLocation(existing->getFile(), nullptr, 0, "");
69985868e8aSDimitry Andric }
70085868e8aSDimitry Andric os << getSourceLocation(newFile, newSc, newSectionOffset,
70185868e8aSDimitry Andric existing->getName());
7020b57cec5SDimitry Andric
703bdd1243dSDimitry Andric if (ctx.config.forceMultiple)
70485868e8aSDimitry Andric warn(os.str());
7050b57cec5SDimitry Andric else
70685868e8aSDimitry Andric error(os.str());
7070b57cec5SDimitry Andric }
7080b57cec5SDimitry Andric
addAbsolute(StringRef n,COFFSymbolRef sym)7090b57cec5SDimitry Andric Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) {
710bdd1243dSDimitry Andric auto [s, wasInserted] = insert(n, nullptr);
7110b57cec5SDimitry Andric s->isUsedInRegularObj = true;
71285868e8aSDimitry Andric if (wasInserted || isa<Undefined>(s) || s->isLazy())
713bdd1243dSDimitry Andric replaceSymbol<DefinedAbsolute>(s, ctx, n, sym);
714480093f4SDimitry Andric else if (auto *da = dyn_cast<DefinedAbsolute>(s)) {
715480093f4SDimitry Andric if (da->getVA() != sym.getValue())
716480093f4SDimitry Andric reportDuplicate(s, nullptr);
717480093f4SDimitry Andric } else if (!isa<DefinedCOFF>(s))
7180b57cec5SDimitry Andric reportDuplicate(s, nullptr);
7190b57cec5SDimitry Andric return s;
7200b57cec5SDimitry Andric }
7210b57cec5SDimitry Andric
addAbsolute(StringRef n,uint64_t va)7220b57cec5SDimitry Andric Symbol *SymbolTable::addAbsolute(StringRef n, uint64_t va) {
723bdd1243dSDimitry Andric auto [s, wasInserted] = insert(n, nullptr);
7240b57cec5SDimitry Andric s->isUsedInRegularObj = true;
72585868e8aSDimitry Andric if (wasInserted || isa<Undefined>(s) || s->isLazy())
726bdd1243dSDimitry Andric replaceSymbol<DefinedAbsolute>(s, ctx, n, va);
727480093f4SDimitry Andric else if (auto *da = dyn_cast<DefinedAbsolute>(s)) {
728480093f4SDimitry Andric if (da->getVA() != va)
729480093f4SDimitry Andric reportDuplicate(s, nullptr);
730480093f4SDimitry Andric } else if (!isa<DefinedCOFF>(s))
7310b57cec5SDimitry Andric reportDuplicate(s, nullptr);
7320b57cec5SDimitry Andric return s;
7330b57cec5SDimitry Andric }
7340b57cec5SDimitry Andric
addSynthetic(StringRef n,Chunk * c)7350b57cec5SDimitry Andric Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) {
736bdd1243dSDimitry Andric auto [s, wasInserted] = insert(n, nullptr);
7370b57cec5SDimitry Andric s->isUsedInRegularObj = true;
73885868e8aSDimitry Andric if (wasInserted || isa<Undefined>(s) || s->isLazy())
7390b57cec5SDimitry Andric replaceSymbol<DefinedSynthetic>(s, n, c);
7400b57cec5SDimitry Andric else if (!isa<DefinedCOFF>(s))
7410b57cec5SDimitry Andric reportDuplicate(s, nullptr);
7420b57cec5SDimitry Andric return s;
7430b57cec5SDimitry Andric }
7440b57cec5SDimitry Andric
addRegular(InputFile * f,StringRef n,const coff_symbol_generic * sym,SectionChunk * c,uint32_t sectionOffset,bool isWeak)7450b57cec5SDimitry Andric Symbol *SymbolTable::addRegular(InputFile *f, StringRef n,
74685868e8aSDimitry Andric const coff_symbol_generic *sym, SectionChunk *c,
747bdd1243dSDimitry Andric uint32_t sectionOffset, bool isWeak) {
748bdd1243dSDimitry Andric auto [s, wasInserted] = insert(n, f);
749bdd1243dSDimitry Andric if (wasInserted || !isa<DefinedRegular>(s) || s->isWeak)
7500b57cec5SDimitry Andric replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ false,
751bdd1243dSDimitry Andric /*IsExternal*/ true, sym, c, isWeak);
752bdd1243dSDimitry Andric else if (!isWeak)
75385868e8aSDimitry Andric reportDuplicate(s, f, c, sectionOffset);
7540b57cec5SDimitry Andric return s;
7550b57cec5SDimitry Andric }
7560b57cec5SDimitry Andric
7570b57cec5SDimitry Andric std::pair<DefinedRegular *, bool>
addComdat(InputFile * f,StringRef n,const coff_symbol_generic * sym)7580b57cec5SDimitry Andric SymbolTable::addComdat(InputFile *f, StringRef n,
7590b57cec5SDimitry Andric const coff_symbol_generic *sym) {
760bdd1243dSDimitry Andric auto [s, wasInserted] = insert(n, f);
7610b57cec5SDimitry Andric if (wasInserted || !isa<DefinedRegular>(s)) {
7620b57cec5SDimitry Andric replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ true,
7630b57cec5SDimitry Andric /*IsExternal*/ true, sym, nullptr);
7640b57cec5SDimitry Andric return {cast<DefinedRegular>(s), true};
7650b57cec5SDimitry Andric }
7660b57cec5SDimitry Andric auto *existingSymbol = cast<DefinedRegular>(s);
7670b57cec5SDimitry Andric if (!existingSymbol->isCOMDAT)
7680b57cec5SDimitry Andric reportDuplicate(s, f);
7690b57cec5SDimitry Andric return {existingSymbol, false};
7700b57cec5SDimitry Andric }
7710b57cec5SDimitry Andric
addCommon(InputFile * f,StringRef n,uint64_t size,const coff_symbol_generic * sym,CommonChunk * c)7720b57cec5SDimitry Andric Symbol *SymbolTable::addCommon(InputFile *f, StringRef n, uint64_t size,
7730b57cec5SDimitry Andric const coff_symbol_generic *sym, CommonChunk *c) {
774bdd1243dSDimitry Andric auto [s, wasInserted] = insert(n, f);
7750b57cec5SDimitry Andric if (wasInserted || !isa<DefinedCOFF>(s))
7760b57cec5SDimitry Andric replaceSymbol<DefinedCommon>(s, f, n, size, sym, c);
7770b57cec5SDimitry Andric else if (auto *dc = dyn_cast<DefinedCommon>(s))
7780b57cec5SDimitry Andric if (size > dc->getSize())
7790b57cec5SDimitry Andric replaceSymbol<DefinedCommon>(s, f, n, size, sym, c);
7800b57cec5SDimitry Andric return s;
7810b57cec5SDimitry Andric }
7820b57cec5SDimitry Andric
addImportData(StringRef n,ImportFile * f)7830b57cec5SDimitry Andric Symbol *SymbolTable::addImportData(StringRef n, ImportFile *f) {
784bdd1243dSDimitry Andric auto [s, wasInserted] = insert(n, nullptr);
7850b57cec5SDimitry Andric s->isUsedInRegularObj = true;
78685868e8aSDimitry Andric if (wasInserted || isa<Undefined>(s) || s->isLazy()) {
7870b57cec5SDimitry Andric replaceSymbol<DefinedImportData>(s, n, f);
7880b57cec5SDimitry Andric return s;
7890b57cec5SDimitry Andric }
7900b57cec5SDimitry Andric
7910b57cec5SDimitry Andric reportDuplicate(s, f);
7920b57cec5SDimitry Andric return nullptr;
7930b57cec5SDimitry Andric }
7940b57cec5SDimitry Andric
addImportThunk(StringRef name,DefinedImportData * id,uint16_t machine)7950b57cec5SDimitry Andric Symbol *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id,
7960b57cec5SDimitry Andric uint16_t machine) {
797bdd1243dSDimitry Andric auto [s, wasInserted] = insert(name, nullptr);
7980b57cec5SDimitry Andric s->isUsedInRegularObj = true;
79985868e8aSDimitry Andric if (wasInserted || isa<Undefined>(s) || s->isLazy()) {
800bdd1243dSDimitry Andric replaceSymbol<DefinedImportThunk>(s, ctx, name, id, machine);
8010b57cec5SDimitry Andric return s;
8020b57cec5SDimitry Andric }
8030b57cec5SDimitry Andric
8040b57cec5SDimitry Andric reportDuplicate(s, id->file);
8050b57cec5SDimitry Andric return nullptr;
8060b57cec5SDimitry Andric }
8070b57cec5SDimitry Andric
addLibcall(StringRef name)8080b57cec5SDimitry Andric void SymbolTable::addLibcall(StringRef name) {
8090b57cec5SDimitry Andric Symbol *sym = findUnderscore(name);
8100b57cec5SDimitry Andric if (!sym)
8110b57cec5SDimitry Andric return;
8120b57cec5SDimitry Andric
81385868e8aSDimitry Andric if (auto *l = dyn_cast<LazyArchive>(sym)) {
8140b57cec5SDimitry Andric MemoryBufferRef mb = l->getMemberBuffer();
81585868e8aSDimitry Andric if (isBitcode(mb))
81685868e8aSDimitry Andric addUndefined(sym->getName());
81785868e8aSDimitry Andric } else if (LazyObject *o = dyn_cast<LazyObject>(sym)) {
81885868e8aSDimitry Andric if (isBitcode(o->file->mb))
8190b57cec5SDimitry Andric addUndefined(sym->getName());
8200b57cec5SDimitry Andric }
8210b57cec5SDimitry Andric }
8220b57cec5SDimitry Andric
getChunks() const823349cc55cSDimitry Andric std::vector<Chunk *> SymbolTable::getChunks() const {
8240b57cec5SDimitry Andric std::vector<Chunk *> res;
825349cc55cSDimitry Andric for (ObjFile *file : ctx.objFileInstances) {
8260b57cec5SDimitry Andric ArrayRef<Chunk *> v = file->getChunks();
8270b57cec5SDimitry Andric res.insert(res.end(), v.begin(), v.end());
8280b57cec5SDimitry Andric }
8290b57cec5SDimitry Andric return res;
8300b57cec5SDimitry Andric }
8310b57cec5SDimitry Andric
find(StringRef name) const832349cc55cSDimitry Andric Symbol *SymbolTable::find(StringRef name) const {
8330b57cec5SDimitry Andric return symMap.lookup(CachedHashStringRef(name));
8340b57cec5SDimitry Andric }
8350b57cec5SDimitry Andric
findUnderscore(StringRef name) const836349cc55cSDimitry Andric Symbol *SymbolTable::findUnderscore(StringRef name) const {
837bdd1243dSDimitry Andric if (ctx.config.machine == I386)
8380b57cec5SDimitry Andric return find(("_" + name).str());
8390b57cec5SDimitry Andric return find(name);
8400b57cec5SDimitry Andric }
8410b57cec5SDimitry Andric
8420b57cec5SDimitry Andric // Return all symbols that start with Prefix, possibly ignoring the first
8430b57cec5SDimitry Andric // character of Prefix or the first character symbol.
getSymsWithPrefix(StringRef prefix)8440b57cec5SDimitry Andric std::vector<Symbol *> SymbolTable::getSymsWithPrefix(StringRef prefix) {
8450b57cec5SDimitry Andric std::vector<Symbol *> syms;
8460b57cec5SDimitry Andric for (auto pair : symMap) {
8470b57cec5SDimitry Andric StringRef name = pair.first.val();
84806c3fb27SDimitry Andric if (name.starts_with(prefix) || name.starts_with(prefix.drop_front()) ||
84906c3fb27SDimitry Andric name.drop_front().starts_with(prefix) ||
85006c3fb27SDimitry Andric name.drop_front().starts_with(prefix.drop_front())) {
8510b57cec5SDimitry Andric syms.push_back(pair.second);
8520b57cec5SDimitry Andric }
8530b57cec5SDimitry Andric }
8540b57cec5SDimitry Andric return syms;
8550b57cec5SDimitry Andric }
8560b57cec5SDimitry Andric
findMangle(StringRef name)8570b57cec5SDimitry Andric Symbol *SymbolTable::findMangle(StringRef name) {
858bdd1243dSDimitry Andric if (Symbol *sym = find(name)) {
859bdd1243dSDimitry Andric if (auto *u = dyn_cast<Undefined>(sym)) {
860bdd1243dSDimitry Andric // We're specifically looking for weak aliases that ultimately resolve to
861bdd1243dSDimitry Andric // defined symbols, hence the call to getWeakAlias() instead of just using
862bdd1243dSDimitry Andric // the weakAlias member variable. This matches link.exe's behavior.
863bdd1243dSDimitry Andric if (Symbol *weakAlias = u->getWeakAlias())
864bdd1243dSDimitry Andric return weakAlias;
865bdd1243dSDimitry Andric } else {
8660b57cec5SDimitry Andric return sym;
867bdd1243dSDimitry Andric }
868bdd1243dSDimitry Andric }
8690b57cec5SDimitry Andric
8700b57cec5SDimitry Andric // Efficient fuzzy string lookup is impossible with a hash table, so iterate
8710b57cec5SDimitry Andric // the symbol table once and collect all possibly matching symbols into this
8720b57cec5SDimitry Andric // vector. Then compare each possibly matching symbol with each possible
8730b57cec5SDimitry Andric // mangling.
8740b57cec5SDimitry Andric std::vector<Symbol *> syms = getSymsWithPrefix(name);
8750b57cec5SDimitry Andric auto findByPrefix = [&syms](const Twine &t) -> Symbol * {
8760b57cec5SDimitry Andric std::string prefix = t.str();
8770b57cec5SDimitry Andric for (auto *s : syms)
87806c3fb27SDimitry Andric if (s->getName().starts_with(prefix))
8790b57cec5SDimitry Andric return s;
8800b57cec5SDimitry Andric return nullptr;
8810b57cec5SDimitry Andric };
8820b57cec5SDimitry Andric
8830b57cec5SDimitry Andric // For non-x86, just look for C++ functions.
884bdd1243dSDimitry Andric if (ctx.config.machine != I386)
8850b57cec5SDimitry Andric return findByPrefix("?" + name + "@@Y");
8860b57cec5SDimitry Andric
88706c3fb27SDimitry Andric if (!name.starts_with("_"))
8880b57cec5SDimitry Andric return nullptr;
8890b57cec5SDimitry Andric // Search for x86 stdcall function.
8900b57cec5SDimitry Andric if (Symbol *s = findByPrefix(name + "@"))
8910b57cec5SDimitry Andric return s;
8920b57cec5SDimitry Andric // Search for x86 fastcall function.
8930b57cec5SDimitry Andric if (Symbol *s = findByPrefix("@" + name.substr(1) + "@"))
8940b57cec5SDimitry Andric return s;
8950b57cec5SDimitry Andric // Search for x86 vectorcall function.
8960b57cec5SDimitry Andric if (Symbol *s = findByPrefix(name.substr(1) + "@@"))
8970b57cec5SDimitry Andric return s;
8980b57cec5SDimitry Andric // Search for x86 C++ non-member function.
8990b57cec5SDimitry Andric return findByPrefix("?" + name.substr(1) + "@@Y");
9000b57cec5SDimitry Andric }
9010b57cec5SDimitry Andric
addUndefined(StringRef name)9020b57cec5SDimitry Andric Symbol *SymbolTable::addUndefined(StringRef name) {
9030b57cec5SDimitry Andric return addUndefined(name, nullptr, false);
9040b57cec5SDimitry Andric }
9050b57cec5SDimitry Andric
compileBitcodeFiles()906349cc55cSDimitry Andric void SymbolTable::compileBitcodeFiles() {
9075f757f3fSDimitry Andric ltoCompilationDone = true;
908349cc55cSDimitry Andric if (ctx.bitcodeFileInstances.empty())
9090b57cec5SDimitry Andric return;
9100b57cec5SDimitry Andric
9115f757f3fSDimitry Andric llvm::TimeTraceScope timeScope("Compile bitcode");
912349cc55cSDimitry Andric ScopedTimer t(ctx.ltoTimer);
913bdd1243dSDimitry Andric lto.reset(new BitcodeCompiler(ctx));
914349cc55cSDimitry Andric for (BitcodeFile *f : ctx.bitcodeFileInstances)
9155ffd83dbSDimitry Andric lto->add(*f);
916bdd1243dSDimitry Andric for (InputFile *newObj : lto->compile()) {
9175ffd83dbSDimitry Andric ObjFile *obj = cast<ObjFile>(newObj);
9180b57cec5SDimitry Andric obj->parse();
919349cc55cSDimitry Andric ctx.objFileInstances.push_back(obj);
9200b57cec5SDimitry Andric }
9210b57cec5SDimitry Andric }
9220b57cec5SDimitry Andric
923bdd1243dSDimitry Andric } // namespace lld::coff
924