1//===- SymbolTable.cpp ----------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "SymbolTable.h"
10#include "COFFLinkerContext.h"
11#include "Config.h"
12#include "Driver.h"
13#include "LTO.h"
14#include "PDB.h"
15#include "Symbols.h"
16#include "lld/Common/ErrorHandler.h"
17#include "lld/Common/Memory.h"
18#include "lld/Common/Timer.h"
19#include "llvm/DebugInfo/DIContext.h"
20#include "llvm/IR/LLVMContext.h"
21#include "llvm/IR/Mangler.h"
22#include "llvm/LTO/LTO.h"
23#include "llvm/Object/COFFModuleDefinition.h"
24#include "llvm/Support/Debug.h"
25#include "llvm/Support/GlobPattern.h"
26#include "llvm/Support/Parallel.h"
27#include "llvm/Support/TimeProfiler.h"
28#include "llvm/Support/raw_ostream.h"
29#include <utility>
30
31using namespace llvm;
32using namespace llvm::COFF;
33using namespace llvm::object;
34using namespace llvm::support;
35
36namespace lld::coff {
37
38StringRef ltrim1(StringRef s, const char *chars) {
39 if (!s.empty() && strchr(s: chars, c: s[0]))
40 return s.substr(Start: 1);
41 return s;
42}
43
44static COFFSyncStream errorOrWarn(COFFLinkerContext &ctx) {
45 return {ctx, ctx.config.forceUnresolved ? DiagLevel::Warn : DiagLevel::Err};
46}
47
48// Causes the file associated with a lazy symbol to be linked in.
49static void forceLazy(Symbol *s) {
50 s->pendingArchiveLoad = true;
51 switch (s->kind()) {
52 case Symbol::Kind::LazyArchiveKind: {
53 auto *l = cast<LazyArchive>(Val: s);
54 l->file->addMember(sym: l->sym);
55 break;
56 }
57 case Symbol::Kind::LazyObjectKind: {
58 InputFile *file = cast<LazyObject>(Val: s)->file;
59 // FIXME: Remove this once we resolve all defineds before all undefineds in
60 // ObjFile::initializeSymbols().
61 if (!file->lazy)
62 return;
63 file->lazy = false;
64 file->symtab.ctx.driver.addFile(file);
65 break;
66 }
67 case Symbol::Kind::LazyDLLSymbolKind: {
68 auto *l = cast<LazyDLLSymbol>(Val: s);
69 l->file->makeImport(s: l->sym);
70 break;
71 }
72 default:
73 llvm_unreachable(
74 "symbol passed to forceLazy is not a LazyArchive or LazyObject");
75 }
76}
77
78// Returns the symbol in SC whose value is <= Addr that is closest to Addr.
79// This is generally the global variable or function whose definition contains
80// Addr.
81static Symbol *getSymbol(SectionChunk *sc, uint32_t addr) {
82 DefinedRegular *candidate = nullptr;
83
84 for (Symbol *s : sc->file->getSymbols()) {
85 auto *d = dyn_cast_or_null<DefinedRegular>(Val: s);
86 if (!d || !d->data || d->file != sc->file || d->getChunk() != sc ||
87 d->getValue() > addr ||
88 (candidate && d->getValue() < candidate->getValue()))
89 continue;
90
91 candidate = d;
92 }
93
94 return candidate;
95}
96
97static std::vector<std::string> getSymbolLocations(BitcodeFile *file) {
98 std::string res("\n>>> referenced by ");
99 StringRef source = file->obj->getSourceFileName();
100 if (!source.empty())
101 res += source.str() + "\n>>> ";
102 res += toString(file);
103 return {res};
104}
105
106static std::optional<std::pair<StringRef, uint32_t>>
107getFileLineDwarf(const SectionChunk *c, uint32_t addr) {
108 std::optional<DILineInfo> optionalLineInfo =
109 c->file->getDILineInfo(offset: addr, sectionIndex: c->getSectionNumber() - 1);
110 if (!optionalLineInfo)
111 return std::nullopt;
112 const DILineInfo &lineInfo = *optionalLineInfo;
113 if (lineInfo.FileName == DILineInfo::BadString)
114 return std::nullopt;
115 return std::make_pair(x: saver().save(S: lineInfo.FileName), y: lineInfo.Line);
116}
117
118static std::optional<std::pair<StringRef, uint32_t>>
119getFileLine(const SectionChunk *c, uint32_t addr) {
120 // MinGW can optionally use codeview, even if the default is dwarf.
121 std::optional<std::pair<StringRef, uint32_t>> fileLine =
122 getFileLineCodeView(c, addr);
123 // If codeview didn't yield any result, check dwarf in MinGW mode.
124 if (!fileLine && c->file->symtab.ctx.config.mingw)
125 fileLine = getFileLineDwarf(c, addr);
126 return fileLine;
127}
128
129// Given a file and the index of a symbol in that file, returns a description
130// of all references to that symbol from that file. If no debug information is
131// available, returns just the name of the file, else one string per actual
132// reference as described in the debug info.
133// Returns up to maxStrings string descriptions, along with the total number of
134// locations found.
135static std::pair<std::vector<std::string>, size_t>
136getSymbolLocations(ObjFile *file, uint32_t symIndex, size_t maxStrings) {
137 struct Location {
138 Symbol *sym;
139 std::pair<StringRef, uint32_t> fileLine;
140 };
141 std::vector<Location> locations;
142 size_t numLocations = 0;
143
144 for (Chunk *c : file->getChunks()) {
145 auto *sc = dyn_cast<SectionChunk>(Val: c);
146 if (!sc)
147 continue;
148 for (const coff_relocation &r : sc->getRelocs()) {
149 if (r.SymbolTableIndex != symIndex)
150 continue;
151 numLocations++;
152 if (locations.size() >= maxStrings)
153 continue;
154
155 std::optional<std::pair<StringRef, uint32_t>> fileLine =
156 getFileLine(c: sc, addr: r.VirtualAddress);
157 Symbol *sym = getSymbol(sc, addr: r.VirtualAddress);
158 if (fileLine)
159 locations.push_back(x: {.sym: sym, .fileLine: *fileLine});
160 else if (sym)
161 locations.push_back(x: {.sym: sym, .fileLine: {"", 0}});
162 }
163 }
164
165 if (maxStrings == 0)
166 return std::make_pair(x: std::vector<std::string>(), y&: numLocations);
167
168 if (numLocations == 0)
169 return std::make_pair(
170 x: std::vector<std::string>{"\n>>> referenced by " + toString(file)}, y: 1);
171
172 std::vector<std::string> symbolLocations(locations.size());
173 size_t i = 0;
174 for (Location loc : locations) {
175 llvm::raw_string_ostream os(symbolLocations[i++]);
176 os << "\n>>> referenced by ";
177 if (!loc.fileLine.first.empty())
178 os << loc.fileLine.first << ":" << loc.fileLine.second
179 << "\n>>> ";
180 os << toString(file);
181 if (loc.sym)
182 os << ":(" << toString(ctx: file->symtab.ctx, b&: *loc.sym) << ')';
183 }
184 return std::make_pair(x&: symbolLocations, y&: numLocations);
185}
186
187std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {
188 return getSymbolLocations(file, symIndex, SIZE_MAX).first;
189}
190
191static std::pair<std::vector<std::string>, size_t>
192getSymbolLocations(InputFile *file, uint32_t symIndex, size_t maxStrings) {
193 if (auto *o = dyn_cast<ObjFile>(Val: file))
194 return getSymbolLocations(file: o, symIndex, maxStrings);
195 if (auto *b = dyn_cast<BitcodeFile>(Val: file)) {
196 std::vector<std::string> symbolLocations = getSymbolLocations(file: b);
197 size_t numLocations = symbolLocations.size();
198 if (symbolLocations.size() > maxStrings)
199 symbolLocations.resize(new_size: maxStrings);
200 return std::make_pair(x&: symbolLocations, y&: numLocations);
201 }
202 llvm_unreachable("unsupported file type passed to getSymbolLocations");
203 return std::make_pair(x: std::vector<std::string>(), y: (size_t)0);
204}
205
206// For an undefined symbol, stores all files referencing it and the index of
207// the undefined symbol in each file.
208struct UndefinedDiag {
209 Symbol *sym;
210 struct File {
211 InputFile *file;
212 uint32_t symIndex;
213 };
214 std::vector<File> files;
215};
216
217void SymbolTable::reportUndefinedSymbol(const UndefinedDiag &undefDiag) {
218 auto diag = errorOrWarn(ctx);
219 diag << "undefined symbol: " << printSymbol(sym: undefDiag.sym);
220
221 const size_t maxUndefReferences = 3;
222 size_t numDisplayedRefs = 0, numRefs = 0;
223 for (const UndefinedDiag::File &ref : undefDiag.files) {
224 auto [symbolLocations, totalLocations] = getSymbolLocations(
225 file: ref.file, symIndex: ref.symIndex, maxStrings: maxUndefReferences - numDisplayedRefs);
226
227 numRefs += totalLocations;
228 numDisplayedRefs += symbolLocations.size();
229 for (const std::string &s : symbolLocations)
230 diag << s;
231 }
232 if (numDisplayedRefs < numRefs)
233 diag << "\n>>> referenced " << numRefs - numDisplayedRefs << " more times";
234
235 // Hints
236 StringRef name = undefDiag.sym->getName();
237 if (name.consume_front(Prefix: "__imp_")) {
238 Symbol *imp = find(name);
239 if (imp && imp->isLazy()) {
240 diag << "\nNOTE: a relevant symbol '" << imp->getName()
241 << "' is available in " << toString(file: imp->getFile())
242 << " but cannot be used because it is not an import library.";
243 }
244 }
245}
246
247void SymbolTable::loadMinGWSymbols() {
248 std::vector<Symbol *> undefs;
249 for (auto &i : symMap) {
250 Symbol *sym = i.second;
251 auto *undef = dyn_cast<Undefined>(Val: sym);
252 if (!undef)
253 continue;
254 if (undef->getWeakAlias())
255 continue;
256 undefs.push_back(x: sym);
257 }
258
259 for (auto sym : undefs) {
260 auto *undef = dyn_cast<Undefined>(Val: sym);
261 if (!undef)
262 continue;
263 if (undef->getWeakAlias())
264 continue;
265 StringRef name = undef->getName();
266
267 if (machine == I386 && ctx.config.stdcallFixup) {
268 // Check if we can resolve an undefined decorated symbol by finding
269 // the intended target as an undecorated symbol (only with a leading
270 // underscore).
271 StringRef origName = name;
272 StringRef baseName = name;
273 // Trim down stdcall/fastcall/vectorcall symbols to the base name.
274 baseName = ltrim1(s: baseName, chars: "_@");
275 baseName = baseName.substr(Start: 0, N: baseName.find(C: '@'));
276 // Add a leading underscore, as it would be in cdecl form.
277 std::string newName = ("_" + baseName).str();
278 Symbol *l;
279 if (newName != origName && (l = find(name: newName)) != nullptr) {
280 // If we found a symbol and it is lazy; load it.
281 if (l->isLazy() && !l->pendingArchiveLoad) {
282 Log(ctx) << "Loading lazy " << l->getName() << " from "
283 << l->getFile()->getName() << " for stdcall fixup";
284 forceLazy(s: l);
285 }
286 // If it's lazy or already defined, hook it up as weak alias.
287 if (l->isLazy() || isa<Defined>(Val: l)) {
288 if (ctx.config.warnStdcallFixup)
289 Warn(ctx) << "Resolving " << origName << " by linking to "
290 << newName;
291 else
292 Log(ctx) << "Resolving " << origName << " by linking to "
293 << newName;
294 undef->setWeakAlias(sym: l);
295 continue;
296 }
297 }
298 }
299
300 if (ctx.config.autoImport) {
301 if (name.starts_with(Prefix: "__imp_"))
302 continue;
303 // If we have an undefined symbol, but we have a lazy symbol we could
304 // load, load it.
305 Symbol *l = find(name: ("__imp_" + name).str());
306 if (!l || l->pendingArchiveLoad || !l->isLazy())
307 continue;
308
309 Log(ctx) << "Loading lazy " << l->getName() << " from "
310 << l->getFile()->getName() << " for automatic import";
311 forceLazy(s: l);
312 }
313 }
314}
315
316Defined *SymbolTable::impSymbol(StringRef name) {
317 if (name.starts_with(Prefix: "__imp_"))
318 return nullptr;
319 return dyn_cast_or_null<Defined>(Val: find(name: ("__imp_" + name).str()));
320}
321
322bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {
323 Defined *imp = impSymbol(name);
324 if (!imp)
325 return false;
326
327 // Replace the reference directly to a variable with a reference
328 // to the import address table instead. This obviously isn't right,
329 // but we mark the symbol as isRuntimePseudoReloc, and a later pass
330 // will add runtime pseudo relocations for every relocation against
331 // this Symbol. The runtime pseudo relocation framework expects the
332 // reference itself to point at the IAT entry.
333 size_t impSize = 0;
334 if (isa<DefinedImportData>(Val: imp)) {
335 Log(ctx) << "Automatically importing " << name << " from "
336 << cast<DefinedImportData>(Val: imp)->getDLLName();
337 impSize = sizeof(DefinedImportData);
338 } else if (isa<DefinedRegular>(Val: imp)) {
339 Log(ctx) << "Automatically importing " << name << " from "
340 << toString(file: cast<DefinedRegular>(Val: imp)->file);
341 impSize = sizeof(DefinedRegular);
342 } else {
343 Warn(ctx) << "unable to automatically import " << name << " from "
344 << imp->getName() << " from " << cast<DefinedRegular>(Val: imp)->file
345 << "; unexpected symbol type";
346 return false;
347 }
348 sym->replaceKeepingName(other: imp, size: impSize);
349 sym->isRuntimePseudoReloc = true;
350
351 // There may exist symbols named .refptr.<name> which only consist
352 // of a single pointer to <name>. If it turns out <name> is
353 // automatically imported, we don't need to keep the .refptr.<name>
354 // pointer at all, but redirect all accesses to it to the IAT entry
355 // for __imp_<name> instead, and drop the whole .refptr.<name> chunk.
356 DefinedRegular *refptr =
357 dyn_cast_or_null<DefinedRegular>(Val: find(name: (".refptr." + name).str()));
358 if (refptr && refptr->getChunk()->getSize() == ctx.config.wordsize) {
359 SectionChunk *sc = dyn_cast_or_null<SectionChunk>(Val: refptr->getChunk());
360 if (sc && sc->getRelocs().size() == 1 && *sc->symbols().begin() == sym) {
361 Log(ctx) << "Replacing .refptr." << name << " with " << imp->getName();
362 refptr->getChunk()->live = false;
363 refptr->replaceKeepingName(other: imp, size: impSize);
364 }
365 }
366 return true;
367}
368
369/// Helper function for reportUnresolvable and resolveRemainingUndefines.
370/// This function emits an "undefined symbol" diagnostic for each symbol in
371/// undefs. If localImports is not nullptr, it also emits a "locally
372/// defined symbol imported" diagnostic for symbols in localImports.
373/// objFiles and bitcodeFiles (if not nullptr) are used to report where
374/// undefined symbols are referenced.
375void SymbolTable::reportProblemSymbols(
376 const SmallPtrSetImpl<Symbol *> &undefs,
377 const DenseMap<Symbol *, Symbol *> *localImports, bool needBitcodeFiles) {
378 // Return early if there is nothing to report (which should be
379 // the common case).
380 if (undefs.empty() && (!localImports || localImports->empty()))
381 return;
382
383 for (Symbol *b : ctx.config.gcroot) {
384 if (undefs.contains(Ptr: b))
385 errorOrWarn(ctx) << "<root>: undefined symbol: " << printSymbol(sym: b);
386 if (localImports)
387 if (Symbol *imp = localImports->lookup(Val: b))
388 Warn(ctx) << "<root>: locally defined symbol imported: "
389 << printSymbol(sym: imp) << " (defined in "
390 << toString(file: imp->getFile()) << ") [LNK4217]";
391 }
392
393 std::vector<UndefinedDiag> undefDiags;
394 DenseMap<Symbol *, int> firstDiag;
395
396 auto processFile = [&](InputFile *file, ArrayRef<Symbol *> symbols) {
397 uint32_t symIndex = (uint32_t)-1;
398 for (Symbol *sym : symbols) {
399 ++symIndex;
400 if (!sym)
401 continue;
402 if (undefs.contains(Ptr: sym)) {
403 auto [it, inserted] = firstDiag.try_emplace(Key: sym, Args: undefDiags.size());
404 if (inserted)
405 undefDiags.push_back(x: {.sym: sym, .files: {{.file: file, .symIndex: symIndex}}});
406 else
407 undefDiags[it->second].files.push_back(x: {.file: file, .symIndex: symIndex});
408 }
409 if (localImports)
410 if (Symbol *imp = localImports->lookup(Val: sym))
411 Warn(ctx) << file
412 << ": locally defined symbol imported: " << printSymbol(sym: imp)
413 << " (defined in " << imp->getFile() << ") [LNK4217]";
414 }
415 };
416
417 for (ObjFile *file : ctx.objFileInstances)
418 processFile(file, file->getSymbols());
419
420 if (needBitcodeFiles)
421 for (BitcodeFile *file : bitcodeFileInstances)
422 processFile(file, file->getSymbols());
423
424 for (const UndefinedDiag &undefDiag : undefDiags)
425 reportUndefinedSymbol(undefDiag);
426}
427
428void SymbolTable::reportUnresolvable() {
429 SmallPtrSet<Symbol *, 8> undefs;
430 for (auto &i : symMap) {
431 Symbol *sym = i.second;
432 auto *undef = dyn_cast<Undefined>(Val: sym);
433 if (!undef || sym->deferUndefined)
434 continue;
435 if (undef->getWeakAlias())
436 continue;
437 StringRef name = undef->getName();
438 if (name.starts_with(Prefix: "__imp_")) {
439 Symbol *imp = find(name: name.substr(Start: strlen(s: "__imp_")));
440 if (Defined *def = dyn_cast_or_null<Defined>(Val: imp)) {
441 def->isUsedInRegularObj = true;
442 continue;
443 }
444 }
445 if (name.contains(Other: "_PchSym_"))
446 continue;
447 if (ctx.config.autoImport && impSymbol(name))
448 continue;
449 undefs.insert(Ptr: sym);
450 }
451
452 reportProblemSymbols(undefs, /*localImports=*/nullptr, needBitcodeFiles: true);
453}
454
455void SymbolTable::resolveRemainingUndefines(std::vector<Undefined *> &aliases) {
456 llvm::TimeTraceScope timeScope("Resolve remaining undefined symbols");
457 SmallPtrSet<Symbol *, 8> undefs;
458 DenseMap<Symbol *, Symbol *> localImports;
459
460 for (auto &i : symMap) {
461 Symbol *sym = i.second;
462 auto *undef = dyn_cast<Undefined>(Val: sym);
463 if (!undef)
464 continue;
465 if (!sym->isUsedInRegularObj)
466 continue;
467
468 StringRef name = undef->getName();
469
470 // A weak alias may have been resolved, so check for that.
471 if (undef->getWeakAlias()) {
472 aliases.push_back(x: undef);
473 continue;
474 }
475
476 // If we can resolve a symbol by removing __imp_ prefix, do that.
477 // This odd rule is for compatibility with MSVC linker.
478 if (name.starts_with(Prefix: "__imp_")) {
479 auto findLocalSym = [&](StringRef n) {
480 Symbol *sym = find(name: n);
481 return sym ? sym->getDefined() : nullptr;
482 };
483
484 StringRef impName = name.substr(Start: strlen(s: "__imp_"));
485 Defined *imp = findLocalSym(impName);
486 if (!imp && isEC()) {
487 // Try to use the mangled symbol on ARM64EC.
488 std::optional<std::string> mangledName =
489 getArm64ECMangledFunctionName(Name: impName);
490 if (mangledName)
491 imp = findLocalSym(*mangledName);
492 if (!imp && impName.consume_front(Prefix: "aux_")) {
493 // If it's a __imp_aux_ symbol, try skipping the aux_ prefix.
494 imp = findLocalSym(impName);
495 if (!imp && (mangledName = getArm64ECMangledFunctionName(Name: impName)))
496 imp = findLocalSym(*mangledName);
497 }
498 }
499 if (imp) {
500 replaceSymbol<DefinedLocalImport>(s: sym, arg&: ctx, arg&: name, arg&: imp);
501 localImportChunks.push_back(x: cast<DefinedLocalImport>(Val: sym)->getChunk());
502 localImports[sym] = imp;
503 continue;
504 }
505 }
506
507 // We don't want to report missing Microsoft precompiled headers symbols.
508 // A proper message will be emitted instead in PDBLinker::aquirePrecompObj
509 if (name.contains(Other: "_PchSym_"))
510 continue;
511
512 if (ctx.config.autoImport && handleMinGWAutomaticImport(sym, name))
513 continue;
514
515 // Remaining undefined symbols are not fatal if /force is specified.
516 // They are replaced with dummy defined symbols.
517 if (ctx.config.forceUnresolved)
518 replaceSymbol<DefinedAbsolute>(s: sym, arg&: ctx, arg&: name, arg: 0);
519 undefs.insert(Ptr: sym);
520 }
521
522 reportProblemSymbols(
523 undefs, localImports: ctx.config.warnLocallyDefinedImported ? &localImports : nullptr,
524 needBitcodeFiles: false);
525}
526
527std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
528 bool inserted = false;
529 Symbol *&sym = symMap[CachedHashStringRef(name)];
530 if (!sym) {
531 sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
532 sym->isUsedInRegularObj = false;
533 sym->pendingArchiveLoad = false;
534 sym->canInline = true;
535 inserted = true;
536
537 if (isEC() && name.starts_with(Prefix: "EXP+"))
538 expSymbols.push_back(x: sym);
539 }
540 return {sym, inserted};
541}
542
543std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, InputFile *file) {
544 std::pair<Symbol *, bool> result = insert(name);
545 if (!file || !isa<BitcodeFile>(Val: file))
546 result.first->isUsedInRegularObj = true;
547 return result;
548}
549
550void SymbolTable::initializeLoadConfig() {
551 auto sym =
552 dyn_cast_or_null<DefinedRegular>(Val: findUnderscore(name: "_load_config_used"));
553 if (!sym) {
554 if (isEC()) {
555 Warn(ctx) << "EC version of '_load_config_used' is missing";
556 return;
557 }
558 if (ctx.config.machine == ARM64X) {
559 Warn(ctx) << "native version of '_load_config_used' is missing for "
560 "ARM64X target";
561 return;
562 }
563 if (ctx.config.guardCF != GuardCFLevel::Off)
564 Warn(ctx)
565 << "Control Flow Guard is enabled but '_load_config_used' is missing";
566 if (ctx.config.dependentLoadFlags)
567 Warn(ctx) << "_load_config_used not found, /dependentloadflag will have "
568 "no effect";
569 return;
570 }
571
572 SectionChunk *sc = sym->getChunk();
573 if (!sc->hasData) {
574 Err(ctx) << "_load_config_used points to uninitialized data";
575 return;
576 }
577 uint64_t offsetInChunk = sym->getValue();
578 if (offsetInChunk + 4 > sc->getSize()) {
579 Err(ctx) << "_load_config_used section chunk is too small";
580 return;
581 }
582
583 ArrayRef<uint8_t> secContents = sc->getContents();
584 loadConfigSize =
585 *reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]);
586 if (offsetInChunk + loadConfigSize > sc->getSize()) {
587 Err(ctx) << "_load_config_used specifies a size larger than its containing "
588 "section chunk";
589 return;
590 }
591
592 uint32_t expectedAlign = ctx.config.is64() ? 8 : 4;
593 if (sc->getAlignment() < expectedAlign)
594 Warn(ctx) << "'_load_config_used' is misaligned (expected alignment to be "
595 << expectedAlign << " bytes, got " << sc->getAlignment()
596 << " instead)";
597 else if (!isAligned(Lhs: Align(expectedAlign), SizeInBytes: offsetInChunk))
598 Warn(ctx) << "'_load_config_used' is misaligned (section offset is 0x"
599 << Twine::utohexstr(Val: sym->getValue()) << " not aligned to "
600 << expectedAlign << " bytes)";
601
602 loadConfigSym = sym;
603}
604
605void SymbolTable::addEntryThunk(Symbol *from, Symbol *to) {
606 entryThunks.push_back(x: {from, to});
607}
608
609void SymbolTable::addExitThunk(Symbol *from, Symbol *to) {
610 exitThunks[from] = to;
611}
612
613void SymbolTable::initializeECThunks() {
614 if (!isArm64EC(Machine: ctx.config.machine))
615 return;
616
617 for (auto it : entryThunks) {
618 Defined *to = it.second->getDefined();
619 if (!to)
620 continue;
621 auto *from = dyn_cast_or_null<DefinedRegular>(Val: it.first->getDefined());
622 // We need to be able to add padding to the function and fill it with an
623 // offset to its entry thunks. To ensure that padding the function is
624 // feasible, functions are required to be COMDAT symbols with no offset.
625 if (!from || !from->getChunk()->isCOMDAT() ||
626 cast<DefinedRegular>(Val: from)->getValue()) {
627 Err(ctx) << "non COMDAT symbol '" << from->getName() << "' in hybrid map";
628 continue;
629 }
630 from->getChunk()->setEntryThunk(to);
631 }
632
633 for (ImportFile *file : ctx.importFileInstances) {
634 if (!file->impchkThunk)
635 continue;
636
637 Symbol *sym = exitThunks.lookup(Val: file->thunkSym);
638 if (!sym)
639 sym = exitThunks.lookup(Val: file->impECSym);
640 if (sym)
641 file->impchkThunk->exitThunk = sym->getDefined();
642 }
643
644 // On ARM64EC, the __imp_ symbol references the auxiliary IAT, while the
645 // __imp_aux_ symbol references the regular IAT. However, x86_64 code expects
646 // both to reference the regular IAT, so adjust the symbol if necessary.
647 parallelForEach(R&: ctx.objFileInstances, Fn: [&](ObjFile *file) {
648 if (file->getMachineType() != AMD64)
649 return;
650 for (auto &sym : file->getMutableSymbols()) {
651 auto impSym = dyn_cast_or_null<DefinedImportData>(Val: sym);
652 if (impSym && impSym->file->impchkThunk && sym == impSym->file->impECSym)
653 sym = impSym->file->impSym;
654 }
655 });
656}
657
658void SymbolTable::initializeSameAddressThunks() {
659 for (auto iter : ctx.config.sameAddresses) {
660 auto sym = dyn_cast_or_null<DefinedRegular>(Val: iter.first->getDefined());
661 if (!sym || !sym->isLive())
662 continue;
663 auto nativeSym =
664 dyn_cast_or_null<DefinedRegular>(Val: iter.second->getDefined());
665 if (!nativeSym || !nativeSym->isLive())
666 continue;
667 Defined *entryThunk = sym->getChunk()->getEntryThunk();
668 if (!entryThunk)
669 continue;
670
671 // Replace symbols with symbols referencing the thunk. Store the original
672 // symbol as equivalent DefinedSynthetic instances for use in the thunk
673 // itself.
674 auto symClone = make<DefinedSynthetic>(args: sym->getName(), args: sym->getChunk(),
675 args: sym->getValue());
676 auto nativeSymClone = make<DefinedSynthetic>(
677 args: nativeSym->getName(), args: nativeSym->getChunk(), args: nativeSym->getValue());
678 SameAddressThunkARM64EC *thunk =
679 make<SameAddressThunkARM64EC>(args&: nativeSymClone, args&: symClone, args&: entryThunk);
680 sameAddressThunks.push_back(x: thunk);
681
682 replaceSymbol<DefinedSynthetic>(s: sym, arg: sym->getName(), arg&: thunk);
683 replaceSymbol<DefinedSynthetic>(s: nativeSym, arg: nativeSym->getName(), arg&: thunk);
684 }
685}
686
687Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f,
688 bool overrideLazy) {
689 auto [s, wasInserted] = insert(name, file: f);
690 if (wasInserted || (s->isLazy() && overrideLazy)) {
691 replaceSymbol<Undefined>(s, arg&: name);
692 return s;
693 }
694 if (s->isLazy())
695 forceLazy(s);
696 return s;
697}
698
699Symbol *SymbolTable::addGCRoot(StringRef name, bool aliasEC) {
700 Symbol *b = addUndefined(name);
701 if (!b->isGCRoot) {
702 b->isGCRoot = true;
703 ctx.config.gcroot.push_back(x: b);
704 }
705
706 // On ARM64EC, a symbol may be defined in either its mangled or demangled form
707 // (or both). Define an anti-dependency symbol that binds both forms, similar
708 // to how compiler-generated code references external functions.
709 if (aliasEC && isEC()) {
710 if (std::optional<std::string> mangledName =
711 getArm64ECMangledFunctionName(Name: name)) {
712 auto u = dyn_cast<Undefined>(Val: b);
713 if (u && !u->weakAlias) {
714 Symbol *t = addUndefined(name: saver().save(S: *mangledName));
715 u->setWeakAlias(sym: t, antiDep: true);
716 }
717 } else if (std::optional<std::string> demangledName =
718 getArm64ECDemangledFunctionName(Name: name)) {
719 Symbol *us = addUndefined(name: saver().save(S: *demangledName));
720 auto u = dyn_cast<Undefined>(Val: us);
721 if (u && !u->weakAlias)
722 u->setWeakAlias(sym: b, antiDep: true);
723 }
724 }
725 return b;
726}
727
728// On ARM64EC, a function symbol may appear in both mangled and demangled forms:
729// - ARM64EC archives contain only the mangled name, while the demangled symbol
730// is defined by the object file as an alias.
731// - x86_64 archives contain only the demangled name (the mangled name is
732// usually defined by an object referencing the symbol as an alias to a guess
733// exit thunk).
734// - ARM64EC import files contain both the mangled and demangled names for
735// thunks.
736// If more than one archive defines the same function, this could lead
737// to different libraries being used for the same function depending on how they
738// are referenced. Avoid this by checking if the paired symbol is already
739// defined before adding a symbol to the table.
740template <typename T>
741bool checkLazyECPair(SymbolTable *symtab, StringRef name, InputFile *f) {
742 if (name.starts_with(Prefix: "__imp_"))
743 return true;
744 std::string pairName;
745 if (std::optional<std::string> mangledName =
746 getArm64ECMangledFunctionName(Name: name))
747 pairName = std::move(*mangledName);
748 else if (std::optional<std::string> demangledName =
749 getArm64ECDemangledFunctionName(Name: name))
750 pairName = std::move(*demangledName);
751 else
752 return true;
753
754 Symbol *sym = symtab->find(name: pairName);
755 if (!sym)
756 return true;
757 if (sym->pendingArchiveLoad)
758 return false;
759 if (auto u = dyn_cast<Undefined>(Val: sym))
760 return !u->weakAlias || u->isAntiDep;
761 // If the symbol is lazy, allow it only if it originates from the same
762 // archive.
763 auto lazy = dyn_cast<T>(sym);
764 return lazy && lazy->file == f;
765}
766
767void SymbolTable::addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym) {
768 StringRef name = sym.getName();
769 if (isEC() && !checkLazyECPair<LazyArchive>(symtab: this, name, f))
770 return;
771 auto [s, wasInserted] = insert(name);
772 if (wasInserted) {
773 replaceSymbol<LazyArchive>(s, arg&: f, arg: sym);
774 return;
775 }
776 auto *u = dyn_cast<Undefined>(Val: s);
777 if (!u || (u->weakAlias && !u->isECAlias(machine)) || s->pendingArchiveLoad)
778 return;
779 s->pendingArchiveLoad = true;
780 f->addMember(sym);
781}
782
783void SymbolTable::addLazyObject(InputFile *f, StringRef n) {
784 assert(f->lazy);
785 if (isEC() && !checkLazyECPair<LazyObject>(symtab: this, name: n, f))
786 return;
787 auto [s, wasInserted] = insert(name: n, file: f);
788 if (wasInserted) {
789 replaceSymbol<LazyObject>(s, arg&: f, arg&: n);
790 return;
791 }
792 auto *u = dyn_cast<Undefined>(Val: s);
793 if (!u || (u->weakAlias && !u->isECAlias(machine)) || s->pendingArchiveLoad)
794 return;
795 s->pendingArchiveLoad = true;
796 f->lazy = false;
797 ctx.driver.addFile(file: f);
798}
799
800void SymbolTable::addLazyDLLSymbol(DLLFile *f, DLLFile::Symbol *sym,
801 StringRef n) {
802 auto [s, wasInserted] = insert(name: n);
803 if (wasInserted) {
804 replaceSymbol<LazyDLLSymbol>(s, arg&: f, arg&: sym, arg&: n);
805 return;
806 }
807 auto *u = dyn_cast<Undefined>(Val: s);
808 if (!u || (u->weakAlias && !u->isECAlias(machine)) || s->pendingArchiveLoad)
809 return;
810 s->pendingArchiveLoad = true;
811 f->makeImport(s: sym);
812}
813
814static std::string getSourceLocationBitcode(BitcodeFile *file) {
815 std::string res("\n>>> defined at ");
816 StringRef source = file->obj->getSourceFileName();
817 if (!source.empty())
818 res += source.str() + "\n>>> ";
819 res += toString(file);
820 return res;
821}
822
823static std::string getSourceLocationObj(ObjFile *file, SectionChunk *sc,
824 uint32_t offset, StringRef name) {
825 std::optional<std::pair<StringRef, uint32_t>> fileLine;
826 if (sc)
827 fileLine = getFileLine(c: sc, addr: offset);
828 if (!fileLine)
829 fileLine = file->getVariableLocation(var: name);
830
831 std::string res;
832 llvm::raw_string_ostream os(res);
833 os << "\n>>> defined at ";
834 if (fileLine)
835 os << fileLine->first << ":" << fileLine->second << "\n>>> ";
836 os << toString(file);
837 return res;
838}
839
840static std::string getSourceLocation(InputFile *file, SectionChunk *sc,
841 uint32_t offset, StringRef name) {
842 if (!file)
843 return "";
844 if (auto *o = dyn_cast<ObjFile>(Val: file))
845 return getSourceLocationObj(file: o, sc, offset, name);
846 if (auto *b = dyn_cast<BitcodeFile>(Val: file))
847 return getSourceLocationBitcode(file: b);
848 return "\n>>> defined at " + toString(file);
849}
850
851// Construct and print an error message in the form of:
852//
853// lld-link: error: duplicate symbol: foo
854// >>> defined at bar.c:30
855// >>> bar.o
856// >>> defined at baz.c:563
857// >>> baz.o
858void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile,
859 SectionChunk *newSc,
860 uint32_t newSectionOffset) {
861 COFFSyncStream diag(ctx, ctx.config.forceMultiple ? DiagLevel::Warn
862 : DiagLevel::Err);
863 diag << "duplicate symbol: " << printSymbol(sym: existing);
864
865 DefinedRegular *d = dyn_cast<DefinedRegular>(Val: existing);
866 if (d && isa<ObjFile>(Val: d->getFile())) {
867 diag << getSourceLocation(file: d->getFile(), sc: d->getChunk(), offset: d->getValue(),
868 name: existing->getName());
869 } else {
870 diag << getSourceLocation(file: existing->getFile(), sc: nullptr, offset: 0, name: "");
871 }
872 diag << getSourceLocation(file: newFile, sc: newSc, offset: newSectionOffset,
873 name: existing->getName());
874}
875
876Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) {
877 auto [s, wasInserted] = insert(name: n, file: nullptr);
878 s->isUsedInRegularObj = true;
879 if (wasInserted || isa<Undefined>(Val: s) || s->isLazy())
880 replaceSymbol<DefinedAbsolute>(s, arg&: ctx, arg&: n, arg&: sym);
881 else if (auto *da = dyn_cast<DefinedAbsolute>(Val: s)) {
882 if (da->getVA() != sym.getValue())
883 reportDuplicate(existing: s, newFile: nullptr);
884 } else if (!isa<DefinedCOFF>(Val: s))
885 reportDuplicate(existing: s, newFile: nullptr);
886 return s;
887}
888
889Symbol *SymbolTable::addAbsolute(StringRef n, uint64_t va) {
890 auto [s, wasInserted] = insert(name: n, file: nullptr);
891 s->isUsedInRegularObj = true;
892 if (wasInserted || isa<Undefined>(Val: s) || s->isLazy())
893 replaceSymbol<DefinedAbsolute>(s, arg&: ctx, arg&: n, arg&: va);
894 else if (auto *da = dyn_cast<DefinedAbsolute>(Val: s)) {
895 if (da->getVA() != va)
896 reportDuplicate(existing: s, newFile: nullptr);
897 } else if (!isa<DefinedCOFF>(Val: s))
898 reportDuplicate(existing: s, newFile: nullptr);
899 return s;
900}
901
902Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) {
903 auto [s, wasInserted] = insert(name: n, file: nullptr);
904 s->isUsedInRegularObj = true;
905 if (wasInserted || isa<Undefined>(Val: s) || s->isLazy())
906 replaceSymbol<DefinedSynthetic>(s, arg&: n, arg&: c);
907 else if (!isa<DefinedCOFF>(Val: s))
908 reportDuplicate(existing: s, newFile: nullptr);
909 return s;
910}
911
912Symbol *SymbolTable::addRegular(InputFile *f, StringRef n,
913 const coff_symbol_generic *sym, SectionChunk *c,
914 uint32_t sectionOffset, bool isWeak) {
915 auto [s, wasInserted] = insert(name: n, file: f);
916 if (wasInserted || !isa<DefinedRegular>(Val: s) || s->isWeak)
917 replaceSymbol<DefinedRegular>(s, arg&: f, arg&: n, /*IsCOMDAT*/ arg: false,
918 /*IsExternal*/ arg: true, arg&: sym, arg&: c, arg&: isWeak);
919 else if (!isWeak)
920 reportDuplicate(existing: s, newFile: f, newSc: c, newSectionOffset: sectionOffset);
921 return s;
922}
923
924std::pair<DefinedRegular *, bool>
925SymbolTable::addComdat(InputFile *f, StringRef n,
926 const coff_symbol_generic *sym) {
927 auto [s, wasInserted] = insert(name: n, file: f);
928 if (wasInserted || !isa<DefinedRegular>(Val: s)) {
929 replaceSymbol<DefinedRegular>(s, arg&: f, arg&: n, /*IsCOMDAT*/ arg: true,
930 /*IsExternal*/ arg: true, arg&: sym, arg: nullptr);
931 return {cast<DefinedRegular>(Val: s), true};
932 }
933 auto *existingSymbol = cast<DefinedRegular>(Val: s);
934 if (!existingSymbol->isCOMDAT)
935 reportDuplicate(existing: s, newFile: f);
936 return {existingSymbol, false};
937}
938
939Symbol *SymbolTable::addCommon(InputFile *f, StringRef n, uint64_t size,
940 const coff_symbol_generic *sym, CommonChunk *c) {
941 auto [s, wasInserted] = insert(name: n, file: f);
942 if (wasInserted || !isa<DefinedCOFF>(Val: s))
943 replaceSymbol<DefinedCommon>(s, arg&: f, arg&: n, arg&: size, arg&: sym, arg&: c);
944 else if (auto *dc = dyn_cast<DefinedCommon>(Val: s))
945 if (size > dc->getSize())
946 replaceSymbol<DefinedCommon>(s, arg&: f, arg&: n, arg&: size, arg&: sym, arg&: c);
947 return s;
948}
949
950DefinedImportData *SymbolTable::addImportData(StringRef n, ImportFile *f,
951 Chunk *&location) {
952 auto [s, wasInserted] = insert(name: n, file: nullptr);
953 s->isUsedInRegularObj = true;
954 if (wasInserted || isa<Undefined>(Val: s) || s->isLazy()) {
955 replaceSymbol<DefinedImportData>(s, arg&: n, arg&: f, arg&: location);
956 return cast<DefinedImportData>(Val: s);
957 }
958
959 reportDuplicate(existing: s, newFile: f);
960 return nullptr;
961}
962
963Defined *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id,
964 ImportThunkChunk *chunk) {
965 auto [s, wasInserted] = insert(name, file: nullptr);
966 s->isUsedInRegularObj = true;
967 if (wasInserted || isa<Undefined>(Val: s) || s->isLazy()) {
968 replaceSymbol<DefinedImportThunk>(s, arg&: ctx, arg&: name, arg&: id, arg&: chunk);
969 return cast<Defined>(Val: s);
970 }
971
972 reportDuplicate(existing: s, newFile: id->file);
973 return nullptr;
974}
975
976void SymbolTable::addLibcall(StringRef name) {
977 Symbol *sym = findUnderscore(name);
978 if (!sym)
979 return;
980
981 if (auto *l = dyn_cast<LazyArchive>(Val: sym)) {
982 MemoryBufferRef mb = l->getMemberBuffer();
983 if (isBitcode(mb))
984 addUndefined(name: sym->getName());
985 } else if (LazyObject *o = dyn_cast<LazyObject>(Val: sym)) {
986 if (isBitcode(mb: o->file->mb))
987 addUndefined(name: sym->getName());
988 }
989}
990
991Symbol *SymbolTable::find(StringRef name) const {
992 return symMap.lookup(Val: CachedHashStringRef(name));
993}
994
995Symbol *SymbolTable::findUnderscore(StringRef name) const {
996 if (machine == I386)
997 return find(name: ("_" + name).str());
998 return find(name);
999}
1000
1001// Return all symbols that start with Prefix, possibly ignoring the first
1002// character of Prefix or the first character symbol.
1003std::vector<Symbol *> SymbolTable::getSymsWithPrefix(StringRef prefix) {
1004 std::vector<Symbol *> syms;
1005 for (auto pair : symMap) {
1006 StringRef name = pair.first.val();
1007 if (name.starts_with(Prefix: prefix) || name.starts_with(Prefix: prefix.drop_front()) ||
1008 name.drop_front().starts_with(Prefix: prefix) ||
1009 name.drop_front().starts_with(Prefix: prefix.drop_front())) {
1010 syms.push_back(x: pair.second);
1011 }
1012 }
1013 return syms;
1014}
1015
1016Symbol *SymbolTable::findMangle(StringRef name) {
1017 if (Symbol *sym = find(name)) {
1018 if (auto *u = dyn_cast<Undefined>(Val: sym)) {
1019 // We're specifically looking for weak aliases that ultimately resolve to
1020 // defined symbols, hence the call to getWeakAlias() instead of just using
1021 // the weakAlias member variable. This matches link.exe's behavior.
1022 if (Symbol *weakAlias = u->getWeakAlias())
1023 return weakAlias;
1024 } else {
1025 return sym;
1026 }
1027 }
1028
1029 // Efficient fuzzy string lookup is impossible with a hash table, so iterate
1030 // the symbol table once and collect all possibly matching symbols into this
1031 // vector. Then compare each possibly matching symbol with each possible
1032 // mangling.
1033 std::vector<Symbol *> syms = getSymsWithPrefix(prefix: name);
1034 auto findByPrefix = [&syms](const Twine &t) -> Symbol * {
1035 std::string prefix = t.str();
1036 for (auto *s : syms)
1037 if (s->getName().starts_with(Prefix: prefix))
1038 return s;
1039 return nullptr;
1040 };
1041
1042 // For non-x86, just look for C++ functions.
1043 if (machine != I386)
1044 return findByPrefix("?" + name + "@@Y");
1045
1046 if (!name.starts_with(Prefix: "_"))
1047 return nullptr;
1048 // Search for x86 stdcall function.
1049 if (Symbol *s = findByPrefix(name + "@"))
1050 return s;
1051 // Search for x86 fastcall function.
1052 if (Symbol *s = findByPrefix("@" + name.substr(Start: 1) + "@"))
1053 return s;
1054 // Search for x86 vectorcall function.
1055 if (Symbol *s = findByPrefix(name.substr(Start: 1) + "@@"))
1056 return s;
1057 // Search for x86 C++ non-member function.
1058 return findByPrefix("?" + name.substr(Start: 1) + "@@Y");
1059}
1060
1061bool SymbolTable::findUnderscoreMangle(StringRef sym) {
1062 Symbol *s = findMangle(name: mangle(sym));
1063 return s && !isa<Undefined>(Val: s);
1064}
1065
1066// Symbol names are mangled by prepending "_" on x86.
1067StringRef SymbolTable::mangle(StringRef sym) {
1068 assert(machine != IMAGE_FILE_MACHINE_UNKNOWN);
1069 if (machine == I386)
1070 return saver().save(S: "_" + sym);
1071 return sym;
1072}
1073
1074StringRef SymbolTable::mangleMaybe(Symbol *s) {
1075 // If the plain symbol name has already been resolved, do nothing.
1076 Undefined *unmangled = dyn_cast<Undefined>(Val: s);
1077 if (!unmangled)
1078 return "";
1079
1080 // Otherwise, see if a similar, mangled symbol exists in the symbol table.
1081 Symbol *mangled = findMangle(name: unmangled->getName());
1082 if (!mangled)
1083 return "";
1084
1085 // If we find a similar mangled symbol, make this an alias to it and return
1086 // its name.
1087 Log(ctx) << unmangled->getName() << " aliased to " << mangled->getName();
1088 unmangled->setWeakAlias(sym: addUndefined(name: mangled->getName()));
1089 return mangled->getName();
1090}
1091
1092// Windows specific -- find default entry point name.
1093//
1094// There are four different entry point functions for Windows executables,
1095// each of which corresponds to a user-defined "main" function. This function
1096// infers an entry point from a user-defined "main" function.
1097StringRef SymbolTable::findDefaultEntry() {
1098 assert(ctx.config.subsystem != IMAGE_SUBSYSTEM_UNKNOWN &&
1099 "must handle /subsystem before calling this");
1100
1101 if (ctx.config.mingw)
1102 return mangle(sym: ctx.config.subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI
1103 ? "WinMainCRTStartup"
1104 : "mainCRTStartup");
1105
1106 if (ctx.config.subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
1107 if (findUnderscoreMangle(sym: "wWinMain")) {
1108 if (!findUnderscoreMangle(sym: "WinMain"))
1109 return mangle(sym: "wWinMainCRTStartup");
1110 Warn(ctx) << "found both wWinMain and WinMain; using latter";
1111 }
1112 return mangle(sym: "WinMainCRTStartup");
1113 }
1114 if (findUnderscoreMangle(sym: "wmain")) {
1115 if (!findUnderscoreMangle(sym: "main"))
1116 return mangle(sym: "wmainCRTStartup");
1117 Warn(ctx) << "found both wmain and main; using latter";
1118 }
1119 return mangle(sym: "mainCRTStartup");
1120}
1121
1122WindowsSubsystem SymbolTable::inferSubsystem() {
1123 if (ctx.config.dll)
1124 return IMAGE_SUBSYSTEM_WINDOWS_GUI;
1125 if (ctx.config.mingw)
1126 return IMAGE_SUBSYSTEM_WINDOWS_CUI;
1127 // Note that link.exe infers the subsystem from the presence of these
1128 // functions even if /entry: or /nodefaultlib are passed which causes them
1129 // to not be called.
1130 bool haveMain = findUnderscoreMangle(sym: "main");
1131 bool haveWMain = findUnderscoreMangle(sym: "wmain");
1132 bool haveWinMain = findUnderscoreMangle(sym: "WinMain");
1133 bool haveWWinMain = findUnderscoreMangle(sym: "wWinMain");
1134 if (haveMain || haveWMain) {
1135 if (haveWinMain || haveWWinMain) {
1136 Warn(ctx) << "found " << (haveMain ? "main" : "wmain") << " and "
1137 << (haveWinMain ? "WinMain" : "wWinMain")
1138 << "; defaulting to /subsystem:console";
1139 }
1140 return IMAGE_SUBSYSTEM_WINDOWS_CUI;
1141 }
1142 if (haveWinMain || haveWWinMain)
1143 return IMAGE_SUBSYSTEM_WINDOWS_GUI;
1144 return IMAGE_SUBSYSTEM_UNKNOWN;
1145}
1146
1147void SymbolTable::addUndefinedGlob(StringRef arg) {
1148 Expected<GlobPattern> pat = GlobPattern::create(Pat: arg);
1149 if (!pat) {
1150 Err(ctx) << "/includeglob: " << toString(E: pat.takeError());
1151 return;
1152 }
1153
1154 SmallVector<Symbol *, 0> syms;
1155 forEachSymbol(callback: [&syms, &pat](Symbol *sym) {
1156 if (pat->match(S: sym->getName())) {
1157 syms.push_back(Elt: sym);
1158 }
1159 });
1160
1161 for (Symbol *sym : syms)
1162 addGCRoot(name: sym->getName());
1163}
1164
1165// Convert stdcall/fastcall style symbols into unsuffixed symbols,
1166// with or without a leading underscore. (MinGW specific.)
1167static StringRef killAt(StringRef sym, bool prefix) {
1168 if (sym.empty())
1169 return sym;
1170 // Strip any trailing stdcall suffix
1171 sym = sym.substr(Start: 0, N: sym.find(C: '@', From: 1));
1172 if (!sym.starts_with(Prefix: "@")) {
1173 if (prefix && !sym.starts_with(Prefix: "_"))
1174 return saver().save(S: "_" + sym);
1175 return sym;
1176 }
1177 // For fastcall, remove the leading @ and replace it with an
1178 // underscore, if prefixes are used.
1179 sym = sym.substr(Start: 1);
1180 if (prefix)
1181 sym = saver().save(S: "_" + sym);
1182 return sym;
1183}
1184
1185static StringRef exportSourceName(ExportSource s) {
1186 switch (s) {
1187 case ExportSource::Directives:
1188 return "source file (directives)";
1189 case ExportSource::Export:
1190 return "/export";
1191 case ExportSource::ModuleDefinition:
1192 return "/def";
1193 default:
1194 llvm_unreachable("unknown ExportSource");
1195 }
1196}
1197
1198// Performs error checking on all /export arguments.
1199// It also sets ordinals.
1200void SymbolTable::fixupExports() {
1201 llvm::TimeTraceScope timeScope("Fixup exports");
1202 // Symbol ordinals must be unique.
1203 std::set<uint16_t> ords;
1204 for (Export &e : exports) {
1205 if (e.ordinal == 0)
1206 continue;
1207 if (!ords.insert(x: e.ordinal).second)
1208 Fatal(ctx) << "duplicate export ordinal: " << e.name;
1209 }
1210
1211 for (Export &e : exports) {
1212 if (!e.exportAs.empty()) {
1213 e.exportName = e.exportAs;
1214 continue;
1215 }
1216
1217 StringRef sym =
1218 !e.forwardTo.empty() || e.extName.empty() ? e.name : e.extName;
1219 if (machine == I386 && sym.starts_with(Prefix: "_")) {
1220 // In MSVC mode, a fully decorated stdcall function is exported
1221 // as-is with the leading underscore (with type IMPORT_NAME).
1222 // In MinGW mode, a decorated stdcall function gets the underscore
1223 // removed, just like normal cdecl functions.
1224 if (ctx.config.mingw || !sym.contains(C: '@')) {
1225 e.exportName = sym.substr(Start: 1);
1226 continue;
1227 }
1228 }
1229 if (isEC() && !e.data && !e.constant) {
1230 if (std::optional<std::string> demangledName =
1231 getArm64ECDemangledFunctionName(Name: sym)) {
1232 e.exportName = saver().save(S: *demangledName);
1233 continue;
1234 }
1235 }
1236 e.exportName = sym;
1237 }
1238
1239 if (ctx.config.killAt && machine == I386) {
1240 for (Export &e : exports) {
1241 e.name = killAt(sym: e.name, prefix: true);
1242 e.exportName = killAt(sym: e.exportName, prefix: false);
1243 e.extName = killAt(sym: e.extName, prefix: true);
1244 e.symbolName = killAt(sym: e.symbolName, prefix: true);
1245 }
1246 }
1247
1248 // Uniquefy by name.
1249 DenseMap<StringRef, std::pair<Export *, unsigned>> map(exports.size());
1250 std::vector<Export> v;
1251 for (Export &e : exports) {
1252 auto pair = map.insert(KV: std::make_pair(x&: e.exportName, y: std::make_pair(x: &e, y: 0)));
1253 bool inserted = pair.second;
1254 if (inserted) {
1255 pair.first->second.second = v.size();
1256 v.push_back(x: e);
1257 continue;
1258 }
1259 Export *existing = pair.first->second.first;
1260 if (e == *existing || e.name != existing->name)
1261 continue;
1262 // If the existing export comes from .OBJ directives, we are allowed to
1263 // overwrite it with /DEF: or /EXPORT without any warning, as MSVC link.exe
1264 // does.
1265 if (existing->source == ExportSource::Directives) {
1266 *existing = e;
1267 v[pair.first->second.second] = e;
1268 continue;
1269 }
1270 if (existing->source == e.source) {
1271 Warn(ctx) << "duplicate " << exportSourceName(s: existing->source)
1272 << " option: " << e.name;
1273 } else {
1274 Warn(ctx) << "duplicate export: " << e.name << " first seen in "
1275 << exportSourceName(s: existing->source) << ", now in "
1276 << exportSourceName(s: e.source);
1277 }
1278 }
1279 exports = std::move(v);
1280
1281 // Sort by name.
1282 llvm::sort(C&: exports, Comp: [](const Export &a, const Export &b) {
1283 return a.exportName < b.exportName;
1284 });
1285}
1286
1287void SymbolTable::assignExportOrdinals() {
1288 // Assign unique ordinals if default (= 0).
1289 uint32_t max = 0;
1290 for (Export &e : exports)
1291 max = std::max(a: max, b: (uint32_t)e.ordinal);
1292 for (Export &e : exports)
1293 if (e.ordinal == 0)
1294 e.ordinal = ++max;
1295 if (max > std::numeric_limits<uint16_t>::max())
1296 Fatal(ctx) << "too many exported symbols (got " << max << ", max "
1297 << Twine(std::numeric_limits<uint16_t>::max()) << ")";
1298}
1299
1300void SymbolTable::parseModuleDefs(StringRef path) {
1301 llvm::TimeTraceScope timeScope("Parse def file");
1302 std::unique_ptr<MemoryBuffer> mb =
1303 CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,
1304 /*RequiresNullTerminator=*/false,
1305 /*IsVolatile=*/true),
1306 "could not open " + path);
1307 COFFModuleDefinition m = check(e: parseCOFFModuleDefinition(
1308 MB: mb->getMemBufferRef(), Machine: machine, MingwDef: ctx.config.mingw));
1309
1310 // Include in /reproduce: output if applicable.
1311 ctx.driver.takeBuffer(mb: std::move(mb));
1312
1313 if (ctx.config.outputFile.empty())
1314 ctx.config.outputFile = std::string(saver().save(S: m.OutputFile));
1315 ctx.config.importName = std::string(saver().save(S: m.ImportName));
1316 if (m.ImageBase)
1317 ctx.config.imageBase = m.ImageBase;
1318 if (m.StackReserve)
1319 ctx.config.stackReserve = m.StackReserve;
1320 if (m.StackCommit)
1321 ctx.config.stackCommit = m.StackCommit;
1322 if (m.HeapReserve)
1323 ctx.config.heapReserve = m.HeapReserve;
1324 if (m.HeapCommit)
1325 ctx.config.heapCommit = m.HeapCommit;
1326 if (m.MajorImageVersion)
1327 ctx.config.majorImageVersion = m.MajorImageVersion;
1328 if (m.MinorImageVersion)
1329 ctx.config.minorImageVersion = m.MinorImageVersion;
1330 if (m.MajorOSVersion)
1331 ctx.config.majorOSVersion = m.MajorOSVersion;
1332 if (m.MinorOSVersion)
1333 ctx.config.minorOSVersion = m.MinorOSVersion;
1334
1335 for (COFFShortExport e1 : m.Exports) {
1336 Export e2;
1337 // Renamed exports are parsed and set as "ExtName = Name". If Name has
1338 // the form "OtherDll.Func", it shouldn't be a normal exported
1339 // function but a forward to another DLL instead. This is supported
1340 // by both MS and GNU linkers.
1341 if (!e1.ExtName.empty() && e1.ExtName != e1.Name &&
1342 StringRef(e1.Name).contains(C: '.')) {
1343 e2.name = saver().save(S: e1.ExtName);
1344 e2.forwardTo = saver().save(S: e1.Name);
1345 } else {
1346 e2.name = saver().save(S: e1.Name);
1347 e2.extName = saver().save(S: e1.ExtName);
1348 }
1349 e2.exportAs = saver().save(S: e1.ExportAs);
1350 e2.importName = saver().save(S: e1.ImportName);
1351 e2.ordinal = e1.Ordinal;
1352 e2.noname = e1.Noname;
1353 e2.data = e1.Data;
1354 e2.isPrivate = e1.Private;
1355 e2.constant = e1.Constant;
1356 e2.source = ExportSource::ModuleDefinition;
1357 exports.push_back(x: e2);
1358 }
1359}
1360
1361// Parse a string of the form of "<from>=<to>".
1362void SymbolTable::parseAlternateName(StringRef s) {
1363 auto [from, to] = s.split(Separator: '=');
1364 if (from.empty() || to.empty())
1365 Fatal(ctx) << "/alternatename: invalid argument: " << s;
1366 auto it = alternateNames.find(x: from);
1367 if (it != alternateNames.end() && it->second != to)
1368 Fatal(ctx) << "/alternatename: conflicts: " << s;
1369 alternateNames.insert(position: it, x: std::make_pair(x&: from, y&: to));
1370}
1371
1372void SymbolTable::resolveAlternateNames() {
1373 // Add weak aliases. Weak aliases is a mechanism to give remaining
1374 // undefined symbols final chance to be resolved successfully.
1375 for (auto pair : alternateNames) {
1376 StringRef from = pair.first;
1377 StringRef to = pair.second;
1378 Symbol *sym = find(name: from);
1379 if (!sym)
1380 continue;
1381 if (auto *u = dyn_cast<Undefined>(Val: sym)) {
1382 if (u->weakAlias) {
1383 // On ARM64EC, anti-dependency aliases are treated as undefined
1384 // symbols unless a demangled symbol aliases a defined one, which
1385 // is part of the implementation.
1386 if (!isEC() || !u->isAntiDep)
1387 continue;
1388 if (!isa<Undefined>(Val: u->weakAlias) &&
1389 !isArm64ECMangledFunctionName(Name: u->getName()))
1390 continue;
1391 }
1392
1393 // Check if the destination symbol is defined. If not, skip it.
1394 // It may still be resolved later if more input files are added.
1395 // Also skip anti-dependency targets, as they can't be chained anyway.
1396 Symbol *toSym = find(name: to);
1397 if (!toSym)
1398 continue;
1399 auto toUndef = dyn_cast<Undefined>(Val: toSym);
1400 if (toUndef && (!toUndef->weakAlias || toUndef->isAntiDep))
1401 continue;
1402 toSym->isUsedInRegularObj = true;
1403 if (toSym->isLazy())
1404 forceLazy(s: toSym);
1405 u->setWeakAlias(sym: toSym);
1406 }
1407 }
1408}
1409
1410// Parses /aligncomm option argument.
1411void SymbolTable::parseAligncomm(StringRef s) {
1412 auto [name, align] = s.split(Separator: ',');
1413 if (name.empty() || align.empty()) {
1414 Err(ctx) << "/aligncomm: invalid argument: " << s;
1415 return;
1416 }
1417 int v;
1418 if (align.getAsInteger(Radix: 0, Result&: v)) {
1419 Err(ctx) << "/aligncomm: invalid argument: " << s;
1420 return;
1421 }
1422 alignComm[std::string(name)] = std::max(a: alignComm[std::string(name)], b: 1 << v);
1423}
1424
1425Symbol *SymbolTable::addUndefined(StringRef name) {
1426 return addUndefined(name, f: nullptr, overrideLazy: false);
1427}
1428
1429std::string SymbolTable::printSymbol(Symbol *sym) const {
1430 std::string name = maybeDemangleSymbol(ctx, symName: sym->getName());
1431 if (ctx.hybridSymtab)
1432 return name + (isEC() ? " (EC symbol)" : " (native symbol)");
1433 return name;
1434}
1435
1436void SymbolTable::compileBitcodeFiles() {
1437 if (bitcodeFileInstances.empty())
1438 return;
1439
1440 ScopedTimer t(ctx.ltoTimer);
1441 lto.reset(p: new BitcodeCompiler(ctx));
1442 {
1443 llvm::TimeTraceScope addScope("Add bitcode file instances");
1444 for (BitcodeFile *f : bitcodeFileInstances)
1445 lto->add(f&: *f);
1446 }
1447 for (InputFile *newObj : lto->compile()) {
1448 ObjFile *obj = cast<ObjFile>(Val: newObj);
1449 obj->parse();
1450 ctx.objFileInstances.push_back(x: obj);
1451 }
1452}
1453
1454} // namespace lld::coff
1455