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 "Config.h"
11 #include "InputChunks.h"
12 #include "InputElement.h"
13 #include "WriterUtils.h"
14 #include "lld/Common/ErrorHandler.h"
15 #include "lld/Common/Memory.h"
16 #include "llvm/ADT/SetVector.h"
17
18 #define DEBUG_TYPE "lld"
19
20 using namespace llvm;
21 using namespace llvm::wasm;
22 using namespace llvm::object;
23
24 namespace lld {
25 namespace wasm {
26 SymbolTable *symtab;
27
addFile(InputFile * file)28 void SymbolTable::addFile(InputFile *file) {
29 log("Processing: " + toString(file));
30
31 // .a file
32 if (auto *f = dyn_cast<ArchiveFile>(file)) {
33 f->parse();
34 return;
35 }
36
37 // .so file
38 if (auto *f = dyn_cast<SharedFile>(file)) {
39 sharedFiles.push_back(f);
40 return;
41 }
42
43 if (config->trace)
44 message(toString(file));
45
46 // LLVM bitcode file
47 if (auto *f = dyn_cast<BitcodeFile>(file)) {
48 f->parse();
49 bitcodeFiles.push_back(f);
50 return;
51 }
52
53 // Regular object file
54 auto *f = cast<ObjFile>(file);
55 f->parse(false);
56 objectFiles.push_back(f);
57 }
58
59 // This function is where all the optimizations of link-time
60 // optimization happens. When LTO is in use, some input files are
61 // not in native object file format but in the LLVM bitcode format.
62 // This function compiles bitcode files into a few big native files
63 // using LLVM functions and replaces bitcode symbols with the results.
64 // Because all bitcode files that the program consists of are passed
65 // to the compiler at once, it can do whole-program optimization.
addCombinedLTOObject()66 void SymbolTable::addCombinedLTOObject() {
67 // Prevent further LTO objects being included
68 BitcodeFile::doneLTO = true;
69
70 if (bitcodeFiles.empty())
71 return;
72
73 // Compile bitcode files and replace bitcode symbols.
74 lto.reset(new BitcodeCompiler);
75 for (BitcodeFile *f : bitcodeFiles)
76 lto->add(*f);
77
78 for (StringRef filename : lto->compile()) {
79 auto *obj = make<ObjFile>(MemoryBufferRef(filename, "lto.tmp"), "");
80 obj->parse(true);
81 objectFiles.push_back(obj);
82 }
83 }
84
find(StringRef name)85 Symbol *SymbolTable::find(StringRef name) {
86 auto it = symMap.find(CachedHashStringRef(name));
87 if (it == symMap.end() || it->second == -1)
88 return nullptr;
89 return symVector[it->second];
90 }
91
replace(StringRef name,Symbol * sym)92 void SymbolTable::replace(StringRef name, Symbol* sym) {
93 auto it = symMap.find(CachedHashStringRef(name));
94 symVector[it->second] = sym;
95 }
96
insertName(StringRef name)97 std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) {
98 bool trace = false;
99 auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()});
100 int &symIndex = p.first->second;
101 bool isNew = p.second;
102 if (symIndex == -1) {
103 symIndex = symVector.size();
104 trace = true;
105 isNew = true;
106 }
107
108 if (!isNew)
109 return {symVector[symIndex], false};
110
111 Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
112 sym->isUsedInRegularObj = false;
113 sym->canInline = true;
114 sym->traced = trace;
115 sym->forceExport = false;
116 symVector.emplace_back(sym);
117 return {sym, true};
118 }
119
insert(StringRef name,const InputFile * file)120 std::pair<Symbol *, bool> SymbolTable::insert(StringRef name,
121 const InputFile *file) {
122 Symbol *s;
123 bool wasInserted;
124 std::tie(s, wasInserted) = insertName(name);
125
126 if (!file || file->kind() == InputFile::ObjectKind)
127 s->isUsedInRegularObj = true;
128
129 return {s, wasInserted};
130 }
131
reportTypeError(const Symbol * existing,const InputFile * file,llvm::wasm::WasmSymbolType type)132 static void reportTypeError(const Symbol *existing, const InputFile *file,
133 llvm::wasm::WasmSymbolType type) {
134 error("symbol type mismatch: " + toString(*existing) + "\n>>> defined as " +
135 toString(existing->getWasmType()) + " in " +
136 toString(existing->getFile()) + "\n>>> defined as " + toString(type) +
137 " in " + toString(file));
138 }
139
140 // Check the type of new symbol matches that of the symbol is replacing.
141 // Returns true if the function types match, false is there is a signature
142 // mismatch.
signatureMatches(FunctionSymbol * existing,const WasmSignature * newSig)143 static bool signatureMatches(FunctionSymbol *existing,
144 const WasmSignature *newSig) {
145 const WasmSignature *oldSig = existing->signature;
146
147 // If either function is missing a signature (this happend for bitcode
148 // symbols) then assume they match. Any mismatch will be reported later
149 // when the LTO objects are added.
150 if (!newSig || !oldSig)
151 return true;
152
153 return *newSig == *oldSig;
154 }
155
checkGlobalType(const Symbol * existing,const InputFile * file,const WasmGlobalType * newType)156 static void checkGlobalType(const Symbol *existing, const InputFile *file,
157 const WasmGlobalType *newType) {
158 if (!isa<GlobalSymbol>(existing)) {
159 reportTypeError(existing, file, WASM_SYMBOL_TYPE_GLOBAL);
160 return;
161 }
162
163 const WasmGlobalType *oldType = cast<GlobalSymbol>(existing)->getGlobalType();
164 if (*newType != *oldType) {
165 error("Global type mismatch: " + existing->getName() + "\n>>> defined as " +
166 toString(*oldType) + " in " + toString(existing->getFile()) +
167 "\n>>> defined as " + toString(*newType) + " in " + toString(file));
168 }
169 }
170
checkTagType(const Symbol * existing,const InputFile * file,const WasmTagType * newType,const WasmSignature * newSig)171 static void checkTagType(const Symbol *existing, const InputFile *file,
172 const WasmTagType *newType,
173 const WasmSignature *newSig) {
174 const auto *existingTag = dyn_cast<TagSymbol>(existing);
175 if (!isa<TagSymbol>(existing)) {
176 reportTypeError(existing, file, WASM_SYMBOL_TYPE_TAG);
177 return;
178 }
179
180 const WasmTagType *oldType = cast<TagSymbol>(existing)->getTagType();
181 const WasmSignature *oldSig = existingTag->signature;
182 if (newType->Attribute != oldType->Attribute)
183 error("Tag type mismatch: " + existing->getName() + "\n>>> defined as " +
184 toString(*oldType) + " in " + toString(existing->getFile()) +
185 "\n>>> defined as " + toString(*newType) + " in " + toString(file));
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));
191 }
192
checkTableType(const Symbol * existing,const InputFile * file,const WasmTableType * newType)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;
198 }
199
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));
205 }
206 // FIXME: No assertions currently on the limits.
207 }
208
checkDataType(const Symbol * existing,const InputFile * file)209 static void checkDataType(const Symbol *existing, const InputFile *file) {
210 if (!isa<DataSymbol>(existing))
211 reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA);
212 }
213
addSyntheticFunction(StringRef name,uint32_t flags,InputFunction * function)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);
222 }
223
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.
addOptionalDataSymbol(StringRef name,uint64_t value)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;
240 }
241
addSyntheticDataSymbol(StringRef name,uint32_t flags)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);
247 }
248
addSyntheticGlobal(StringRef name,uint32_t flags,InputGlobal * global)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);
257 }
258
addOptionalGlobalSymbol(StringRef name,InputGlobal * global)259 DefinedGlobal *SymbolTable::addOptionalGlobalSymbol(StringRef name,
260 InputGlobal *global) {
261 LLVM_DEBUG(dbgs() << "addOptionalGlobalSymbol: " << name << " -> " << global
262 << "\n");
263 Symbol *s = find(name);
264 if (!s || s->isDefined())
265 return nullptr;
266 syntheticGlobals.emplace_back(global);
267 return replaceSymbol<DefinedGlobal>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN,
268 nullptr, global);
269 }
270
addSyntheticTable(StringRef name,uint32_t flags,InputTable * table)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);
281 }
282
shouldReplace(const Symbol * existing,InputFile * newFile,uint32_t newFlags)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;
290 }
291
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;
296 }
297
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;
302 }
303
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;
309 }
310
addDefinedFunction(StringRef name,uint32_t flags,InputFile * file,InputFunction * function)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);
320
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;
328 };
329
330 if (wasInserted || s->isLazy()) {
331 replaceSym(s);
332 return s;
333 }
334
335 auto existingFunction = dyn_cast<FunctionSymbol>(s);
336 if (!existingFunction) {
337 reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION);
338 return s;
339 }
340
341 bool checkSig = true;
342 if (auto ud = dyn_cast<UndefinedFunction>(existingFunction))
343 checkSig = ud->isCalledDirectly;
344
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);
353
354 // This variant we found take the place in the symbol table as the primary
355 // variant.
356 replace(name, variant);
357 return variant;
358 }
359
360 // Existing function with matching signature.
361 if (shouldReplace(s, file, flags))
362 replaceSym(s);
363
364 return s;
365 }
366
addDefinedData(StringRef name,uint32_t flags,InputFile * file,InputChunk * segment,uint64_t address,uint64_t size)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);
375
376 auto replaceSym = [&]() {
377 replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size);
378 };
379
380 if (wasInserted || s->isLazy()) {
381 replaceSym();
382 return s;
383 }
384
385 checkDataType(s, file);
386
387 if (shouldReplace(s, file, flags))
388 replaceSym();
389 return s;
390 }
391
addDefinedGlobal(StringRef name,uint32_t flags,InputFile * file,InputGlobal * global)392 Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags,
393 InputFile *file, InputGlobal *global) {
394 LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n");
395
396 Symbol *s;
397 bool wasInserted;
398 std::tie(s, wasInserted) = insert(name, file);
399
400 auto replaceSym = [&]() {
401 replaceSymbol<DefinedGlobal>(s, name, flags, file, global);
402 };
403
404 if (wasInserted || s->isLazy()) {
405 replaceSym();
406 return s;
407 }
408
409 checkGlobalType(s, file, &global->getType());
410
411 if (shouldReplace(s, file, flags))
412 replaceSym();
413 return s;
414 }
415
addDefinedTag(StringRef name,uint32_t flags,InputFile * file,InputTag * tag)416 Symbol *SymbolTable::addDefinedTag(StringRef name, uint32_t flags,
417 InputFile *file, InputTag *tag) {
418 LLVM_DEBUG(dbgs() << "addDefinedTag:" << name << "\n");
419
420 Symbol *s;
421 bool wasInserted;
422 std::tie(s, wasInserted) = insert(name, file);
423
424 auto replaceSym = [&]() {
425 replaceSymbol<DefinedTag>(s, name, flags, file, tag);
426 };
427
428 if (wasInserted || s->isLazy()) {
429 replaceSym();
430 return s;
431 }
432
433 checkTagType(s, file, &tag->getType(), &tag->signature);
434
435 if (shouldReplace(s, file, flags))
436 replaceSym();
437 return s;
438 }
439
addDefinedTable(StringRef name,uint32_t flags,InputFile * file,InputTable * table)440 Symbol *SymbolTable::addDefinedTable(StringRef name, uint32_t flags,
441 InputFile *file, InputTable *table) {
442 LLVM_DEBUG(dbgs() << "addDefinedTable:" << name << "\n");
443
444 Symbol *s;
445 bool wasInserted;
446 std::tie(s, wasInserted) = insert(name, file);
447
448 auto replaceSym = [&]() {
449 replaceSymbol<DefinedTable>(s, name, flags, file, table);
450 };
451
452 if (wasInserted || s->isLazy()) {
453 replaceSym();
454 return s;
455 }
456
457 checkTableType(s, file, &table->getType());
458
459 if (shouldReplace(s, file, flags))
460 replaceSym();
461 return s;
462 }
463
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>
setImportAttributes(T * existing,Optional<StringRef> importName,Optional<StringRef> importModule,uint32_t flags,InputFile * file)471 static void setImportAttributes(T *existing, Optional<StringRef> importName,
472 Optional<StringRef> importModule,
473 uint32_t flags, InputFile *file) {
474 if (importName) {
475 if (!existing->importName)
476 existing->importName = importName;
477 if (existing->importName != importName)
478 error("import name mismatch for symbol: " + toString(*existing) +
479 "\n>>> defined as " + *existing->importName + " in " +
480 toString(existing->getFile()) + "\n>>> defined as " + *importName +
481 " in " + toString(file));
482 }
483
484 if (importModule) {
485 if (!existing->importModule)
486 existing->importModule = importModule;
487 if (existing->importModule != importModule)
488 error("import module mismatch for symbol: " + toString(*existing) +
489 "\n>>> defined as " + *existing->importModule + " in " +
490 toString(existing->getFile()) + "\n>>> defined as " +
491 *importModule + " in " + toString(file));
492 }
493
494 // Update symbol binding, if the existing symbol is weak
495 uint32_t binding = flags & WASM_SYMBOL_BINDING_MASK;
496 if (existing->isWeak() && binding != WASM_SYMBOL_BINDING_WEAK) {
497 existing->flags = (existing->flags & ~WASM_SYMBOL_BINDING_MASK) | binding;
498 }
499 }
500
addUndefinedFunction(StringRef name,Optional<StringRef> importName,Optional<StringRef> importModule,uint32_t flags,InputFile * file,const WasmSignature * sig,bool isCalledDirectly)501 Symbol *SymbolTable::addUndefinedFunction(StringRef name,
502 Optional<StringRef> importName,
503 Optional<StringRef> importModule,
504 uint32_t flags, InputFile *file,
505 const WasmSignature *sig,
506 bool isCalledDirectly) {
507 LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " ["
508 << (sig ? toString(*sig) : "none")
509 << "] IsCalledDirectly:" << isCalledDirectly << " flags=0x"
510 << utohexstr(flags) << "\n");
511 assert(flags & WASM_SYMBOL_UNDEFINED);
512
513 Symbol *s;
514 bool wasInserted;
515 std::tie(s, wasInserted) = insert(name, file);
516 if (s->traced)
517 printTraceSymbolUndefined(name, file);
518
519 auto replaceSym = [&]() {
520 replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags,
521 file, sig, isCalledDirectly);
522 };
523
524 if (wasInserted) {
525 replaceSym();
526 } else if (auto *lazy = dyn_cast<LazySymbol>(s)) {
527 if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
528 lazy->setWeak();
529 lazy->signature = sig;
530 } else {
531 lazy->fetch();
532 }
533 } else {
534 auto existingFunction = dyn_cast<FunctionSymbol>(s);
535 if (!existingFunction) {
536 reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION);
537 return s;
538 }
539 if (!existingFunction->signature && sig)
540 existingFunction->signature = sig;
541 auto *existingUndefined = dyn_cast<UndefinedFunction>(existingFunction);
542 if (isCalledDirectly && !signatureMatches(existingFunction, sig)) {
543 // If the existing undefined functions is not called directly then let
544 // this one take precedence. Otherwise the existing function is either
545 // directly called or defined, in which case we need a function variant.
546 if (existingUndefined && !existingUndefined->isCalledDirectly)
547 replaceSym();
548 else if (getFunctionVariant(s, sig, file, &s))
549 replaceSym();
550 }
551 if (existingUndefined)
552 setImportAttributes(existingUndefined, importName, importModule, flags,
553 file);
554 }
555
556 return s;
557 }
558
addUndefinedData(StringRef name,uint32_t flags,InputFile * file)559 Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags,
560 InputFile *file) {
561 LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n");
562 assert(flags & WASM_SYMBOL_UNDEFINED);
563
564 Symbol *s;
565 bool wasInserted;
566 std::tie(s, wasInserted) = insert(name, file);
567 if (s->traced)
568 printTraceSymbolUndefined(name, file);
569
570 if (wasInserted) {
571 replaceSymbol<UndefinedData>(s, name, flags, file);
572 } else if (auto *lazy = dyn_cast<LazySymbol>(s)) {
573 if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK)
574 lazy->setWeak();
575 else
576 lazy->fetch();
577 } else if (s->isDefined()) {
578 checkDataType(s, file);
579 }
580 return s;
581 }
582
addUndefinedGlobal(StringRef name,Optional<StringRef> importName,Optional<StringRef> importModule,uint32_t flags,InputFile * file,const WasmGlobalType * type)583 Symbol *SymbolTable::addUndefinedGlobal(StringRef name,
584 Optional<StringRef> importName,
585 Optional<StringRef> importModule,
586 uint32_t flags, InputFile *file,
587 const WasmGlobalType *type) {
588 LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n");
589 assert(flags & WASM_SYMBOL_UNDEFINED);
590
591 Symbol *s;
592 bool wasInserted;
593 std::tie(s, wasInserted) = insert(name, file);
594 if (s->traced)
595 printTraceSymbolUndefined(name, file);
596
597 if (wasInserted)
598 replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags,
599 file, type);
600 else if (auto *lazy = dyn_cast<LazySymbol>(s))
601 lazy->fetch();
602 else if (s->isDefined())
603 checkGlobalType(s, file, type);
604 return s;
605 }
606
addUndefinedTable(StringRef name,Optional<StringRef> importName,Optional<StringRef> importModule,uint32_t flags,InputFile * file,const WasmTableType * type)607 Symbol *SymbolTable::addUndefinedTable(StringRef name,
608 Optional<StringRef> importName,
609 Optional<StringRef> importModule,
610 uint32_t flags, InputFile *file,
611 const WasmTableType *type) {
612 LLVM_DEBUG(dbgs() << "addUndefinedTable: " << name << "\n");
613 assert(flags & WASM_SYMBOL_UNDEFINED);
614
615 Symbol *s;
616 bool wasInserted;
617 std::tie(s, wasInserted) = insert(name, file);
618 if (s->traced)
619 printTraceSymbolUndefined(name, file);
620
621 if (wasInserted)
622 replaceSymbol<UndefinedTable>(s, name, importName, importModule, flags,
623 file, type);
624 else if (auto *lazy = dyn_cast<LazySymbol>(s))
625 lazy->fetch();
626 else if (s->isDefined())
627 checkTableType(s, file, type);
628 return s;
629 }
630
createUndefinedIndirectFunctionTable(StringRef name)631 TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) {
632 WasmLimits limits{0, 0, 0}; // Set by the writer.
633 WasmTableType *type = make<WasmTableType>();
634 type->ElemType = uint8_t(ValType::FUNCREF);
635 type->Limits = limits;
636 StringRef module(defaultModule);
637 uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN;
638 flags |= WASM_SYMBOL_UNDEFINED;
639 Symbol *sym = addUndefinedTable(name, name, module, flags, nullptr, type);
640 sym->markLive();
641 sym->forceExport = config->exportTable;
642 return cast<TableSymbol>(sym);
643 }
644
createDefinedIndirectFunctionTable(StringRef name)645 TableSymbol *SymbolTable::createDefinedIndirectFunctionTable(StringRef name) {
646 const uint32_t invalidIndex = -1;
647 WasmLimits limits{0, 0, 0}; // Set by the writer.
648 WasmTableType type{uint8_t(ValType::FUNCREF), limits};
649 WasmTable desc{invalidIndex, type, name};
650 InputTable *table = make<InputTable>(desc, nullptr);
651 uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN;
652 TableSymbol *sym = addSyntheticTable(name, flags, table);
653 sym->markLive();
654 sym->forceExport = config->exportTable;
655 return sym;
656 }
657
658 // Whether or not we need an indirect function table is usually a function of
659 // whether an input declares a need for it. However sometimes it's possible for
660 // no input to need the indirect function table, but then a late
661 // addInternalGOTEntry causes a function to be allocated an address. In that
662 // case address we synthesize a definition at the last minute.
resolveIndirectFunctionTable(bool required)663 TableSymbol *SymbolTable::resolveIndirectFunctionTable(bool required) {
664 Symbol *existing = find(functionTableName);
665 if (existing) {
666 if (!isa<TableSymbol>(existing)) {
667 error(Twine("reserved symbol must be of type table: `") +
668 functionTableName + "`");
669 return nullptr;
670 }
671 if (existing->isDefined()) {
672 error(Twine("reserved symbol must not be defined in input files: `") +
673 functionTableName + "`");
674 return nullptr;
675 }
676 }
677
678 if (config->importTable) {
679 if (existing)
680 return cast<TableSymbol>(existing);
681 if (required)
682 return createUndefinedIndirectFunctionTable(functionTableName);
683 } else if ((existing && existing->isLive()) || config->exportTable ||
684 required) {
685 // A defined table is required. Either because the user request an exported
686 // table or because the table symbol is already live. The existing table is
687 // guaranteed to be undefined due to the check above.
688 return createDefinedIndirectFunctionTable(functionTableName);
689 }
690
691 // An indirect function table will only be present in the symbol table if
692 // needed by a reloc; if we get here, we don't need one.
693 return nullptr;
694 }
695
addLazy(ArchiveFile * file,const Archive::Symbol * sym)696 void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) {
697 LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n");
698 StringRef name = sym->getName();
699
700 Symbol *s;
701 bool wasInserted;
702 std::tie(s, wasInserted) = insertName(name);
703
704 if (wasInserted) {
705 replaceSymbol<LazySymbol>(s, name, 0, file, *sym);
706 return;
707 }
708
709 if (!s->isUndefined())
710 return;
711
712 // The existing symbol is undefined, load a new one from the archive,
713 // unless the existing symbol is weak in which case replace the undefined
714 // symbols with a LazySymbol.
715 if (s->isWeak()) {
716 const WasmSignature *oldSig = nullptr;
717 // In the case of an UndefinedFunction we need to preserve the expected
718 // signature.
719 if (auto *f = dyn_cast<UndefinedFunction>(s))
720 oldSig = f->signature;
721 LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
722 auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK,
723 file, *sym);
724 newSym->signature = oldSig;
725 return;
726 }
727
728 LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
729 file->addMember(sym);
730 }
731
addComdat(StringRef name)732 bool SymbolTable::addComdat(StringRef name) {
733 return comdatGroups.insert(CachedHashStringRef(name)).second;
734 }
735
736 // The new signature doesn't match. Create a variant to the symbol with the
737 // signature encoded in the name and return that instead. These symbols are
738 // then unified later in handleSymbolVariants.
getFunctionVariant(Symbol * sym,const WasmSignature * sig,const InputFile * file,Symbol ** out)739 bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig,
740 const InputFile *file, Symbol **out) {
741 LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> "
742 << " " << toString(*sig) << "\n");
743 Symbol *variant = nullptr;
744
745 // Linear search through symbol variants. Should never be more than two
746 // or three entries here.
747 auto &variants = symVariants[CachedHashStringRef(sym->getName())];
748 if (variants.empty())
749 variants.push_back(sym);
750
751 for (Symbol* v : variants) {
752 if (*v->getSignature() == *sig) {
753 variant = v;
754 break;
755 }
756 }
757
758 bool wasAdded = !variant;
759 if (wasAdded) {
760 // Create a new variant;
761 LLVM_DEBUG(dbgs() << "added new variant\n");
762 variant = reinterpret_cast<Symbol *>(make<SymbolUnion>());
763 variant->isUsedInRegularObj =
764 !file || file->kind() == InputFile::ObjectKind;
765 variant->canInline = true;
766 variant->traced = false;
767 variant->forceExport = false;
768 variants.push_back(variant);
769 } else {
770 LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n");
771 assert(*variant->getSignature() == *sig);
772 }
773
774 *out = variant;
775 return wasAdded;
776 }
777
778 // Set a flag for --trace-symbol so that we can print out a log message
779 // if a new symbol with the same name is inserted into the symbol table.
trace(StringRef name)780 void SymbolTable::trace(StringRef name) {
781 symMap.insert({CachedHashStringRef(name), -1});
782 }
783
wrap(Symbol * sym,Symbol * real,Symbol * wrap)784 void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) {
785 // Swap symbols as instructed by -wrap.
786 int &origIdx = symMap[CachedHashStringRef(sym->getName())];
787 int &realIdx= symMap[CachedHashStringRef(real->getName())];
788 int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())];
789 LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n");
790
791 // Anyone looking up __real symbols should get the original
792 realIdx = origIdx;
793 // Anyone looking up the original should get the __wrap symbol
794 origIdx = wrapIdx;
795 }
796
797 static const uint8_t unreachableFn[] = {
798 0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
799 0x00 /* opcode unreachable */, 0x0b /* opcode end */
800 };
801
802 // Replace the given symbol body with an unreachable function.
803 // This is used by handleWeakUndefines in order to generate a callable
804 // equivalent of an undefined function and also handleSymbolVariants for
805 // undefined functions that don't match the signature of the definition.
replaceWithUnreachable(Symbol * sym,const WasmSignature & sig,StringRef debugName)806 InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym,
807 const WasmSignature &sig,
808 StringRef debugName) {
809 auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName);
810 func->setBody(unreachableFn);
811 syntheticFunctions.emplace_back(func);
812 // Mark new symbols as local. For relocatable output we don't want them
813 // to be exported outside the object file.
814 replaceSymbol<DefinedFunction>(sym, debugName, WASM_SYMBOL_BINDING_LOCAL,
815 nullptr, func);
816 // Ensure the stub function doesn't get a table entry. Its address
817 // should always compare equal to the null pointer.
818 sym->isStub = true;
819 return func;
820 }
821
replaceWithUndefined(Symbol * sym)822 void SymbolTable::replaceWithUndefined(Symbol *sym) {
823 // Add a synthetic dummy for weak undefined functions. These dummies will
824 // be GC'd if not used as the target of any "call" instructions.
825 StringRef debugName = saver.save("undefined_weak:" + toString(*sym));
826 replaceWithUnreachable(sym, *sym->getSignature(), debugName);
827 // Hide our dummy to prevent export.
828 sym->setHidden(true);
829 }
830
831 // For weak undefined functions, there may be "call" instructions that reference
832 // the symbol. In this case, we need to synthesise a dummy/stub function that
833 // will abort at runtime, so that relocations can still provided an operand to
834 // the call instruction that passes Wasm validation.
handleWeakUndefines()835 void SymbolTable::handleWeakUndefines() {
836 for (Symbol *sym : getSymbols()) {
837 if (sym->isUndefWeak()) {
838 if (sym->getSignature()) {
839 replaceWithUndefined(sym);
840 } else {
841 // It is possible for undefined functions not to have a signature (eg.
842 // if added via "--undefined"), but weak undefined ones do have a
843 // signature. Lazy symbols may not be functions and therefore Sig can
844 // still be null in some circumstance.
845 assert(!isa<FunctionSymbol>(sym));
846 }
847 }
848 }
849 }
850
createUndefinedStub(const WasmSignature & sig)851 DefinedFunction *SymbolTable::createUndefinedStub(const WasmSignature &sig) {
852 if (stubFunctions.count(sig))
853 return stubFunctions[sig];
854 LLVM_DEBUG(dbgs() << "createUndefinedStub: " << toString(sig) << "\n");
855 auto *sym = reinterpret_cast<DefinedFunction *>(make<SymbolUnion>());
856 sym->isUsedInRegularObj = true;
857 sym->canInline = true;
858 sym->traced = false;
859 sym->forceExport = false;
860 sym->signature = &sig;
861 replaceSymbol<DefinedFunction>(
862 sym, "undefined_stub", WASM_SYMBOL_VISIBILITY_HIDDEN, nullptr, nullptr);
863 replaceWithUnreachable(sym, sig, "undefined_stub");
864 stubFunctions[sig] = sym;
865 return sym;
866 }
867
reportFunctionSignatureMismatch(StringRef symName,FunctionSymbol * a,FunctionSymbol * b,bool isError)868 static void reportFunctionSignatureMismatch(StringRef symName,
869 FunctionSymbol *a,
870 FunctionSymbol *b, bool isError) {
871 std::string msg = ("function signature mismatch: " + symName +
872 "\n>>> defined as " + toString(*a->signature) + " in " +
873 toString(a->getFile()) + "\n>>> defined as " +
874 toString(*b->signature) + " in " + toString(b->getFile()))
875 .str();
876 if (isError)
877 error(msg);
878 else
879 warn(msg);
880 }
881
882 // Remove any variant symbols that were created due to function signature
883 // mismatches.
handleSymbolVariants()884 void SymbolTable::handleSymbolVariants() {
885 for (auto pair : symVariants) {
886 // Push the initial symbol onto the list of variants.
887 StringRef symName = pair.first.val();
888 std::vector<Symbol *> &variants = pair.second;
889
890 #ifndef NDEBUG
891 LLVM_DEBUG(dbgs() << "symbol with (" << variants.size()
892 << ") variants: " << symName << "\n");
893 for (auto *s: variants) {
894 auto *f = cast<FunctionSymbol>(s);
895 LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " "
896 << toString(*f->signature) << "\n");
897 }
898 #endif
899
900 // Find the one definition.
901 DefinedFunction *defined = nullptr;
902 for (auto *symbol : variants) {
903 if (auto f = dyn_cast<DefinedFunction>(symbol)) {
904 defined = f;
905 break;
906 }
907 }
908
909 // If there are no definitions, and the undefined symbols disagree on
910 // the signature, there is not we can do since we don't know which one
911 // to use as the signature on the import.
912 if (!defined) {
913 reportFunctionSignatureMismatch(symName,
914 cast<FunctionSymbol>(variants[0]),
915 cast<FunctionSymbol>(variants[1]), true);
916 return;
917 }
918
919 for (auto *symbol : variants) {
920 if (symbol != defined) {
921 auto *f = cast<FunctionSymbol>(symbol);
922 reportFunctionSignatureMismatch(symName, f, defined, false);
923 StringRef debugName = saver.save("signature_mismatch:" + toString(*f));
924 replaceWithUnreachable(f, *f->signature, debugName);
925 }
926 }
927 }
928 }
929
930 } // namespace wasm
931 } // namespace lld
932