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.count(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.count(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() {
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->resolveWeakAlias())
472 continue;
473
474 // If we can resolve a symbol by removing __imp_ prefix, do that.
475 // This odd rule is for compatibility with MSVC linker.
476 if (name.starts_with(Prefix: "__imp_")) {
477 auto findLocalSym = [&](StringRef n) {
478 Symbol *sym = find(name: n);
479 if (auto undef = dyn_cast_or_null<Undefined>(Val: sym)) {
480 // The unprefixed symbol might come later in symMap, so handle it now
481 // if needed.
482 if (!undef->resolveWeakAlias())
483 sym = nullptr;
484 }
485 return sym;
486 };
487
488 StringRef impName = name.substr(Start: strlen(s: "__imp_"));
489 Symbol *imp = findLocalSym(impName);
490 if (!imp && isEC()) {
491 // Try to use the mangled symbol on ARM64EC.
492 std::optional<std::string> mangledName =
493 getArm64ECMangledFunctionName(Name: impName);
494 if (mangledName)
495 imp = findLocalSym(*mangledName);
496 if (!imp && impName.consume_front(Prefix: "aux_")) {
497 // If it's a __imp_aux_ symbol, try skipping the aux_ prefix.
498 imp = findLocalSym(impName);
499 if (!imp && (mangledName = getArm64ECMangledFunctionName(Name: impName)))
500 imp = findLocalSym(*mangledName);
501 }
502 }
503 if (imp && isa<Defined>(Val: imp)) {
504 auto *d = cast<Defined>(Val: imp);
505 replaceSymbol<DefinedLocalImport>(s: sym, arg&: ctx, arg&: name, arg&: d);
506 localImportChunks.push_back(x: cast<DefinedLocalImport>(Val: sym)->getChunk());
507 localImports[sym] = d;
508 continue;
509 }
510 }
511
512 // We don't want to report missing Microsoft precompiled headers symbols.
513 // A proper message will be emitted instead in PDBLinker::aquirePrecompObj
514 if (name.contains(Other: "_PchSym_"))
515 continue;
516
517 if (ctx.config.autoImport && handleMinGWAutomaticImport(sym, name))
518 continue;
519
520 // Remaining undefined symbols are not fatal if /force is specified.
521 // They are replaced with dummy defined symbols.
522 if (ctx.config.forceUnresolved)
523 replaceSymbol<DefinedAbsolute>(s: sym, arg&: ctx, arg&: name, arg: 0);
524 undefs.insert(Ptr: sym);
525 }
526
527 reportProblemSymbols(
528 undefs, localImports: ctx.config.warnLocallyDefinedImported ? &localImports : nullptr,
529 needBitcodeFiles: false);
530}
531
532std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
533 bool inserted = false;
534 Symbol *&sym = symMap[CachedHashStringRef(name)];
535 if (!sym) {
536 sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
537 sym->isUsedInRegularObj = false;
538 sym->pendingArchiveLoad = false;
539 sym->canInline = true;
540 inserted = true;
541
542 if (isEC() && name.starts_with(Prefix: "EXP+"))
543 expSymbols.push_back(x: sym);
544 }
545 return {sym, inserted};
546}
547
548std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, InputFile *file) {
549 std::pair<Symbol *, bool> result = insert(name);
550 if (!file || !isa<BitcodeFile>(Val: file))
551 result.first->isUsedInRegularObj = true;
552 return result;
553}
554
555void SymbolTable::initializeLoadConfig() {
556 auto sym =
557 dyn_cast_or_null<DefinedRegular>(Val: findUnderscore(name: "_load_config_used"));
558 if (!sym) {
559 if (isEC()) {
560 Warn(ctx) << "EC version of '_load_config_used' is missing";
561 return;
562 }
563 if (ctx.config.machine == ARM64X) {
564 Warn(ctx) << "native version of '_load_config_used' is missing for "
565 "ARM64X target";
566 return;
567 }
568 if (ctx.config.guardCF != GuardCFLevel::Off)
569 Warn(ctx)
570 << "Control Flow Guard is enabled but '_load_config_used' is missing";
571 if (ctx.config.dependentLoadFlags)
572 Warn(ctx) << "_load_config_used not found, /dependentloadflag will have "
573 "no effect";
574 return;
575 }
576
577 SectionChunk *sc = sym->getChunk();
578 if (!sc->hasData) {
579 Err(ctx) << "_load_config_used points to uninitialized data";
580 return;
581 }
582 uint64_t offsetInChunk = sym->getValue();
583 if (offsetInChunk + 4 > sc->getSize()) {
584 Err(ctx) << "_load_config_used section chunk is too small";
585 return;
586 }
587
588 ArrayRef<uint8_t> secContents = sc->getContents();
589 loadConfigSize =
590 *reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]);
591 if (offsetInChunk + loadConfigSize > sc->getSize()) {
592 Err(ctx) << "_load_config_used specifies a size larger than its containing "
593 "section chunk";
594 return;
595 }
596
597 uint32_t expectedAlign = ctx.config.is64() ? 8 : 4;
598 if (sc->getAlignment() < expectedAlign)
599 Warn(ctx) << "'_load_config_used' is misaligned (expected alignment to be "
600 << expectedAlign << " bytes, got " << sc->getAlignment()
601 << " instead)";
602 else if (!isAligned(Lhs: Align(expectedAlign), SizeInBytes: offsetInChunk))
603 Warn(ctx) << "'_load_config_used' is misaligned (section offset is 0x"
604 << Twine::utohexstr(Val: sym->getValue()) << " not aligned to "
605 << expectedAlign << " bytes)";
606
607 loadConfigSym = sym;
608}
609
610void SymbolTable::addEntryThunk(Symbol *from, Symbol *to) {
611 entryThunks.push_back(x: {from, to});
612}
613
614void SymbolTable::addExitThunk(Symbol *from, Symbol *to) {
615 exitThunks[from] = to;
616}
617
618void SymbolTable::initializeECThunks() {
619 if (!isArm64EC(Machine: ctx.config.machine))
620 return;
621
622 for (auto it : entryThunks) {
623 auto *to = dyn_cast<Defined>(Val: it.second);
624 if (!to)
625 continue;
626 auto *from = dyn_cast<DefinedRegular>(Val: it.first);
627 // We need to be able to add padding to the function and fill it with an
628 // offset to its entry thunks. To ensure that padding the function is
629 // feasible, functions are required to be COMDAT symbols with no offset.
630 if (!from || !from->getChunk()->isCOMDAT() ||
631 cast<DefinedRegular>(Val: from)->getValue()) {
632 Err(ctx) << "non COMDAT symbol '" << from->getName() << "' in hybrid map";
633 continue;
634 }
635 from->getChunk()->setEntryThunk(to);
636 }
637
638 for (ImportFile *file : ctx.importFileInstances) {
639 if (!file->impchkThunk)
640 continue;
641
642 Symbol *sym = exitThunks.lookup(Val: file->thunkSym);
643 if (!sym)
644 sym = exitThunks.lookup(Val: file->impECSym);
645 file->impchkThunk->exitThunk = dyn_cast_or_null<Defined>(Val: sym);
646 }
647
648 // On ARM64EC, the __imp_ symbol references the auxiliary IAT, while the
649 // __imp_aux_ symbol references the regular IAT. However, x86_64 code expects
650 // both to reference the regular IAT, so adjust the symbol if necessary.
651 parallelForEach(R&: ctx.objFileInstances, Fn: [&](ObjFile *file) {
652 if (file->getMachineType() != AMD64)
653 return;
654 for (auto &sym : file->getMutableSymbols()) {
655 auto impSym = dyn_cast_or_null<DefinedImportData>(Val: sym);
656 if (impSym && impSym->file->impchkThunk && sym == impSym->file->impECSym)
657 sym = impSym->file->impSym;
658 }
659 });
660}
661
662Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f,
663 bool overrideLazy) {
664 auto [s, wasInserted] = insert(name, file: f);
665 if (wasInserted || (s->isLazy() && overrideLazy)) {
666 replaceSymbol<Undefined>(s, arg&: name);
667 return s;
668 }
669 if (s->isLazy())
670 forceLazy(s);
671 return s;
672}
673
674Symbol *SymbolTable::addGCRoot(StringRef name, bool aliasEC) {
675 Symbol *b = addUndefined(name);
676 if (!b->isGCRoot) {
677 b->isGCRoot = true;
678 ctx.config.gcroot.push_back(x: b);
679 }
680
681 // On ARM64EC, a symbol may be defined in either its mangled or demangled form
682 // (or both). Define an anti-dependency symbol that binds both forms, similar
683 // to how compiler-generated code references external functions.
684 if (aliasEC && isEC()) {
685 if (std::optional<std::string> mangledName =
686 getArm64ECMangledFunctionName(Name: name)) {
687 auto u = dyn_cast<Undefined>(Val: b);
688 if (u && !u->weakAlias) {
689 Symbol *t = addUndefined(name: saver().save(S: *mangledName));
690 u->setWeakAlias(sym: t, antiDep: true);
691 }
692 } else if (std::optional<std::string> demangledName =
693 getArm64ECDemangledFunctionName(Name: name)) {
694 Symbol *us = addUndefined(name: saver().save(S: *demangledName));
695 auto u = dyn_cast<Undefined>(Val: us);
696 if (u && !u->weakAlias)
697 u->setWeakAlias(sym: b, antiDep: true);
698 }
699 }
700 return b;
701}
702
703// On ARM64EC, a function symbol may appear in both mangled and demangled forms:
704// - ARM64EC archives contain only the mangled name, while the demangled symbol
705// is defined by the object file as an alias.
706// - x86_64 archives contain only the demangled name (the mangled name is
707// usually defined by an object referencing the symbol as an alias to a guess
708// exit thunk).
709// - ARM64EC import files contain both the mangled and demangled names for
710// thunks.
711// If more than one archive defines the same function, this could lead
712// to different libraries being used for the same function depending on how they
713// are referenced. Avoid this by checking if the paired symbol is already
714// defined before adding a symbol to the table.
715template <typename T>
716bool checkLazyECPair(SymbolTable *symtab, StringRef name, InputFile *f) {
717 if (name.starts_with(Prefix: "__imp_"))
718 return true;
719 std::string pairName;
720 if (std::optional<std::string> mangledName =
721 getArm64ECMangledFunctionName(Name: name))
722 pairName = std::move(*mangledName);
723 else if (std::optional<std::string> demangledName =
724 getArm64ECDemangledFunctionName(Name: name))
725 pairName = std::move(*demangledName);
726 else
727 return true;
728
729 Symbol *sym = symtab->find(name: pairName);
730 if (!sym)
731 return true;
732 if (sym->pendingArchiveLoad)
733 return false;
734 if (auto u = dyn_cast<Undefined>(Val: sym))
735 return !u->weakAlias || u->isAntiDep;
736 // If the symbol is lazy, allow it only if it originates from the same
737 // archive.
738 auto lazy = dyn_cast<T>(sym);
739 return lazy && lazy->file == f;
740}
741
742void SymbolTable::addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym) {
743 StringRef name = sym.getName();
744 if (isEC() && !checkLazyECPair<LazyArchive>(symtab: this, name, f))
745 return;
746 auto [s, wasInserted] = insert(name);
747 if (wasInserted) {
748 replaceSymbol<LazyArchive>(s, arg&: f, arg: sym);
749 return;
750 }
751 auto *u = dyn_cast<Undefined>(Val: s);
752 if (!u || (u->weakAlias && !u->isECAlias(machine)) || s->pendingArchiveLoad)
753 return;
754 s->pendingArchiveLoad = true;
755 f->addMember(sym);
756}
757
758void SymbolTable::addLazyObject(InputFile *f, StringRef n) {
759 assert(f->lazy);
760 if (isEC() && !checkLazyECPair<LazyObject>(symtab: this, name: n, f))
761 return;
762 auto [s, wasInserted] = insert(name: n, file: f);
763 if (wasInserted) {
764 replaceSymbol<LazyObject>(s, arg&: f, arg&: n);
765 return;
766 }
767 auto *u = dyn_cast<Undefined>(Val: s);
768 if (!u || (u->weakAlias && !u->isECAlias(machine)) || s->pendingArchiveLoad)
769 return;
770 s->pendingArchiveLoad = true;
771 f->lazy = false;
772 ctx.driver.addFile(file: f);
773}
774
775void SymbolTable::addLazyDLLSymbol(DLLFile *f, DLLFile::Symbol *sym,
776 StringRef n) {
777 auto [s, wasInserted] = insert(name: n);
778 if (wasInserted) {
779 replaceSymbol<LazyDLLSymbol>(s, arg&: f, arg&: sym, arg&: n);
780 return;
781 }
782 auto *u = dyn_cast<Undefined>(Val: s);
783 if (!u || (u->weakAlias && !u->isECAlias(machine)) || s->pendingArchiveLoad)
784 return;
785 s->pendingArchiveLoad = true;
786 f->makeImport(s: sym);
787}
788
789static std::string getSourceLocationBitcode(BitcodeFile *file) {
790 std::string res("\n>>> defined at ");
791 StringRef source = file->obj->getSourceFileName();
792 if (!source.empty())
793 res += source.str() + "\n>>> ";
794 res += toString(file);
795 return res;
796}
797
798static std::string getSourceLocationObj(ObjFile *file, SectionChunk *sc,
799 uint32_t offset, StringRef name) {
800 std::optional<std::pair<StringRef, uint32_t>> fileLine;
801 if (sc)
802 fileLine = getFileLine(c: sc, addr: offset);
803 if (!fileLine)
804 fileLine = file->getVariableLocation(var: name);
805
806 std::string res;
807 llvm::raw_string_ostream os(res);
808 os << "\n>>> defined at ";
809 if (fileLine)
810 os << fileLine->first << ":" << fileLine->second << "\n>>> ";
811 os << toString(file);
812 return res;
813}
814
815static std::string getSourceLocation(InputFile *file, SectionChunk *sc,
816 uint32_t offset, StringRef name) {
817 if (!file)
818 return "";
819 if (auto *o = dyn_cast<ObjFile>(Val: file))
820 return getSourceLocationObj(file: o, sc, offset, name);
821 if (auto *b = dyn_cast<BitcodeFile>(Val: file))
822 return getSourceLocationBitcode(file: b);
823 return "\n>>> defined at " + toString(file);
824}
825
826// Construct and print an error message in the form of:
827//
828// lld-link: error: duplicate symbol: foo
829// >>> defined at bar.c:30
830// >>> bar.o
831// >>> defined at baz.c:563
832// >>> baz.o
833void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile,
834 SectionChunk *newSc,
835 uint32_t newSectionOffset) {
836 COFFSyncStream diag(ctx, ctx.config.forceMultiple ? DiagLevel::Warn
837 : DiagLevel::Err);
838 diag << "duplicate symbol: " << printSymbol(sym: existing);
839
840 DefinedRegular *d = dyn_cast<DefinedRegular>(Val: existing);
841 if (d && isa<ObjFile>(Val: d->getFile())) {
842 diag << getSourceLocation(file: d->getFile(), sc: d->getChunk(), offset: d->getValue(),
843 name: existing->getName());
844 } else {
845 diag << getSourceLocation(file: existing->getFile(), sc: nullptr, offset: 0, name: "");
846 }
847 diag << getSourceLocation(file: newFile, sc: newSc, offset: newSectionOffset,
848 name: existing->getName());
849}
850
851Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) {
852 auto [s, wasInserted] = insert(name: n, file: nullptr);
853 s->isUsedInRegularObj = true;
854 if (wasInserted || isa<Undefined>(Val: s) || s->isLazy())
855 replaceSymbol<DefinedAbsolute>(s, arg&: ctx, arg&: n, arg&: sym);
856 else if (auto *da = dyn_cast<DefinedAbsolute>(Val: s)) {
857 if (da->getVA() != sym.getValue())
858 reportDuplicate(existing: s, newFile: nullptr);
859 } else if (!isa<DefinedCOFF>(Val: s))
860 reportDuplicate(existing: s, newFile: nullptr);
861 return s;
862}
863
864Symbol *SymbolTable::addAbsolute(StringRef n, uint64_t va) {
865 auto [s, wasInserted] = insert(name: n, file: nullptr);
866 s->isUsedInRegularObj = true;
867 if (wasInserted || isa<Undefined>(Val: s) || s->isLazy())
868 replaceSymbol<DefinedAbsolute>(s, arg&: ctx, arg&: n, arg&: va);
869 else if (auto *da = dyn_cast<DefinedAbsolute>(Val: s)) {
870 if (da->getVA() != va)
871 reportDuplicate(existing: s, newFile: nullptr);
872 } else if (!isa<DefinedCOFF>(Val: s))
873 reportDuplicate(existing: s, newFile: nullptr);
874 return s;
875}
876
877Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) {
878 auto [s, wasInserted] = insert(name: n, file: nullptr);
879 s->isUsedInRegularObj = true;
880 if (wasInserted || isa<Undefined>(Val: s) || s->isLazy())
881 replaceSymbol<DefinedSynthetic>(s, arg&: n, arg&: c);
882 else if (!isa<DefinedCOFF>(Val: s))
883 reportDuplicate(existing: s, newFile: nullptr);
884 return s;
885}
886
887Symbol *SymbolTable::addRegular(InputFile *f, StringRef n,
888 const coff_symbol_generic *sym, SectionChunk *c,
889 uint32_t sectionOffset, bool isWeak) {
890 auto [s, wasInserted] = insert(name: n, file: f);
891 if (wasInserted || !isa<DefinedRegular>(Val: s) || s->isWeak)
892 replaceSymbol<DefinedRegular>(s, arg&: f, arg&: n, /*IsCOMDAT*/ arg: false,
893 /*IsExternal*/ arg: true, arg&: sym, arg&: c, arg&: isWeak);
894 else if (!isWeak)
895 reportDuplicate(existing: s, newFile: f, newSc: c, newSectionOffset: sectionOffset);
896 return s;
897}
898
899std::pair<DefinedRegular *, bool>
900SymbolTable::addComdat(InputFile *f, StringRef n,
901 const coff_symbol_generic *sym) {
902 auto [s, wasInserted] = insert(name: n, file: f);
903 if (wasInserted || !isa<DefinedRegular>(Val: s)) {
904 replaceSymbol<DefinedRegular>(s, arg&: f, arg&: n, /*IsCOMDAT*/ arg: true,
905 /*IsExternal*/ arg: true, arg&: sym, arg: nullptr);
906 return {cast<DefinedRegular>(Val: s), true};
907 }
908 auto *existingSymbol = cast<DefinedRegular>(Val: s);
909 if (!existingSymbol->isCOMDAT)
910 reportDuplicate(existing: s, newFile: f);
911 return {existingSymbol, false};
912}
913
914Symbol *SymbolTable::addCommon(InputFile *f, StringRef n, uint64_t size,
915 const coff_symbol_generic *sym, CommonChunk *c) {
916 auto [s, wasInserted] = insert(name: n, file: f);
917 if (wasInserted || !isa<DefinedCOFF>(Val: s))
918 replaceSymbol<DefinedCommon>(s, arg&: f, arg&: n, arg&: size, arg&: sym, arg&: c);
919 else if (auto *dc = dyn_cast<DefinedCommon>(Val: s))
920 if (size > dc->getSize())
921 replaceSymbol<DefinedCommon>(s, arg&: f, arg&: n, arg&: size, arg&: sym, arg&: c);
922 return s;
923}
924
925DefinedImportData *SymbolTable::addImportData(StringRef n, ImportFile *f,
926 Chunk *&location) {
927 auto [s, wasInserted] = insert(name: n, file: nullptr);
928 s->isUsedInRegularObj = true;
929 if (wasInserted || isa<Undefined>(Val: s) || s->isLazy()) {
930 replaceSymbol<DefinedImportData>(s, arg&: n, arg&: f, arg&: location);
931 return cast<DefinedImportData>(Val: s);
932 }
933
934 reportDuplicate(existing: s, newFile: f);
935 return nullptr;
936}
937
938Defined *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id,
939 ImportThunkChunk *chunk) {
940 auto [s, wasInserted] = insert(name, file: nullptr);
941 s->isUsedInRegularObj = true;
942 if (wasInserted || isa<Undefined>(Val: s) || s->isLazy()) {
943 replaceSymbol<DefinedImportThunk>(s, arg&: ctx, arg&: name, arg&: id, arg&: chunk);
944 return cast<Defined>(Val: s);
945 }
946
947 reportDuplicate(existing: s, newFile: id->file);
948 return nullptr;
949}
950
951void SymbolTable::addLibcall(StringRef name) {
952 Symbol *sym = findUnderscore(name);
953 if (!sym)
954 return;
955
956 if (auto *l = dyn_cast<LazyArchive>(Val: sym)) {
957 MemoryBufferRef mb = l->getMemberBuffer();
958 if (isBitcode(mb))
959 addUndefined(name: sym->getName());
960 } else if (LazyObject *o = dyn_cast<LazyObject>(Val: sym)) {
961 if (isBitcode(mb: o->file->mb))
962 addUndefined(name: sym->getName());
963 }
964}
965
966Symbol *SymbolTable::find(StringRef name) const {
967 return symMap.lookup(Val: CachedHashStringRef(name));
968}
969
970Symbol *SymbolTable::findUnderscore(StringRef name) const {
971 if (machine == I386)
972 return find(name: ("_" + name).str());
973 return find(name);
974}
975
976// Return all symbols that start with Prefix, possibly ignoring the first
977// character of Prefix or the first character symbol.
978std::vector<Symbol *> SymbolTable::getSymsWithPrefix(StringRef prefix) {
979 std::vector<Symbol *> syms;
980 for (auto pair : symMap) {
981 StringRef name = pair.first.val();
982 if (name.starts_with(Prefix: prefix) || name.starts_with(Prefix: prefix.drop_front()) ||
983 name.drop_front().starts_with(Prefix: prefix) ||
984 name.drop_front().starts_with(Prefix: prefix.drop_front())) {
985 syms.push_back(x: pair.second);
986 }
987 }
988 return syms;
989}
990
991Symbol *SymbolTable::findMangle(StringRef name) {
992 if (Symbol *sym = find(name)) {
993 if (auto *u = dyn_cast<Undefined>(Val: sym)) {
994 // We're specifically looking for weak aliases that ultimately resolve to
995 // defined symbols, hence the call to getWeakAlias() instead of just using
996 // the weakAlias member variable. This matches link.exe's behavior.
997 if (Symbol *weakAlias = u->getWeakAlias())
998 return weakAlias;
999 } else {
1000 return sym;
1001 }
1002 }
1003
1004 // Efficient fuzzy string lookup is impossible with a hash table, so iterate
1005 // the symbol table once and collect all possibly matching symbols into this
1006 // vector. Then compare each possibly matching symbol with each possible
1007 // mangling.
1008 std::vector<Symbol *> syms = getSymsWithPrefix(prefix: name);
1009 auto findByPrefix = [&syms](const Twine &t) -> Symbol * {
1010 std::string prefix = t.str();
1011 for (auto *s : syms)
1012 if (s->getName().starts_with(Prefix: prefix))
1013 return s;
1014 return nullptr;
1015 };
1016
1017 // For non-x86, just look for C++ functions.
1018 if (machine != I386)
1019 return findByPrefix("?" + name + "@@Y");
1020
1021 if (!name.starts_with(Prefix: "_"))
1022 return nullptr;
1023 // Search for x86 stdcall function.
1024 if (Symbol *s = findByPrefix(name + "@"))
1025 return s;
1026 // Search for x86 fastcall function.
1027 if (Symbol *s = findByPrefix("@" + name.substr(Start: 1) + "@"))
1028 return s;
1029 // Search for x86 vectorcall function.
1030 if (Symbol *s = findByPrefix(name.substr(Start: 1) + "@@"))
1031 return s;
1032 // Search for x86 C++ non-member function.
1033 return findByPrefix("?" + name.substr(Start: 1) + "@@Y");
1034}
1035
1036bool SymbolTable::findUnderscoreMangle(StringRef sym) {
1037 Symbol *s = findMangle(name: mangle(sym));
1038 return s && !isa<Undefined>(Val: s);
1039}
1040
1041// Symbol names are mangled by prepending "_" on x86.
1042StringRef SymbolTable::mangle(StringRef sym) {
1043 assert(machine != IMAGE_FILE_MACHINE_UNKNOWN);
1044 if (machine == I386)
1045 return saver().save(S: "_" + sym);
1046 return sym;
1047}
1048
1049StringRef SymbolTable::mangleMaybe(Symbol *s) {
1050 // If the plain symbol name has already been resolved, do nothing.
1051 Undefined *unmangled = dyn_cast<Undefined>(Val: s);
1052 if (!unmangled)
1053 return "";
1054
1055 // Otherwise, see if a similar, mangled symbol exists in the symbol table.
1056 Symbol *mangled = findMangle(name: unmangled->getName());
1057 if (!mangled)
1058 return "";
1059
1060 // If we find a similar mangled symbol, make this an alias to it and return
1061 // its name.
1062 Log(ctx) << unmangled->getName() << " aliased to " << mangled->getName();
1063 unmangled->setWeakAlias(sym: addUndefined(name: mangled->getName()));
1064 return mangled->getName();
1065}
1066
1067// Windows specific -- find default entry point name.
1068//
1069// There are four different entry point functions for Windows executables,
1070// each of which corresponds to a user-defined "main" function. This function
1071// infers an entry point from a user-defined "main" function.
1072StringRef SymbolTable::findDefaultEntry() {
1073 assert(ctx.config.subsystem != IMAGE_SUBSYSTEM_UNKNOWN &&
1074 "must handle /subsystem before calling this");
1075
1076 if (ctx.config.mingw)
1077 return mangle(sym: ctx.config.subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI
1078 ? "WinMainCRTStartup"
1079 : "mainCRTStartup");
1080
1081 if (ctx.config.subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
1082 if (findUnderscoreMangle(sym: "wWinMain")) {
1083 if (!findUnderscoreMangle(sym: "WinMain"))
1084 return mangle(sym: "wWinMainCRTStartup");
1085 Warn(ctx) << "found both wWinMain and WinMain; using latter";
1086 }
1087 return mangle(sym: "WinMainCRTStartup");
1088 }
1089 if (findUnderscoreMangle(sym: "wmain")) {
1090 if (!findUnderscoreMangle(sym: "main"))
1091 return mangle(sym: "wmainCRTStartup");
1092 Warn(ctx) << "found both wmain and main; using latter";
1093 }
1094 return mangle(sym: "mainCRTStartup");
1095}
1096
1097WindowsSubsystem SymbolTable::inferSubsystem() {
1098 if (ctx.config.dll)
1099 return IMAGE_SUBSYSTEM_WINDOWS_GUI;
1100 if (ctx.config.mingw)
1101 return IMAGE_SUBSYSTEM_WINDOWS_CUI;
1102 // Note that link.exe infers the subsystem from the presence of these
1103 // functions even if /entry: or /nodefaultlib are passed which causes them
1104 // to not be called.
1105 bool haveMain = findUnderscoreMangle(sym: "main");
1106 bool haveWMain = findUnderscoreMangle(sym: "wmain");
1107 bool haveWinMain = findUnderscoreMangle(sym: "WinMain");
1108 bool haveWWinMain = findUnderscoreMangle(sym: "wWinMain");
1109 if (haveMain || haveWMain) {
1110 if (haveWinMain || haveWWinMain) {
1111 Warn(ctx) << "found " << (haveMain ? "main" : "wmain") << " and "
1112 << (haveWinMain ? "WinMain" : "wWinMain")
1113 << "; defaulting to /subsystem:console";
1114 }
1115 return IMAGE_SUBSYSTEM_WINDOWS_CUI;
1116 }
1117 if (haveWinMain || haveWWinMain)
1118 return IMAGE_SUBSYSTEM_WINDOWS_GUI;
1119 return IMAGE_SUBSYSTEM_UNKNOWN;
1120}
1121
1122void SymbolTable::addUndefinedGlob(StringRef arg) {
1123 Expected<GlobPattern> pat = GlobPattern::create(Pat: arg);
1124 if (!pat) {
1125 Err(ctx) << "/includeglob: " << toString(E: pat.takeError());
1126 return;
1127 }
1128
1129 SmallVector<Symbol *, 0> syms;
1130 forEachSymbol(callback: [&syms, &pat](Symbol *sym) {
1131 if (pat->match(S: sym->getName())) {
1132 syms.push_back(Elt: sym);
1133 }
1134 });
1135
1136 for (Symbol *sym : syms)
1137 addGCRoot(name: sym->getName());
1138}
1139
1140// Convert stdcall/fastcall style symbols into unsuffixed symbols,
1141// with or without a leading underscore. (MinGW specific.)
1142static StringRef killAt(StringRef sym, bool prefix) {
1143 if (sym.empty())
1144 return sym;
1145 // Strip any trailing stdcall suffix
1146 sym = sym.substr(Start: 0, N: sym.find(C: '@', From: 1));
1147 if (!sym.starts_with(Prefix: "@")) {
1148 if (prefix && !sym.starts_with(Prefix: "_"))
1149 return saver().save(S: "_" + sym);
1150 return sym;
1151 }
1152 // For fastcall, remove the leading @ and replace it with an
1153 // underscore, if prefixes are used.
1154 sym = sym.substr(Start: 1);
1155 if (prefix)
1156 sym = saver().save(S: "_" + sym);
1157 return sym;
1158}
1159
1160static StringRef exportSourceName(ExportSource s) {
1161 switch (s) {
1162 case ExportSource::Directives:
1163 return "source file (directives)";
1164 case ExportSource::Export:
1165 return "/export";
1166 case ExportSource::ModuleDefinition:
1167 return "/def";
1168 default:
1169 llvm_unreachable("unknown ExportSource");
1170 }
1171}
1172
1173// Performs error checking on all /export arguments.
1174// It also sets ordinals.
1175void SymbolTable::fixupExports() {
1176 llvm::TimeTraceScope timeScope("Fixup exports");
1177 // Symbol ordinals must be unique.
1178 std::set<uint16_t> ords;
1179 for (Export &e : exports) {
1180 if (e.ordinal == 0)
1181 continue;
1182 if (!ords.insert(x: e.ordinal).second)
1183 Fatal(ctx) << "duplicate export ordinal: " << e.name;
1184 }
1185
1186 for (Export &e : exports) {
1187 if (!e.exportAs.empty()) {
1188 e.exportName = e.exportAs;
1189 continue;
1190 }
1191
1192 StringRef sym =
1193 !e.forwardTo.empty() || e.extName.empty() ? e.name : e.extName;
1194 if (machine == I386 && sym.starts_with(Prefix: "_")) {
1195 // In MSVC mode, a fully decorated stdcall function is exported
1196 // as-is with the leading underscore (with type IMPORT_NAME).
1197 // In MinGW mode, a decorated stdcall function gets the underscore
1198 // removed, just like normal cdecl functions.
1199 if (ctx.config.mingw || !sym.contains(C: '@')) {
1200 e.exportName = sym.substr(Start: 1);
1201 continue;
1202 }
1203 }
1204 if (isEC() && !e.data && !e.constant) {
1205 if (std::optional<std::string> demangledName =
1206 getArm64ECDemangledFunctionName(Name: sym)) {
1207 e.exportName = saver().save(S: *demangledName);
1208 continue;
1209 }
1210 }
1211 e.exportName = sym;
1212 }
1213
1214 if (ctx.config.killAt && machine == I386) {
1215 for (Export &e : exports) {
1216 e.name = killAt(sym: e.name, prefix: true);
1217 e.exportName = killAt(sym: e.exportName, prefix: false);
1218 e.extName = killAt(sym: e.extName, prefix: true);
1219 e.symbolName = killAt(sym: e.symbolName, prefix: true);
1220 }
1221 }
1222
1223 // Uniquefy by name.
1224 DenseMap<StringRef, std::pair<Export *, unsigned>> map(exports.size());
1225 std::vector<Export> v;
1226 for (Export &e : exports) {
1227 auto pair = map.insert(KV: std::make_pair(x&: e.exportName, y: std::make_pair(x: &e, y: 0)));
1228 bool inserted = pair.second;
1229 if (inserted) {
1230 pair.first->second.second = v.size();
1231 v.push_back(x: e);
1232 continue;
1233 }
1234 Export *existing = pair.first->second.first;
1235 if (e == *existing || e.name != existing->name)
1236 continue;
1237 // If the existing export comes from .OBJ directives, we are allowed to
1238 // overwrite it with /DEF: or /EXPORT without any warning, as MSVC link.exe
1239 // does.
1240 if (existing->source == ExportSource::Directives) {
1241 *existing = e;
1242 v[pair.first->second.second] = e;
1243 continue;
1244 }
1245 if (existing->source == e.source) {
1246 Warn(ctx) << "duplicate " << exportSourceName(s: existing->source)
1247 << " option: " << e.name;
1248 } else {
1249 Warn(ctx) << "duplicate export: " << e.name << " first seen in "
1250 << exportSourceName(s: existing->source) << ", now in "
1251 << exportSourceName(s: e.source);
1252 }
1253 }
1254 exports = std::move(v);
1255
1256 // Sort by name.
1257 llvm::sort(C&: exports, Comp: [](const Export &a, const Export &b) {
1258 return a.exportName < b.exportName;
1259 });
1260}
1261
1262void SymbolTable::assignExportOrdinals() {
1263 // Assign unique ordinals if default (= 0).
1264 uint32_t max = 0;
1265 for (Export &e : exports)
1266 max = std::max(a: max, b: (uint32_t)e.ordinal);
1267 for (Export &e : exports)
1268 if (e.ordinal == 0)
1269 e.ordinal = ++max;
1270 if (max > std::numeric_limits<uint16_t>::max())
1271 Fatal(ctx) << "too many exported symbols (got " << max << ", max "
1272 << Twine(std::numeric_limits<uint16_t>::max()) << ")";
1273}
1274
1275void SymbolTable::parseModuleDefs(StringRef path) {
1276 llvm::TimeTraceScope timeScope("Parse def file");
1277 std::unique_ptr<MemoryBuffer> mb =
1278 CHECK(MemoryBuffer::getFile(path, /*IsText=*/false,
1279 /*RequiresNullTerminator=*/false,
1280 /*IsVolatile=*/true),
1281 "could not open " + path);
1282 COFFModuleDefinition m = check(e: parseCOFFModuleDefinition(
1283 MB: mb->getMemBufferRef(), Machine: machine, MingwDef: ctx.config.mingw));
1284
1285 // Include in /reproduce: output if applicable.
1286 ctx.driver.takeBuffer(mb: std::move(mb));
1287
1288 if (ctx.config.outputFile.empty())
1289 ctx.config.outputFile = std::string(saver().save(S: m.OutputFile));
1290 ctx.config.importName = std::string(saver().save(S: m.ImportName));
1291 if (m.ImageBase)
1292 ctx.config.imageBase = m.ImageBase;
1293 if (m.StackReserve)
1294 ctx.config.stackReserve = m.StackReserve;
1295 if (m.StackCommit)
1296 ctx.config.stackCommit = m.StackCommit;
1297 if (m.HeapReserve)
1298 ctx.config.heapReserve = m.HeapReserve;
1299 if (m.HeapCommit)
1300 ctx.config.heapCommit = m.HeapCommit;
1301 if (m.MajorImageVersion)
1302 ctx.config.majorImageVersion = m.MajorImageVersion;
1303 if (m.MinorImageVersion)
1304 ctx.config.minorImageVersion = m.MinorImageVersion;
1305 if (m.MajorOSVersion)
1306 ctx.config.majorOSVersion = m.MajorOSVersion;
1307 if (m.MinorOSVersion)
1308 ctx.config.minorOSVersion = m.MinorOSVersion;
1309
1310 for (COFFShortExport e1 : m.Exports) {
1311 Export e2;
1312 // Renamed exports are parsed and set as "ExtName = Name". If Name has
1313 // the form "OtherDll.Func", it shouldn't be a normal exported
1314 // function but a forward to another DLL instead. This is supported
1315 // by both MS and GNU linkers.
1316 if (!e1.ExtName.empty() && e1.ExtName != e1.Name &&
1317 StringRef(e1.Name).contains(C: '.')) {
1318 e2.name = saver().save(S: e1.ExtName);
1319 e2.forwardTo = saver().save(S: e1.Name);
1320 } else {
1321 e2.name = saver().save(S: e1.Name);
1322 e2.extName = saver().save(S: e1.ExtName);
1323 }
1324 e2.exportAs = saver().save(S: e1.ExportAs);
1325 e2.importName = saver().save(S: e1.ImportName);
1326 e2.ordinal = e1.Ordinal;
1327 e2.noname = e1.Noname;
1328 e2.data = e1.Data;
1329 e2.isPrivate = e1.Private;
1330 e2.constant = e1.Constant;
1331 e2.source = ExportSource::ModuleDefinition;
1332 exports.push_back(x: e2);
1333 }
1334}
1335
1336// Parse a string of the form of "<from>=<to>".
1337void SymbolTable::parseAlternateName(StringRef s) {
1338 auto [from, to] = s.split(Separator: '=');
1339 if (from.empty() || to.empty())
1340 Fatal(ctx) << "/alternatename: invalid argument: " << s;
1341 auto it = alternateNames.find(x: from);
1342 if (it != alternateNames.end() && it->second != to)
1343 Fatal(ctx) << "/alternatename: conflicts: " << s;
1344 alternateNames.insert(position: it, x: std::make_pair(x&: from, y&: to));
1345}
1346
1347// Parses /aligncomm option argument.
1348void SymbolTable::parseAligncomm(StringRef s) {
1349 auto [name, align] = s.split(Separator: ',');
1350 if (name.empty() || align.empty()) {
1351 Err(ctx) << "/aligncomm: invalid argument: " << s;
1352 return;
1353 }
1354 int v;
1355 if (align.getAsInteger(Radix: 0, Result&: v)) {
1356 Err(ctx) << "/aligncomm: invalid argument: " << s;
1357 return;
1358 }
1359 alignComm[std::string(name)] = std::max(a: alignComm[std::string(name)], b: 1 << v);
1360}
1361
1362Symbol *SymbolTable::addUndefined(StringRef name) {
1363 return addUndefined(name, f: nullptr, overrideLazy: false);
1364}
1365
1366std::string SymbolTable::printSymbol(Symbol *sym) const {
1367 std::string name = maybeDemangleSymbol(ctx, symName: sym->getName());
1368 if (ctx.hybridSymtab)
1369 return name + (isEC() ? " (EC symbol)" : " (native symbol)");
1370 return name;
1371}
1372
1373void SymbolTable::compileBitcodeFiles() {
1374 if (bitcodeFileInstances.empty())
1375 return;
1376
1377 llvm::TimeTraceScope timeScope("Compile bitcode");
1378 ScopedTimer t(ctx.ltoTimer);
1379 lto.reset(p: new BitcodeCompiler(ctx));
1380 for (BitcodeFile *f : bitcodeFileInstances)
1381 lto->add(f&: *f);
1382 for (InputFile *newObj : lto->compile()) {
1383 ObjFile *obj = cast<ObjFile>(Val: newObj);
1384 obj->parse();
1385 ctx.objFileInstances.push_back(x: obj);
1386 }
1387}
1388
1389} // namespace lld::coff
1390

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of lld/COFF/SymbolTable.cpp