[NFC][RemoveDIs] Prefer iterators over inst-pointers in InstCombine
[llvm-project.git] / lld / wasm / SymbolTable.cpp
blobd33176a0fa54ad6d5d3c12d33769651ab4410399
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 //===----------------------------------------------------------------------===//
9 #include "SymbolTable.h"
10 #include "Config.h"
11 #include "InputChunks.h"
12 #include "InputElement.h"
13 #include "WriterUtils.h"
14 #include "lld/Common/CommonLinkerContext.h"
15 #include <optional>
17 #define DEBUG_TYPE "lld"
19 using namespace llvm;
20 using namespace llvm::wasm;
21 using namespace llvm::object;
23 namespace lld::wasm {
24 SymbolTable *symtab;
26 void SymbolTable::addFile(InputFile *file) {
27 log("Processing: " + toString(file));
29 // .a file
30 if (auto *f = dyn_cast<ArchiveFile>(file)) {
31 f->parse();
32 return;
35 // .so file
36 if (auto *f = dyn_cast<SharedFile>(file)) {
37 sharedFiles.push_back(f);
38 return;
41 // stub file
42 if (auto *f = dyn_cast<StubFile>(file)) {
43 f->parse();
44 stubFiles.push_back(f);
45 return;
48 if (config->trace)
49 message(toString(file));
51 // LLVM bitcode file
52 if (auto *f = dyn_cast<BitcodeFile>(file)) {
53 f->parse();
54 bitcodeFiles.push_back(f);
55 return;
58 // Regular object file
59 auto *f = cast<ObjFile>(file);
60 f->parse(false);
61 objectFiles.push_back(f);
64 // This function is where all the optimizations of link-time
65 // optimization happens. When LTO is in use, some input files are
66 // not in native object file format but in the LLVM bitcode format.
67 // This function compiles bitcode files into a few big native files
68 // using LLVM functions and replaces bitcode symbols with the results.
69 // Because all bitcode files that the program consists of are passed
70 // to the compiler at once, it can do whole-program optimization.
71 void SymbolTable::compileBitcodeFiles() {
72 // Prevent further LTO objects being included
73 BitcodeFile::doneLTO = true;
75 if (bitcodeFiles.empty())
76 return;
78 // Compile bitcode files and replace bitcode symbols.
79 lto.reset(new BitcodeCompiler);
80 for (BitcodeFile *f : bitcodeFiles)
81 lto->add(*f);
83 for (StringRef filename : lto->compile()) {
84 auto *obj = make<ObjFile>(MemoryBufferRef(filename, "lto.tmp"), "");
85 obj->parse(true);
86 objectFiles.push_back(obj);
90 Symbol *SymbolTable::find(StringRef name) {
91 auto it = symMap.find(CachedHashStringRef(name));
92 if (it == symMap.end() || it->second == -1)
93 return nullptr;
94 return symVector[it->second];
97 void SymbolTable::replace(StringRef name, Symbol* sym) {
98 auto it = symMap.find(CachedHashStringRef(name));
99 symVector[it->second] = sym;
102 std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) {
103 bool trace = false;
104 auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()});
105 int &symIndex = p.first->second;
106 bool isNew = p.second;
107 if (symIndex == -1) {
108 symIndex = symVector.size();
109 trace = true;
110 isNew = true;
113 if (!isNew)
114 return {symVector[symIndex], false};
116 Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
117 sym->isUsedInRegularObj = false;
118 sym->canInline = true;
119 sym->traced = trace;
120 sym->forceExport = false;
121 sym->referenced = !config->gcSections;
122 symVector.emplace_back(sym);
123 return {sym, true};
126 std::pair<Symbol *, bool> SymbolTable::insert(StringRef name,
127 const InputFile *file) {
128 Symbol *s;
129 bool wasInserted;
130 std::tie(s, wasInserted) = insertName(name);
132 if (!file || file->kind() == InputFile::ObjectKind)
133 s->isUsedInRegularObj = true;
135 return {s, wasInserted};
138 static void reportTypeError(const Symbol *existing, const InputFile *file,
139 llvm::wasm::WasmSymbolType type) {
140 error("symbol type mismatch: " + toString(*existing) + "\n>>> defined as " +
141 toString(existing->getWasmType()) + " in " +
142 toString(existing->getFile()) + "\n>>> defined as " + toString(type) +
143 " in " + toString(file));
146 // Check the type of new symbol matches that of the symbol is replacing.
147 // Returns true if the function types match, false is there is a signature
148 // mismatch.
149 static bool signatureMatches(FunctionSymbol *existing,
150 const WasmSignature *newSig) {
151 const WasmSignature *oldSig = existing->signature;
153 // If either function is missing a signature (this happens for bitcode
154 // symbols) then assume they match. Any mismatch will be reported later
155 // when the LTO objects are added.
156 if (!newSig || !oldSig)
157 return true;
159 return *newSig == *oldSig;
162 static void checkGlobalType(const Symbol *existing, const InputFile *file,
163 const WasmGlobalType *newType) {
164 if (!isa<GlobalSymbol>(existing)) {
165 reportTypeError(existing, file, WASM_SYMBOL_TYPE_GLOBAL);
166 return;
169 const WasmGlobalType *oldType = cast<GlobalSymbol>(existing)->getGlobalType();
170 if (*newType != *oldType) {
171 error("Global type mismatch: " + existing->getName() + "\n>>> defined as " +
172 toString(*oldType) + " in " + toString(existing->getFile()) +
173 "\n>>> defined as " + toString(*newType) + " in " + toString(file));
177 static void checkTagType(const Symbol *existing, const InputFile *file,
178 const WasmSignature *newSig) {
179 const auto *existingTag = dyn_cast<TagSymbol>(existing);
180 if (!isa<TagSymbol>(existing)) {
181 reportTypeError(existing, file, WASM_SYMBOL_TYPE_TAG);
182 return;
185 const WasmSignature *oldSig = existingTag->signature;
186 if (*newSig != *oldSig)
187 warn("Tag signature mismatch: " + existing->getName() +
188 "\n>>> defined as " + toString(*oldSig) + " in " +
189 toString(existing->getFile()) + "\n>>> defined as " +
190 toString(*newSig) + " in " + toString(file));
193 static void checkTableType(const Symbol *existing, const InputFile *file,
194 const WasmTableType *newType) {
195 if (!isa<TableSymbol>(existing)) {
196 reportTypeError(existing, file, WASM_SYMBOL_TYPE_TABLE);
197 return;
200 const WasmTableType *oldType = cast<TableSymbol>(existing)->getTableType();
201 if (newType->ElemType != oldType->ElemType) {
202 error("Table type mismatch: " + existing->getName() + "\n>>> defined as " +
203 toString(*oldType) + " in " + toString(existing->getFile()) +
204 "\n>>> defined as " + toString(*newType) + " in " + toString(file));
206 // FIXME: No assertions currently on the limits.
209 static void checkDataType(const Symbol *existing, const InputFile *file) {
210 if (!isa<DataSymbol>(existing))
211 reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA);
214 DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name,
215 uint32_t flags,
216 InputFunction *function) {
217 LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n");
218 assert(!find(name));
219 syntheticFunctions.emplace_back(function);
220 return replaceSymbol<DefinedFunction>(insertName(name).first, name,
221 flags, nullptr, function);
224 // Adds an optional, linker generated, data symbol. The symbol will only be
225 // added if there is an undefine reference to it, or if it is explicitly
226 // exported via the --export flag. Otherwise we don't add the symbol and return
227 // nullptr.
228 DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name,
229 uint64_t value) {
230 Symbol *s = find(name);
231 if (!s && (config->exportAll || config->exportedSymbols.count(name) != 0))
232 s = insertName(name).first;
233 else if (!s || s->isDefined())
234 return nullptr;
235 LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n");
236 auto *rtn = replaceSymbol<DefinedData>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN);
237 rtn->setVA(value);
238 rtn->referenced = true;
239 return rtn;
242 DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name,
243 uint32_t flags) {
244 LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n");
245 assert(!find(name));
246 return replaceSymbol<DefinedData>(insertName(name).first, name, flags);
249 DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags,
250 InputGlobal *global) {
251 LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global
252 << "\n");
253 assert(!find(name));
254 syntheticGlobals.emplace_back(global);
255 return replaceSymbol<DefinedGlobal>(insertName(name).first, name, flags,
256 nullptr, global);
259 DefinedGlobal *SymbolTable::addOptionalGlobalSymbol(StringRef name,
260 InputGlobal *global) {
261 Symbol *s = find(name);
262 if (!s || s->isDefined())
263 return nullptr;
264 LLVM_DEBUG(dbgs() << "addOptionalGlobalSymbol: " << name << " -> " << global
265 << "\n");
266 syntheticGlobals.emplace_back(global);
267 return replaceSymbol<DefinedGlobal>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN,
268 nullptr, global);
271 DefinedTable *SymbolTable::addSyntheticTable(StringRef name, uint32_t flags,
272 InputTable *table) {
273 LLVM_DEBUG(dbgs() << "addSyntheticTable: " << name << " -> " << table
274 << "\n");
275 Symbol *s = find(name);
276 assert(!s || s->isUndefined());
277 if (!s)
278 s = insertName(name).first;
279 syntheticTables.emplace_back(table);
280 return replaceSymbol<DefinedTable>(s, name, flags, nullptr, table);
283 static bool shouldReplace(const Symbol *existing, InputFile *newFile,
284 uint32_t newFlags) {
285 // If existing symbol is undefined, replace it.
286 if (!existing->isDefined()) {
287 LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
288 << existing->getName() << "\n");
289 return true;
292 // Now we have two defined symbols. If the new one is weak, we can ignore it.
293 if ((newFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
294 LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
295 return false;
298 // If the existing symbol is weak, we should replace it.
299 if (existing->isWeak()) {
300 LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
301 return true;
304 // Neither symbol is week. They conflict.
305 error("duplicate symbol: " + toString(*existing) + "\n>>> defined in " +
306 toString(existing->getFile()) + "\n>>> defined in " +
307 toString(newFile));
308 return true;
311 Symbol *SymbolTable::addDefinedFunction(StringRef name, uint32_t flags,
312 InputFile *file,
313 InputFunction *function) {
314 LLVM_DEBUG(dbgs() << "addDefinedFunction: " << name << " ["
315 << (function ? toString(function->signature) : "none")
316 << "]\n");
317 Symbol *s;
318 bool wasInserted;
319 std::tie(s, wasInserted) = insert(name, file);
321 auto replaceSym = [&](Symbol *sym) {
322 // If the new defined function doesn't have signature (i.e. bitcode
323 // functions) but the old symbol does, then preserve the old signature
324 const WasmSignature *oldSig = s->getSignature();
325 auto* newSym = replaceSymbol<DefinedFunction>(sym, name, flags, file, function);
326 if (!newSym->signature)
327 newSym->signature = oldSig;
330 if (wasInserted || s->isLazy()) {
331 replaceSym(s);
332 return s;
335 auto existingFunction = dyn_cast<FunctionSymbol>(s);
336 if (!existingFunction) {
337 reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION);
338 return s;
341 bool checkSig = true;
342 if (auto ud = dyn_cast<UndefinedFunction>(existingFunction))
343 checkSig = ud->isCalledDirectly;
345 if (checkSig && function && !signatureMatches(existingFunction, &function->signature)) {
346 Symbol* variant;
347 if (getFunctionVariant(s, &function->signature, file, &variant))
348 // New variant, always replace
349 replaceSym(variant);
350 else if (shouldReplace(s, file, flags))
351 // Variant already exists, replace it after checking shouldReplace
352 replaceSym(variant);
354 // This variant we found take the place in the symbol table as the primary
355 // variant.
356 replace(name, variant);
357 return variant;
360 // Existing function with matching signature.
361 if (shouldReplace(s, file, flags))
362 replaceSym(s);
364 return s;
367 Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags,
368 InputFile *file, InputChunk *segment,
369 uint64_t address, uint64_t size) {
370 LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address
371 << "\n");
372 Symbol *s;
373 bool wasInserted;
374 std::tie(s, wasInserted) = insert(name, file);
376 auto replaceSym = [&]() {
377 replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size);
380 if (wasInserted || s->isLazy()) {
381 replaceSym();
382 return s;
385 checkDataType(s, file);
387 if (shouldReplace(s, file, flags))
388 replaceSym();
389 return s;
392 Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags,
393 InputFile *file, InputGlobal *global) {
394 LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n");
396 Symbol *s;
397 bool wasInserted;
398 std::tie(s, wasInserted) = insert(name, file);
400 auto replaceSym = [&]() {
401 replaceSymbol<DefinedGlobal>(s, name, flags, file, global);
404 if (wasInserted || s->isLazy()) {
405 replaceSym();
406 return s;
409 checkGlobalType(s, file, &global->getType());
411 if (shouldReplace(s, file, flags))
412 replaceSym();
413 return s;
416 Symbol *SymbolTable::addDefinedTag(StringRef name, uint32_t flags,
417 InputFile *file, InputTag *tag) {
418 LLVM_DEBUG(dbgs() << "addDefinedTag:" << name << "\n");
420 Symbol *s;
421 bool wasInserted;
422 std::tie(s, wasInserted) = insert(name, file);
424 auto replaceSym = [&]() {
425 replaceSymbol<DefinedTag>(s, name, flags, file, tag);
428 if (wasInserted || s->isLazy()) {
429 replaceSym();
430 return s;
433 checkTagType(s, file, &tag->signature);
435 if (shouldReplace(s, file, flags))
436 replaceSym();
437 return s;
440 Symbol *SymbolTable::addDefinedTable(StringRef name, uint32_t flags,
441 InputFile *file, InputTable *table) {
442 LLVM_DEBUG(dbgs() << "addDefinedTable:" << name << "\n");
444 Symbol *s;
445 bool wasInserted;
446 std::tie(s, wasInserted) = insert(name, file);
448 auto replaceSym = [&]() {
449 replaceSymbol<DefinedTable>(s, name, flags, file, table);
452 if (wasInserted || s->isLazy()) {
453 replaceSym();
454 return s;
457 checkTableType(s, file, &table->getType());
459 if (shouldReplace(s, file, flags))
460 replaceSym();
461 return s;
464 // This function get called when an undefined symbol is added, and there is
465 // already an existing one in the symbols table. In this case we check that
466 // custom 'import-module' and 'import-field' symbol attributes agree.
467 // With LTO these attributes are not available when the bitcode is read and only
468 // become available when the LTO object is read. In this case we silently
469 // replace the empty attributes with the valid ones.
470 template <typename T>
471 static void setImportAttributes(T *existing,
472 std::optional<StringRef> importName,
473 std::optional<StringRef> importModule,
474 uint32_t flags, InputFile *file) {
475 if (importName) {
476 if (!existing->importName)
477 existing->importName = importName;
478 if (existing->importName != importName)
479 error("import name mismatch for symbol: " + toString(*existing) +
480 "\n>>> defined as " + *existing->importName + " in " +
481 toString(existing->getFile()) + "\n>>> defined as " + *importName +
482 " in " + toString(file));
485 if (importModule) {
486 if (!existing->importModule)
487 existing->importModule = importModule;
488 if (existing->importModule != importModule)
489 error("import module mismatch for symbol: " + toString(*existing) +
490 "\n>>> defined as " + *existing->importModule + " in " +
491 toString(existing->getFile()) + "\n>>> defined as " +
492 *importModule + " in " + toString(file));
495 // Update symbol binding, if the existing symbol is weak
496 uint32_t binding = flags & WASM_SYMBOL_BINDING_MASK;
497 if (existing->isWeak() && binding != WASM_SYMBOL_BINDING_WEAK) {
498 existing->flags = (existing->flags & ~WASM_SYMBOL_BINDING_MASK) | binding;
502 Symbol *SymbolTable::addUndefinedFunction(StringRef name,
503 std::optional<StringRef> importName,
504 std::optional<StringRef> importModule,
505 uint32_t flags, InputFile *file,
506 const WasmSignature *sig,
507 bool isCalledDirectly) {
508 LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " ["
509 << (sig ? toString(*sig) : "none")
510 << "] IsCalledDirectly:" << isCalledDirectly << " flags=0x"
511 << utohexstr(flags) << "\n");
512 assert(flags & WASM_SYMBOL_UNDEFINED);
514 Symbol *s;
515 bool wasInserted;
516 std::tie(s, wasInserted) = insert(name, file);
517 if (s->traced)
518 printTraceSymbolUndefined(name, file);
520 auto replaceSym = [&]() {
521 replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags,
522 file, sig, isCalledDirectly);
525 if (wasInserted) {
526 replaceSym();
527 } else if (auto *lazy = dyn_cast<LazySymbol>(s)) {
528 if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
529 lazy->setWeak();
530 lazy->signature = sig;
531 } else {
532 lazy->fetch();
533 if (!config->whyExtract.empty())
534 config->whyExtractRecords.emplace_back(toString(file), s->getFile(),
535 *s);
537 } else {
538 auto existingFunction = dyn_cast<FunctionSymbol>(s);
539 if (!existingFunction) {
540 reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION);
541 return s;
543 if (!existingFunction->signature && sig)
544 existingFunction->signature = sig;
545 auto *existingUndefined = dyn_cast<UndefinedFunction>(existingFunction);
546 if (isCalledDirectly && !signatureMatches(existingFunction, sig)) {
547 // If the existing undefined functions is not called directly then let
548 // this one take precedence. Otherwise the existing function is either
549 // directly called or defined, in which case we need a function variant.
550 if (existingUndefined && !existingUndefined->isCalledDirectly)
551 replaceSym();
552 else if (getFunctionVariant(s, sig, file, &s))
553 replaceSym();
555 if (existingUndefined) {
556 setImportAttributes(existingUndefined, importName, importModule, flags,
557 file);
558 if (isCalledDirectly)
559 existingUndefined->isCalledDirectly = true;
560 if (s->isWeak())
561 s->flags = flags;
565 return s;
568 Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags,
569 InputFile *file) {
570 LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n");
571 assert(flags & WASM_SYMBOL_UNDEFINED);
573 Symbol *s;
574 bool wasInserted;
575 std::tie(s, wasInserted) = insert(name, file);
576 if (s->traced)
577 printTraceSymbolUndefined(name, file);
579 if (wasInserted) {
580 replaceSymbol<UndefinedData>(s, name, flags, file);
581 } else if (auto *lazy = dyn_cast<LazySymbol>(s)) {
582 if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK)
583 lazy->setWeak();
584 else
585 lazy->fetch();
586 } else if (s->isDefined()) {
587 checkDataType(s, file);
588 } else if (s->isWeak()) {
589 s->flags = flags;
591 return s;
594 Symbol *SymbolTable::addUndefinedGlobal(StringRef name,
595 std::optional<StringRef> importName,
596 std::optional<StringRef> importModule,
597 uint32_t flags, InputFile *file,
598 const WasmGlobalType *type) {
599 LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n");
600 assert(flags & WASM_SYMBOL_UNDEFINED);
602 Symbol *s;
603 bool wasInserted;
604 std::tie(s, wasInserted) = insert(name, file);
605 if (s->traced)
606 printTraceSymbolUndefined(name, file);
608 if (wasInserted)
609 replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags,
610 file, type);
611 else if (auto *lazy = dyn_cast<LazySymbol>(s))
612 lazy->fetch();
613 else if (s->isDefined())
614 checkGlobalType(s, file, type);
615 else if (s->isWeak())
616 s->flags = flags;
617 return s;
620 Symbol *SymbolTable::addUndefinedTable(StringRef name,
621 std::optional<StringRef> importName,
622 std::optional<StringRef> importModule,
623 uint32_t flags, InputFile *file,
624 const WasmTableType *type) {
625 LLVM_DEBUG(dbgs() << "addUndefinedTable: " << name << "\n");
626 assert(flags & WASM_SYMBOL_UNDEFINED);
628 Symbol *s;
629 bool wasInserted;
630 std::tie(s, wasInserted) = insert(name, file);
631 if (s->traced)
632 printTraceSymbolUndefined(name, file);
634 if (wasInserted)
635 replaceSymbol<UndefinedTable>(s, name, importName, importModule, flags,
636 file, type);
637 else if (auto *lazy = dyn_cast<LazySymbol>(s))
638 lazy->fetch();
639 else if (s->isDefined())
640 checkTableType(s, file, type);
641 else if (s->isWeak())
642 s->flags = flags;
643 return s;
646 Symbol *SymbolTable::addUndefinedTag(StringRef name,
647 std::optional<StringRef> importName,
648 std::optional<StringRef> importModule,
649 uint32_t flags, InputFile *file,
650 const WasmSignature *sig) {
651 LLVM_DEBUG(dbgs() << "addUndefinedTag: " << name << "\n");
652 assert(flags & WASM_SYMBOL_UNDEFINED);
654 Symbol *s;
655 bool wasInserted;
656 std::tie(s, wasInserted) = insert(name, file);
657 if (s->traced)
658 printTraceSymbolUndefined(name, file);
660 if (wasInserted)
661 replaceSymbol<UndefinedTag>(s, name, importName, importModule, flags, file,
662 sig);
663 else if (auto *lazy = dyn_cast<LazySymbol>(s))
664 lazy->fetch();
665 else if (s->isDefined())
666 checkTagType(s, file, sig);
667 else if (s->isWeak())
668 s->flags = flags;
669 return s;
672 TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) {
673 WasmLimits limits{0, 0, 0}; // Set by the writer.
674 WasmTableType *type = make<WasmTableType>();
675 type->ElemType = uint8_t(ValType::FUNCREF);
676 type->Limits = limits;
677 StringRef module(defaultModule);
678 uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN;
679 flags |= WASM_SYMBOL_UNDEFINED;
680 Symbol *sym = addUndefinedTable(name, name, module, flags, nullptr, type);
681 sym->markLive();
682 sym->forceExport = config->exportTable;
683 return cast<TableSymbol>(sym);
686 TableSymbol *SymbolTable::createDefinedIndirectFunctionTable(StringRef name) {
687 const uint32_t invalidIndex = -1;
688 WasmLimits limits{0, 0, 0}; // Set by the writer.
689 WasmTableType type{uint8_t(ValType::FUNCREF), limits};
690 WasmTable desc{invalidIndex, type, name};
691 InputTable *table = make<InputTable>(desc, nullptr);
692 uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN;
693 TableSymbol *sym = addSyntheticTable(name, flags, table);
694 sym->markLive();
695 sym->forceExport = config->exportTable;
696 return sym;
699 // Whether or not we need an indirect function table is usually a function of
700 // whether an input declares a need for it. However sometimes it's possible for
701 // no input to need the indirect function table, but then a late
702 // addInternalGOTEntry causes a function to be allocated an address. In that
703 // case address we synthesize a definition at the last minute.
704 TableSymbol *SymbolTable::resolveIndirectFunctionTable(bool required) {
705 Symbol *existing = find(functionTableName);
706 if (existing) {
707 if (!isa<TableSymbol>(existing)) {
708 error(Twine("reserved symbol must be of type table: `") +
709 functionTableName + "`");
710 return nullptr;
712 if (existing->isDefined()) {
713 error(Twine("reserved symbol must not be defined in input files: `") +
714 functionTableName + "`");
715 return nullptr;
719 if (config->importTable) {
720 if (existing)
721 return cast<TableSymbol>(existing);
722 if (required)
723 return createUndefinedIndirectFunctionTable(functionTableName);
724 } else if ((existing && existing->isLive()) || config->exportTable ||
725 required) {
726 // A defined table is required. Either because the user request an exported
727 // table or because the table symbol is already live. The existing table is
728 // guaranteed to be undefined due to the check above.
729 return createDefinedIndirectFunctionTable(functionTableName);
732 // An indirect function table will only be present in the symbol table if
733 // needed by a reloc; if we get here, we don't need one.
734 return nullptr;
737 void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) {
738 LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n");
739 StringRef name = sym->getName();
741 Symbol *s;
742 bool wasInserted;
743 std::tie(s, wasInserted) = insertName(name);
745 if (wasInserted) {
746 replaceSymbol<LazySymbol>(s, name, 0, file, *sym);
747 return;
750 if (!s->isUndefined())
751 return;
753 // The existing symbol is undefined, load a new one from the archive,
754 // unless the existing symbol is weak in which case replace the undefined
755 // symbols with a LazySymbol.
756 if (s->isWeak()) {
757 const WasmSignature *oldSig = nullptr;
758 // In the case of an UndefinedFunction we need to preserve the expected
759 // signature.
760 if (auto *f = dyn_cast<UndefinedFunction>(s))
761 oldSig = f->signature;
762 LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
763 auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK,
764 file, *sym);
765 newSym->signature = oldSig;
766 return;
769 LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
770 const InputFile *oldFile = s->getFile();
771 file->addMember(sym);
772 if (!config->whyExtract.empty())
773 config->whyExtractRecords.emplace_back(toString(oldFile), s->getFile(), *s);
776 bool SymbolTable::addComdat(StringRef name) {
777 return comdatGroups.insert(CachedHashStringRef(name)).second;
780 // The new signature doesn't match. Create a variant to the symbol with the
781 // signature encoded in the name and return that instead. These symbols are
782 // then unified later in handleSymbolVariants.
783 bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig,
784 const InputFile *file, Symbol **out) {
785 LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> "
786 << " " << toString(*sig) << "\n");
787 Symbol *variant = nullptr;
789 // Linear search through symbol variants. Should never be more than two
790 // or three entries here.
791 auto &variants = symVariants[CachedHashStringRef(sym->getName())];
792 if (variants.empty())
793 variants.push_back(sym);
795 for (Symbol* v : variants) {
796 if (*v->getSignature() == *sig) {
797 variant = v;
798 break;
802 bool wasAdded = !variant;
803 if (wasAdded) {
804 // Create a new variant;
805 LLVM_DEBUG(dbgs() << "added new variant\n");
806 variant = reinterpret_cast<Symbol *>(make<SymbolUnion>());
807 variant->isUsedInRegularObj =
808 !file || file->kind() == InputFile::ObjectKind;
809 variant->canInline = true;
810 variant->traced = false;
811 variant->forceExport = false;
812 variants.push_back(variant);
813 } else {
814 LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n");
815 assert(*variant->getSignature() == *sig);
818 *out = variant;
819 return wasAdded;
822 // Set a flag for --trace-symbol so that we can print out a log message
823 // if a new symbol with the same name is inserted into the symbol table.
824 void SymbolTable::trace(StringRef name) {
825 symMap.insert({CachedHashStringRef(name), -1});
828 void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) {
829 // Swap symbols as instructed by -wrap.
830 int &origIdx = symMap[CachedHashStringRef(sym->getName())];
831 int &realIdx= symMap[CachedHashStringRef(real->getName())];
832 int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())];
833 LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n");
835 // Anyone looking up __real symbols should get the original
836 realIdx = origIdx;
837 // Anyone looking up the original should get the __wrap symbol
838 origIdx = wrapIdx;
841 static const uint8_t unreachableFn[] = {
842 0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
843 0x00 /* opcode unreachable */, 0x0b /* opcode end */
846 // Replace the given symbol body with an unreachable function.
847 // This is used by handleWeakUndefines in order to generate a callable
848 // equivalent of an undefined function and also handleSymbolVariants for
849 // undefined functions that don't match the signature of the definition.
850 InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym,
851 const WasmSignature &sig,
852 StringRef debugName) {
853 auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName);
854 func->setBody(unreachableFn);
855 syntheticFunctions.emplace_back(func);
856 // Mark new symbols as local. For relocatable output we don't want them
857 // to be exported outside the object file.
858 replaceSymbol<DefinedFunction>(sym, debugName, WASM_SYMBOL_BINDING_LOCAL,
859 nullptr, func);
860 // Ensure the stub function doesn't get a table entry. Its address
861 // should always compare equal to the null pointer.
862 sym->isStub = true;
863 return func;
866 void SymbolTable::replaceWithUndefined(Symbol *sym) {
867 // Add a synthetic dummy for weak undefined functions. These dummies will
868 // be GC'd if not used as the target of any "call" instructions.
869 StringRef debugName = saver().save("undefined_weak:" + toString(*sym));
870 replaceWithUnreachable(sym, *sym->getSignature(), debugName);
871 // Hide our dummy to prevent export.
872 sym->setHidden(true);
875 // For weak undefined functions, there may be "call" instructions that reference
876 // the symbol. In this case, we need to synthesise a dummy/stub function that
877 // will abort at runtime, so that relocations can still provided an operand to
878 // the call instruction that passes Wasm validation.
879 void SymbolTable::handleWeakUndefines() {
880 for (Symbol *sym : symbols()) {
881 if (sym->isUndefWeak() && sym->isUsedInRegularObj) {
882 if (sym->getSignature()) {
883 replaceWithUndefined(sym);
884 } else {
885 // It is possible for undefined functions not to have a signature (eg.
886 // if added via "--undefined"), but weak undefined ones do have a
887 // signature. Lazy symbols may not be functions and therefore Sig can
888 // still be null in some circumstance.
889 assert(!isa<FunctionSymbol>(sym));
895 DefinedFunction *SymbolTable::createUndefinedStub(const WasmSignature &sig) {
896 if (stubFunctions.count(sig))
897 return stubFunctions[sig];
898 LLVM_DEBUG(dbgs() << "createUndefinedStub: " << toString(sig) << "\n");
899 auto *sym = reinterpret_cast<DefinedFunction *>(make<SymbolUnion>());
900 sym->isUsedInRegularObj = true;
901 sym->canInline = true;
902 sym->traced = false;
903 sym->forceExport = false;
904 sym->signature = &sig;
905 replaceSymbol<DefinedFunction>(
906 sym, "undefined_stub", WASM_SYMBOL_VISIBILITY_HIDDEN, nullptr, nullptr);
907 replaceWithUnreachable(sym, sig, "undefined_stub");
908 stubFunctions[sig] = sym;
909 return sym;
912 static void reportFunctionSignatureMismatch(StringRef symName,
913 FunctionSymbol *a,
914 FunctionSymbol *b, bool isError) {
915 std::string msg = ("function signature mismatch: " + symName +
916 "\n>>> defined as " + toString(*a->signature) + " in " +
917 toString(a->getFile()) + "\n>>> defined as " +
918 toString(*b->signature) + " in " + toString(b->getFile()))
919 .str();
920 if (isError)
921 error(msg);
922 else
923 warn(msg);
926 // Remove any variant symbols that were created due to function signature
927 // mismatches.
928 void SymbolTable::handleSymbolVariants() {
929 for (auto pair : symVariants) {
930 // Push the initial symbol onto the list of variants.
931 StringRef symName = pair.first.val();
932 std::vector<Symbol *> &variants = pair.second;
934 #ifndef NDEBUG
935 LLVM_DEBUG(dbgs() << "symbol with (" << variants.size()
936 << ") variants: " << symName << "\n");
937 for (auto *s: variants) {
938 auto *f = cast<FunctionSymbol>(s);
939 LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " "
940 << toString(*f->signature) << "\n");
942 #endif
944 // Find the one definition.
945 DefinedFunction *defined = nullptr;
946 for (auto *symbol : variants) {
947 if (auto f = dyn_cast<DefinedFunction>(symbol)) {
948 defined = f;
949 break;
953 // If there are no definitions, and the undefined symbols disagree on
954 // the signature, there is not we can do since we don't know which one
955 // to use as the signature on the import.
956 if (!defined) {
957 reportFunctionSignatureMismatch(symName,
958 cast<FunctionSymbol>(variants[0]),
959 cast<FunctionSymbol>(variants[1]), true);
960 return;
963 for (auto *symbol : variants) {
964 if (symbol != defined) {
965 auto *f = cast<FunctionSymbol>(symbol);
966 reportFunctionSignatureMismatch(symName, f, defined, false);
967 StringRef debugName =
968 saver().save("signature_mismatch:" + toString(*f));
969 replaceWithUnreachable(f, *f->signature, debugName);
975 } // namespace wasm::lld