xref: /openbsd-src/gnu/llvm/lld/wasm/SymbolTable.cpp (revision dfe94b169149f14cc1aee2cf6dad58a8d9a1860c)
1ece8a530Spatrick //===- SymbolTable.cpp ----------------------------------------------------===//
2ece8a530Spatrick //
3ece8a530Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ece8a530Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ece8a530Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ece8a530Spatrick //
7ece8a530Spatrick //===----------------------------------------------------------------------===//
8ece8a530Spatrick 
9ece8a530Spatrick #include "SymbolTable.h"
10ece8a530Spatrick #include "Config.h"
11ece8a530Spatrick #include "InputChunks.h"
121cf9926bSpatrick #include "InputElement.h"
13ece8a530Spatrick #include "WriterUtils.h"
14*dfe94b16Srobert #include "lld/Common/CommonLinkerContext.h"
15*dfe94b16Srobert #include <optional>
16ece8a530Spatrick 
17ece8a530Spatrick #define DEBUG_TYPE "lld"
18ece8a530Spatrick 
19ece8a530Spatrick using namespace llvm;
20ece8a530Spatrick using namespace llvm::wasm;
21ece8a530Spatrick using namespace llvm::object;
22ece8a530Spatrick 
23ece8a530Spatrick namespace lld {
24ece8a530Spatrick namespace wasm {
25ece8a530Spatrick SymbolTable *symtab;
26ece8a530Spatrick 
addFile(InputFile * file)27ece8a530Spatrick void SymbolTable::addFile(InputFile *file) {
28ece8a530Spatrick   log("Processing: " + toString(file));
29ece8a530Spatrick 
30ece8a530Spatrick   // .a file
31ece8a530Spatrick   if (auto *f = dyn_cast<ArchiveFile>(file)) {
32ece8a530Spatrick     f->parse();
33ece8a530Spatrick     return;
34ece8a530Spatrick   }
35ece8a530Spatrick 
36ece8a530Spatrick   // .so file
37ece8a530Spatrick   if (auto *f = dyn_cast<SharedFile>(file)) {
38ece8a530Spatrick     sharedFiles.push_back(f);
39ece8a530Spatrick     return;
40ece8a530Spatrick   }
41ece8a530Spatrick 
42*dfe94b16Srobert   // stub file
43*dfe94b16Srobert   if (auto *f = dyn_cast<StubFile>(file)) {
44*dfe94b16Srobert     f->parse();
45*dfe94b16Srobert     stubFiles.push_back(f);
46*dfe94b16Srobert     return;
47*dfe94b16Srobert   }
48*dfe94b16Srobert 
49ece8a530Spatrick   if (config->trace)
50ece8a530Spatrick     message(toString(file));
51ece8a530Spatrick 
52ece8a530Spatrick   // LLVM bitcode file
53ece8a530Spatrick   if (auto *f = dyn_cast<BitcodeFile>(file)) {
54ece8a530Spatrick     f->parse();
55ece8a530Spatrick     bitcodeFiles.push_back(f);
56ece8a530Spatrick     return;
57ece8a530Spatrick   }
58ece8a530Spatrick 
59ece8a530Spatrick   // Regular object file
60ece8a530Spatrick   auto *f = cast<ObjFile>(file);
61ece8a530Spatrick   f->parse(false);
62ece8a530Spatrick   objectFiles.push_back(f);
63ece8a530Spatrick }
64ece8a530Spatrick 
65ece8a530Spatrick // This function is where all the optimizations of link-time
66ece8a530Spatrick // optimization happens. When LTO is in use, some input files are
67ece8a530Spatrick // not in native object file format but in the LLVM bitcode format.
68ece8a530Spatrick // This function compiles bitcode files into a few big native files
69ece8a530Spatrick // using LLVM functions and replaces bitcode symbols with the results.
70ece8a530Spatrick // Because all bitcode files that the program consists of are passed
71ece8a530Spatrick // to the compiler at once, it can do whole-program optimization.
compileBitcodeFiles()72*dfe94b16Srobert void SymbolTable::compileBitcodeFiles() {
73bb684c34Spatrick   // Prevent further LTO objects being included
74bb684c34Spatrick   BitcodeFile::doneLTO = true;
75bb684c34Spatrick 
76ece8a530Spatrick   if (bitcodeFiles.empty())
77ece8a530Spatrick     return;
78ece8a530Spatrick 
79ece8a530Spatrick   // Compile bitcode files and replace bitcode symbols.
80ece8a530Spatrick   lto.reset(new BitcodeCompiler);
81ece8a530Spatrick   for (BitcodeFile *f : bitcodeFiles)
82ece8a530Spatrick     lto->add(*f);
83ece8a530Spatrick 
84ece8a530Spatrick   for (StringRef filename : lto->compile()) {
85ece8a530Spatrick     auto *obj = make<ObjFile>(MemoryBufferRef(filename, "lto.tmp"), "");
86ece8a530Spatrick     obj->parse(true);
87ece8a530Spatrick     objectFiles.push_back(obj);
88ece8a530Spatrick   }
89ece8a530Spatrick }
90ece8a530Spatrick 
find(StringRef name)91ece8a530Spatrick Symbol *SymbolTable::find(StringRef name) {
92ece8a530Spatrick   auto it = symMap.find(CachedHashStringRef(name));
93ece8a530Spatrick   if (it == symMap.end() || it->second == -1)
94ece8a530Spatrick     return nullptr;
95ece8a530Spatrick   return symVector[it->second];
96ece8a530Spatrick }
97ece8a530Spatrick 
replace(StringRef name,Symbol * sym)98ece8a530Spatrick void SymbolTable::replace(StringRef name, Symbol* sym) {
99ece8a530Spatrick   auto it = symMap.find(CachedHashStringRef(name));
100ece8a530Spatrick   symVector[it->second] = sym;
101ece8a530Spatrick }
102ece8a530Spatrick 
insertName(StringRef name)103ece8a530Spatrick std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) {
104ece8a530Spatrick   bool trace = false;
105ece8a530Spatrick   auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()});
106ece8a530Spatrick   int &symIndex = p.first->second;
107ece8a530Spatrick   bool isNew = p.second;
108ece8a530Spatrick   if (symIndex == -1) {
109ece8a530Spatrick     symIndex = symVector.size();
110ece8a530Spatrick     trace = true;
111ece8a530Spatrick     isNew = true;
112ece8a530Spatrick   }
113ece8a530Spatrick 
114ece8a530Spatrick   if (!isNew)
115ece8a530Spatrick     return {symVector[symIndex], false};
116ece8a530Spatrick 
117ece8a530Spatrick   Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
118ece8a530Spatrick   sym->isUsedInRegularObj = false;
119ece8a530Spatrick   sym->canInline = true;
120ece8a530Spatrick   sym->traced = trace;
121bb684c34Spatrick   sym->forceExport = false;
122*dfe94b16Srobert   sym->referenced = !config->gcSections;
123ece8a530Spatrick   symVector.emplace_back(sym);
124ece8a530Spatrick   return {sym, true};
125ece8a530Spatrick }
126ece8a530Spatrick 
insert(StringRef name,const InputFile * file)127ece8a530Spatrick std::pair<Symbol *, bool> SymbolTable::insert(StringRef name,
128ece8a530Spatrick                                               const InputFile *file) {
129ece8a530Spatrick   Symbol *s;
130ece8a530Spatrick   bool wasInserted;
131ece8a530Spatrick   std::tie(s, wasInserted) = insertName(name);
132ece8a530Spatrick 
133ece8a530Spatrick   if (!file || file->kind() == InputFile::ObjectKind)
134ece8a530Spatrick     s->isUsedInRegularObj = true;
135ece8a530Spatrick 
136ece8a530Spatrick   return {s, wasInserted};
137ece8a530Spatrick }
138ece8a530Spatrick 
reportTypeError(const Symbol * existing,const InputFile * file,llvm::wasm::WasmSymbolType type)139ece8a530Spatrick static void reportTypeError(const Symbol *existing, const InputFile *file,
140ece8a530Spatrick                             llvm::wasm::WasmSymbolType type) {
141ece8a530Spatrick   error("symbol type mismatch: " + toString(*existing) + "\n>>> defined as " +
142ece8a530Spatrick         toString(existing->getWasmType()) + " in " +
143ece8a530Spatrick         toString(existing->getFile()) + "\n>>> defined as " + toString(type) +
144ece8a530Spatrick         " in " + toString(file));
145ece8a530Spatrick }
146ece8a530Spatrick 
147ece8a530Spatrick // Check the type of new symbol matches that of the symbol is replacing.
148bb684c34Spatrick // Returns true if the function types match, false is there is a signature
149ece8a530Spatrick // mismatch.
signatureMatches(FunctionSymbol * existing,const WasmSignature * newSig)150ece8a530Spatrick static bool signatureMatches(FunctionSymbol *existing,
151ece8a530Spatrick                              const WasmSignature *newSig) {
152ece8a530Spatrick   const WasmSignature *oldSig = existing->signature;
153ece8a530Spatrick 
154*dfe94b16Srobert   // If either function is missing a signature (this happens for bitcode
155ece8a530Spatrick   // symbols) then assume they match.  Any mismatch will be reported later
156ece8a530Spatrick   // when the LTO objects are added.
157ece8a530Spatrick   if (!newSig || !oldSig)
158ece8a530Spatrick     return true;
159ece8a530Spatrick 
160ece8a530Spatrick   return *newSig == *oldSig;
161ece8a530Spatrick }
162ece8a530Spatrick 
checkGlobalType(const Symbol * existing,const InputFile * file,const WasmGlobalType * newType)163ece8a530Spatrick static void checkGlobalType(const Symbol *existing, const InputFile *file,
164ece8a530Spatrick                             const WasmGlobalType *newType) {
165ece8a530Spatrick   if (!isa<GlobalSymbol>(existing)) {
166ece8a530Spatrick     reportTypeError(existing, file, WASM_SYMBOL_TYPE_GLOBAL);
167ece8a530Spatrick     return;
168ece8a530Spatrick   }
169ece8a530Spatrick 
170ece8a530Spatrick   const WasmGlobalType *oldType = cast<GlobalSymbol>(existing)->getGlobalType();
171ece8a530Spatrick   if (*newType != *oldType) {
172ece8a530Spatrick     error("Global type mismatch: " + existing->getName() + "\n>>> defined as " +
173ece8a530Spatrick           toString(*oldType) + " in " + toString(existing->getFile()) +
174ece8a530Spatrick           "\n>>> defined as " + toString(*newType) + " in " + toString(file));
175ece8a530Spatrick   }
176ece8a530Spatrick }
177ece8a530Spatrick 
checkTagType(const Symbol * existing,const InputFile * file,const WasmSignature * newSig)1781cf9926bSpatrick static void checkTagType(const Symbol *existing, const InputFile *file,
179ece8a530Spatrick                          const WasmSignature *newSig) {
1801cf9926bSpatrick   const auto *existingTag = dyn_cast<TagSymbol>(existing);
1811cf9926bSpatrick   if (!isa<TagSymbol>(existing)) {
1821cf9926bSpatrick     reportTypeError(existing, file, WASM_SYMBOL_TYPE_TAG);
183ece8a530Spatrick     return;
184ece8a530Spatrick   }
185ece8a530Spatrick 
1861cf9926bSpatrick   const WasmSignature *oldSig = existingTag->signature;
187ece8a530Spatrick   if (*newSig != *oldSig)
1881cf9926bSpatrick     warn("Tag signature mismatch: " + existing->getName() +
189ece8a530Spatrick          "\n>>> defined as " + toString(*oldSig) + " in " +
190ece8a530Spatrick          toString(existing->getFile()) + "\n>>> defined as " +
191ece8a530Spatrick          toString(*newSig) + " in " + toString(file));
192ece8a530Spatrick }
193ece8a530Spatrick 
checkTableType(const Symbol * existing,const InputFile * file,const WasmTableType * newType)1941cf9926bSpatrick static void checkTableType(const Symbol *existing, const InputFile *file,
1951cf9926bSpatrick                            const WasmTableType *newType) {
1961cf9926bSpatrick   if (!isa<TableSymbol>(existing)) {
1971cf9926bSpatrick     reportTypeError(existing, file, WASM_SYMBOL_TYPE_TABLE);
1981cf9926bSpatrick     return;
1991cf9926bSpatrick   }
2001cf9926bSpatrick 
2011cf9926bSpatrick   const WasmTableType *oldType = cast<TableSymbol>(existing)->getTableType();
2021cf9926bSpatrick   if (newType->ElemType != oldType->ElemType) {
2031cf9926bSpatrick     error("Table type mismatch: " + existing->getName() + "\n>>> defined as " +
2041cf9926bSpatrick           toString(*oldType) + " in " + toString(existing->getFile()) +
2051cf9926bSpatrick           "\n>>> defined as " + toString(*newType) + " in " + toString(file));
2061cf9926bSpatrick   }
2071cf9926bSpatrick   // FIXME: No assertions currently on the limits.
2081cf9926bSpatrick }
2091cf9926bSpatrick 
checkDataType(const Symbol * existing,const InputFile * file)210ece8a530Spatrick static void checkDataType(const Symbol *existing, const InputFile *file) {
211ece8a530Spatrick   if (!isa<DataSymbol>(existing))
212ece8a530Spatrick     reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA);
213ece8a530Spatrick }
214ece8a530Spatrick 
addSyntheticFunction(StringRef name,uint32_t flags,InputFunction * function)215ece8a530Spatrick DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name,
216ece8a530Spatrick                                                    uint32_t flags,
217ece8a530Spatrick                                                    InputFunction *function) {
218ece8a530Spatrick   LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n");
219ece8a530Spatrick   assert(!find(name));
220ece8a530Spatrick   syntheticFunctions.emplace_back(function);
221ece8a530Spatrick   return replaceSymbol<DefinedFunction>(insertName(name).first, name,
222ece8a530Spatrick                                         flags, nullptr, function);
223ece8a530Spatrick }
224ece8a530Spatrick 
2251cf9926bSpatrick // Adds an optional, linker generated, data symbol.  The symbol will only be
226ece8a530Spatrick // added if there is an undefine reference to it, or if it is explicitly
227ece8a530Spatrick // exported via the --export flag.  Otherwise we don't add the symbol and return
228ece8a530Spatrick // nullptr.
addOptionalDataSymbol(StringRef name,uint64_t value)229ece8a530Spatrick DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name,
2301cf9926bSpatrick                                                 uint64_t value) {
231ece8a530Spatrick   Symbol *s = find(name);
232ece8a530Spatrick   if (!s && (config->exportAll || config->exportedSymbols.count(name) != 0))
233ece8a530Spatrick     s = insertName(name).first;
234ece8a530Spatrick   else if (!s || s->isDefined())
235ece8a530Spatrick     return nullptr;
236ece8a530Spatrick   LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n");
237ece8a530Spatrick   auto *rtn = replaceSymbol<DefinedData>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN);
2381cf9926bSpatrick   rtn->setVA(value);
239ece8a530Spatrick   rtn->referenced = true;
240ece8a530Spatrick   return rtn;
241ece8a530Spatrick }
242ece8a530Spatrick 
addSyntheticDataSymbol(StringRef name,uint32_t flags)243ece8a530Spatrick DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name,
244ece8a530Spatrick                                                  uint32_t flags) {
245ece8a530Spatrick   LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n");
246ece8a530Spatrick   assert(!find(name));
247ece8a530Spatrick   return replaceSymbol<DefinedData>(insertName(name).first, name, flags);
248ece8a530Spatrick }
249ece8a530Spatrick 
addSyntheticGlobal(StringRef name,uint32_t flags,InputGlobal * global)250ece8a530Spatrick DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags,
251ece8a530Spatrick                                                InputGlobal *global) {
252ece8a530Spatrick   LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global
253ece8a530Spatrick                     << "\n");
254ece8a530Spatrick   assert(!find(name));
255ece8a530Spatrick   syntheticGlobals.emplace_back(global);
256ece8a530Spatrick   return replaceSymbol<DefinedGlobal>(insertName(name).first, name, flags,
257ece8a530Spatrick                                       nullptr, global);
258ece8a530Spatrick }
259ece8a530Spatrick 
addOptionalGlobalSymbol(StringRef name,InputGlobal * global)2601cf9926bSpatrick DefinedGlobal *SymbolTable::addOptionalGlobalSymbol(StringRef name,
2611cf9926bSpatrick                                                     InputGlobal *global) {
2621cf9926bSpatrick   Symbol *s = find(name);
2631cf9926bSpatrick   if (!s || s->isDefined())
2641cf9926bSpatrick     return nullptr;
265*dfe94b16Srobert   LLVM_DEBUG(dbgs() << "addOptionalGlobalSymbol: " << name << " -> " << global
266*dfe94b16Srobert                     << "\n");
2671cf9926bSpatrick   syntheticGlobals.emplace_back(global);
2681cf9926bSpatrick   return replaceSymbol<DefinedGlobal>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN,
2691cf9926bSpatrick                                       nullptr, global);
2701cf9926bSpatrick }
2711cf9926bSpatrick 
addSyntheticTable(StringRef name,uint32_t flags,InputTable * table)2721cf9926bSpatrick DefinedTable *SymbolTable::addSyntheticTable(StringRef name, uint32_t flags,
2731cf9926bSpatrick                                              InputTable *table) {
2741cf9926bSpatrick   LLVM_DEBUG(dbgs() << "addSyntheticTable: " << name << " -> " << table
2751cf9926bSpatrick                     << "\n");
2761cf9926bSpatrick   Symbol *s = find(name);
2771cf9926bSpatrick   assert(!s || s->isUndefined());
2781cf9926bSpatrick   if (!s)
2791cf9926bSpatrick     s = insertName(name).first;
2801cf9926bSpatrick   syntheticTables.emplace_back(table);
2811cf9926bSpatrick   return replaceSymbol<DefinedTable>(s, name, flags, nullptr, table);
2821cf9926bSpatrick }
2831cf9926bSpatrick 
shouldReplace(const Symbol * existing,InputFile * newFile,uint32_t newFlags)284ece8a530Spatrick static bool shouldReplace(const Symbol *existing, InputFile *newFile,
285ece8a530Spatrick                           uint32_t newFlags) {
286ece8a530Spatrick   // If existing symbol is undefined, replace it.
287ece8a530Spatrick   if (!existing->isDefined()) {
288ece8a530Spatrick     LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
289ece8a530Spatrick                       << existing->getName() << "\n");
290ece8a530Spatrick     return true;
291ece8a530Spatrick   }
292ece8a530Spatrick 
293ece8a530Spatrick   // Now we have two defined symbols. If the new one is weak, we can ignore it.
294ece8a530Spatrick   if ((newFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
295ece8a530Spatrick     LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
296ece8a530Spatrick     return false;
297ece8a530Spatrick   }
298ece8a530Spatrick 
299ece8a530Spatrick   // If the existing symbol is weak, we should replace it.
300ece8a530Spatrick   if (existing->isWeak()) {
301ece8a530Spatrick     LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
302ece8a530Spatrick     return true;
303ece8a530Spatrick   }
304ece8a530Spatrick 
305ece8a530Spatrick   // Neither symbol is week. They conflict.
306ece8a530Spatrick   error("duplicate symbol: " + toString(*existing) + "\n>>> defined in " +
307ece8a530Spatrick         toString(existing->getFile()) + "\n>>> defined in " +
308ece8a530Spatrick         toString(newFile));
309ece8a530Spatrick   return true;
310ece8a530Spatrick }
311ece8a530Spatrick 
addDefinedFunction(StringRef name,uint32_t flags,InputFile * file,InputFunction * function)312ece8a530Spatrick Symbol *SymbolTable::addDefinedFunction(StringRef name, uint32_t flags,
313ece8a530Spatrick                                         InputFile *file,
314ece8a530Spatrick                                         InputFunction *function) {
315ece8a530Spatrick   LLVM_DEBUG(dbgs() << "addDefinedFunction: " << name << " ["
316ece8a530Spatrick                     << (function ? toString(function->signature) : "none")
317ece8a530Spatrick                     << "]\n");
318ece8a530Spatrick   Symbol *s;
319ece8a530Spatrick   bool wasInserted;
320ece8a530Spatrick   std::tie(s, wasInserted) = insert(name, file);
321ece8a530Spatrick 
322ece8a530Spatrick   auto replaceSym = [&](Symbol *sym) {
323bb684c34Spatrick     // If the new defined function doesn't have signature (i.e. bitcode
324ece8a530Spatrick     // functions) but the old symbol does, then preserve the old signature
325ece8a530Spatrick     const WasmSignature *oldSig = s->getSignature();
326ece8a530Spatrick     auto* newSym = replaceSymbol<DefinedFunction>(sym, name, flags, file, function);
327ece8a530Spatrick     if (!newSym->signature)
328ece8a530Spatrick       newSym->signature = oldSig;
329ece8a530Spatrick   };
330ece8a530Spatrick 
331ece8a530Spatrick   if (wasInserted || s->isLazy()) {
332ece8a530Spatrick     replaceSym(s);
333ece8a530Spatrick     return s;
334ece8a530Spatrick   }
335ece8a530Spatrick 
336ece8a530Spatrick   auto existingFunction = dyn_cast<FunctionSymbol>(s);
337ece8a530Spatrick   if (!existingFunction) {
338ece8a530Spatrick     reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION);
339ece8a530Spatrick     return s;
340ece8a530Spatrick   }
341ece8a530Spatrick 
342ece8a530Spatrick   bool checkSig = true;
343ece8a530Spatrick   if (auto ud = dyn_cast<UndefinedFunction>(existingFunction))
344ece8a530Spatrick     checkSig = ud->isCalledDirectly;
345ece8a530Spatrick 
346ece8a530Spatrick   if (checkSig && function && !signatureMatches(existingFunction, &function->signature)) {
347ece8a530Spatrick     Symbol* variant;
348ece8a530Spatrick     if (getFunctionVariant(s, &function->signature, file, &variant))
349ece8a530Spatrick       // New variant, always replace
350ece8a530Spatrick       replaceSym(variant);
351ece8a530Spatrick     else if (shouldReplace(s, file, flags))
352ece8a530Spatrick       // Variant already exists, replace it after checking shouldReplace
353ece8a530Spatrick       replaceSym(variant);
354ece8a530Spatrick 
355ece8a530Spatrick     // This variant we found take the place in the symbol table as the primary
356ece8a530Spatrick     // variant.
357ece8a530Spatrick     replace(name, variant);
358ece8a530Spatrick     return variant;
359ece8a530Spatrick   }
360ece8a530Spatrick 
361ece8a530Spatrick   // Existing function with matching signature.
362ece8a530Spatrick   if (shouldReplace(s, file, flags))
363ece8a530Spatrick     replaceSym(s);
364ece8a530Spatrick 
365ece8a530Spatrick   return s;
366ece8a530Spatrick }
367ece8a530Spatrick 
addDefinedData(StringRef name,uint32_t flags,InputFile * file,InputChunk * segment,uint64_t address,uint64_t size)368ece8a530Spatrick Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags,
3691cf9926bSpatrick                                     InputFile *file, InputChunk *segment,
370bb684c34Spatrick                                     uint64_t address, uint64_t size) {
371ece8a530Spatrick   LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address
372ece8a530Spatrick                     << "\n");
373ece8a530Spatrick   Symbol *s;
374ece8a530Spatrick   bool wasInserted;
375ece8a530Spatrick   std::tie(s, wasInserted) = insert(name, file);
376ece8a530Spatrick 
377ece8a530Spatrick   auto replaceSym = [&]() {
378ece8a530Spatrick     replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size);
379ece8a530Spatrick   };
380ece8a530Spatrick 
381ece8a530Spatrick   if (wasInserted || s->isLazy()) {
382ece8a530Spatrick     replaceSym();
383ece8a530Spatrick     return s;
384ece8a530Spatrick   }
385ece8a530Spatrick 
386ece8a530Spatrick   checkDataType(s, file);
387ece8a530Spatrick 
388ece8a530Spatrick   if (shouldReplace(s, file, flags))
389ece8a530Spatrick     replaceSym();
390ece8a530Spatrick   return s;
391ece8a530Spatrick }
392ece8a530Spatrick 
addDefinedGlobal(StringRef name,uint32_t flags,InputFile * file,InputGlobal * global)393ece8a530Spatrick Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags,
394ece8a530Spatrick                                       InputFile *file, InputGlobal *global) {
395ece8a530Spatrick   LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n");
396ece8a530Spatrick 
397ece8a530Spatrick   Symbol *s;
398ece8a530Spatrick   bool wasInserted;
399ece8a530Spatrick   std::tie(s, wasInserted) = insert(name, file);
400ece8a530Spatrick 
401ece8a530Spatrick   auto replaceSym = [&]() {
402ece8a530Spatrick     replaceSymbol<DefinedGlobal>(s, name, flags, file, global);
403ece8a530Spatrick   };
404ece8a530Spatrick 
405ece8a530Spatrick   if (wasInserted || s->isLazy()) {
406ece8a530Spatrick     replaceSym();
407ece8a530Spatrick     return s;
408ece8a530Spatrick   }
409ece8a530Spatrick 
410ece8a530Spatrick   checkGlobalType(s, file, &global->getType());
411ece8a530Spatrick 
412ece8a530Spatrick   if (shouldReplace(s, file, flags))
413ece8a530Spatrick     replaceSym();
414ece8a530Spatrick   return s;
415ece8a530Spatrick }
416ece8a530Spatrick 
addDefinedTag(StringRef name,uint32_t flags,InputFile * file,InputTag * tag)4171cf9926bSpatrick Symbol *SymbolTable::addDefinedTag(StringRef name, uint32_t flags,
4181cf9926bSpatrick                                    InputFile *file, InputTag *tag) {
4191cf9926bSpatrick   LLVM_DEBUG(dbgs() << "addDefinedTag:" << name << "\n");
420ece8a530Spatrick 
421ece8a530Spatrick   Symbol *s;
422ece8a530Spatrick   bool wasInserted;
423ece8a530Spatrick   std::tie(s, wasInserted) = insert(name, file);
424ece8a530Spatrick 
425ece8a530Spatrick   auto replaceSym = [&]() {
4261cf9926bSpatrick     replaceSymbol<DefinedTag>(s, name, flags, file, tag);
427ece8a530Spatrick   };
428ece8a530Spatrick 
429ece8a530Spatrick   if (wasInserted || s->isLazy()) {
430ece8a530Spatrick     replaceSym();
431ece8a530Spatrick     return s;
432ece8a530Spatrick   }
433ece8a530Spatrick 
434*dfe94b16Srobert   checkTagType(s, file, &tag->signature);
4351cf9926bSpatrick 
4361cf9926bSpatrick   if (shouldReplace(s, file, flags))
4371cf9926bSpatrick     replaceSym();
4381cf9926bSpatrick   return s;
4391cf9926bSpatrick }
4401cf9926bSpatrick 
addDefinedTable(StringRef name,uint32_t flags,InputFile * file,InputTable * table)4411cf9926bSpatrick Symbol *SymbolTable::addDefinedTable(StringRef name, uint32_t flags,
4421cf9926bSpatrick                                      InputFile *file, InputTable *table) {
4431cf9926bSpatrick   LLVM_DEBUG(dbgs() << "addDefinedTable:" << name << "\n");
4441cf9926bSpatrick 
4451cf9926bSpatrick   Symbol *s;
4461cf9926bSpatrick   bool wasInserted;
4471cf9926bSpatrick   std::tie(s, wasInserted) = insert(name, file);
4481cf9926bSpatrick 
4491cf9926bSpatrick   auto replaceSym = [&]() {
4501cf9926bSpatrick     replaceSymbol<DefinedTable>(s, name, flags, file, table);
4511cf9926bSpatrick   };
4521cf9926bSpatrick 
4531cf9926bSpatrick   if (wasInserted || s->isLazy()) {
4541cf9926bSpatrick     replaceSym();
4551cf9926bSpatrick     return s;
4561cf9926bSpatrick   }
4571cf9926bSpatrick 
4581cf9926bSpatrick   checkTableType(s, file, &table->getType());
459ece8a530Spatrick 
460ece8a530Spatrick   if (shouldReplace(s, file, flags))
461ece8a530Spatrick     replaceSym();
462ece8a530Spatrick   return s;
463ece8a530Spatrick }
464ece8a530Spatrick 
465ece8a530Spatrick // This function get called when an undefined symbol is added, and there is
466ece8a530Spatrick // already an existing one in the symbols table.  In this case we check that
467ece8a530Spatrick // custom 'import-module' and 'import-field' symbol attributes agree.
468ece8a530Spatrick // With LTO these attributes are not available when the bitcode is read and only
469ece8a530Spatrick // become available when the LTO object is read.  In this case we silently
470ece8a530Spatrick // replace the empty attributes with the valid ones.
471ece8a530Spatrick template <typename T>
setImportAttributes(T * existing,std::optional<StringRef> importName,std::optional<StringRef> importModule,uint32_t flags,InputFile * file)472*dfe94b16Srobert static void setImportAttributes(T *existing,
473*dfe94b16Srobert                                 std::optional<StringRef> importName,
474*dfe94b16Srobert                                 std::optional<StringRef> importModule,
475bb684c34Spatrick                                 uint32_t flags, InputFile *file) {
476bb684c34Spatrick   if (importName) {
477bb684c34Spatrick     if (!existing->importName)
478ece8a530Spatrick       existing->importName = importName;
479ece8a530Spatrick     if (existing->importName != importName)
480ece8a530Spatrick       error("import name mismatch for symbol: " + toString(*existing) +
481bb684c34Spatrick             "\n>>> defined as " + *existing->importName + " in " +
482bb684c34Spatrick             toString(existing->getFile()) + "\n>>> defined as " + *importName +
483ece8a530Spatrick             " in " + toString(file));
484ece8a530Spatrick   }
485ece8a530Spatrick 
486bb684c34Spatrick   if (importModule) {
487bb684c34Spatrick     if (!existing->importModule)
488ece8a530Spatrick       existing->importModule = importModule;
489ece8a530Spatrick     if (existing->importModule != importModule)
490ece8a530Spatrick       error("import module mismatch for symbol: " + toString(*existing) +
491bb684c34Spatrick             "\n>>> defined as " + *existing->importModule + " in " +
492bb684c34Spatrick             toString(existing->getFile()) + "\n>>> defined as " +
493bb684c34Spatrick             *importModule + " in " + toString(file));
494bb684c34Spatrick   }
495bb684c34Spatrick 
496bb684c34Spatrick   // Update symbol binding, if the existing symbol is weak
497bb684c34Spatrick   uint32_t binding = flags & WASM_SYMBOL_BINDING_MASK;
498bb684c34Spatrick   if (existing->isWeak() && binding != WASM_SYMBOL_BINDING_WEAK) {
499bb684c34Spatrick     existing->flags = (existing->flags & ~WASM_SYMBOL_BINDING_MASK) | binding;
500ece8a530Spatrick   }
501ece8a530Spatrick }
502ece8a530Spatrick 
addUndefinedFunction(StringRef name,std::optional<StringRef> importName,std::optional<StringRef> importModule,uint32_t flags,InputFile * file,const WasmSignature * sig,bool isCalledDirectly)503bb684c34Spatrick Symbol *SymbolTable::addUndefinedFunction(StringRef name,
504*dfe94b16Srobert                                           std::optional<StringRef> importName,
505*dfe94b16Srobert                                           std::optional<StringRef> importModule,
506ece8a530Spatrick                                           uint32_t flags, InputFile *file,
507ece8a530Spatrick                                           const WasmSignature *sig,
508ece8a530Spatrick                                           bool isCalledDirectly) {
509ece8a530Spatrick   LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " ["
510ece8a530Spatrick                     << (sig ? toString(*sig) : "none")
511bb684c34Spatrick                     << "] IsCalledDirectly:" << isCalledDirectly << " flags=0x"
512bb684c34Spatrick                     << utohexstr(flags) << "\n");
513ece8a530Spatrick   assert(flags & WASM_SYMBOL_UNDEFINED);
514ece8a530Spatrick 
515ece8a530Spatrick   Symbol *s;
516ece8a530Spatrick   bool wasInserted;
517ece8a530Spatrick   std::tie(s, wasInserted) = insert(name, file);
518ece8a530Spatrick   if (s->traced)
519ece8a530Spatrick     printTraceSymbolUndefined(name, file);
520ece8a530Spatrick 
521ece8a530Spatrick   auto replaceSym = [&]() {
522ece8a530Spatrick     replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags,
523ece8a530Spatrick                                      file, sig, isCalledDirectly);
524ece8a530Spatrick   };
525ece8a530Spatrick 
5261cf9926bSpatrick   if (wasInserted) {
527ece8a530Spatrick     replaceSym();
5281cf9926bSpatrick   } else if (auto *lazy = dyn_cast<LazySymbol>(s)) {
5291cf9926bSpatrick     if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
5301cf9926bSpatrick       lazy->setWeak();
5311cf9926bSpatrick       lazy->signature = sig;
5321cf9926bSpatrick     } else {
533ece8a530Spatrick       lazy->fetch();
534*dfe94b16Srobert       if (!config->whyExtract.empty())
535*dfe94b16Srobert         config->whyExtractRecords.emplace_back(toString(file), s->getFile(),
536*dfe94b16Srobert                                                *s);
5371cf9926bSpatrick     }
5381cf9926bSpatrick   } else {
539ece8a530Spatrick     auto existingFunction = dyn_cast<FunctionSymbol>(s);
540ece8a530Spatrick     if (!existingFunction) {
541ece8a530Spatrick       reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION);
542ece8a530Spatrick       return s;
543ece8a530Spatrick     }
544ece8a530Spatrick     if (!existingFunction->signature && sig)
545ece8a530Spatrick       existingFunction->signature = sig;
546bb684c34Spatrick     auto *existingUndefined = dyn_cast<UndefinedFunction>(existingFunction);
547ece8a530Spatrick     if (isCalledDirectly && !signatureMatches(existingFunction, sig)) {
548bb684c34Spatrick       // If the existing undefined functions is not called directly then let
549ece8a530Spatrick       // this one take precedence.  Otherwise the existing function is either
550bb684c34Spatrick       // directly called or defined, in which case we need a function variant.
551ece8a530Spatrick       if (existingUndefined && !existingUndefined->isCalledDirectly)
552ece8a530Spatrick         replaceSym();
553ece8a530Spatrick       else if (getFunctionVariant(s, sig, file, &s))
554ece8a530Spatrick         replaceSym();
555ece8a530Spatrick     }
556*dfe94b16Srobert     if (existingUndefined) {
557bb684c34Spatrick       setImportAttributes(existingUndefined, importName, importModule, flags,
558bb684c34Spatrick                           file);
559*dfe94b16Srobert       if (isCalledDirectly)
560*dfe94b16Srobert         existingUndefined->isCalledDirectly = true;
561*dfe94b16Srobert     }
562ece8a530Spatrick   }
563ece8a530Spatrick 
564ece8a530Spatrick   return s;
565ece8a530Spatrick }
566ece8a530Spatrick 
addUndefinedData(StringRef name,uint32_t flags,InputFile * file)567ece8a530Spatrick Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags,
568ece8a530Spatrick                                       InputFile *file) {
569ece8a530Spatrick   LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n");
570ece8a530Spatrick   assert(flags & WASM_SYMBOL_UNDEFINED);
571ece8a530Spatrick 
572ece8a530Spatrick   Symbol *s;
573ece8a530Spatrick   bool wasInserted;
574ece8a530Spatrick   std::tie(s, wasInserted) = insert(name, file);
575ece8a530Spatrick   if (s->traced)
576ece8a530Spatrick     printTraceSymbolUndefined(name, file);
577ece8a530Spatrick 
5781cf9926bSpatrick   if (wasInserted) {
579ece8a530Spatrick     replaceSymbol<UndefinedData>(s, name, flags, file);
5801cf9926bSpatrick   } else if (auto *lazy = dyn_cast<LazySymbol>(s)) {
5811cf9926bSpatrick     if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK)
5821cf9926bSpatrick       lazy->setWeak();
5831cf9926bSpatrick     else
584ece8a530Spatrick       lazy->fetch();
5851cf9926bSpatrick   } else if (s->isDefined()) {
586ece8a530Spatrick     checkDataType(s, file);
5871cf9926bSpatrick   }
588ece8a530Spatrick   return s;
589ece8a530Spatrick }
590ece8a530Spatrick 
addUndefinedGlobal(StringRef name,std::optional<StringRef> importName,std::optional<StringRef> importModule,uint32_t flags,InputFile * file,const WasmGlobalType * type)591bb684c34Spatrick Symbol *SymbolTable::addUndefinedGlobal(StringRef name,
592*dfe94b16Srobert                                         std::optional<StringRef> importName,
593*dfe94b16Srobert                                         std::optional<StringRef> importModule,
594bb684c34Spatrick                                         uint32_t flags, InputFile *file,
595ece8a530Spatrick                                         const WasmGlobalType *type) {
596ece8a530Spatrick   LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n");
597ece8a530Spatrick   assert(flags & WASM_SYMBOL_UNDEFINED);
598ece8a530Spatrick 
599ece8a530Spatrick   Symbol *s;
600ece8a530Spatrick   bool wasInserted;
601ece8a530Spatrick   std::tie(s, wasInserted) = insert(name, file);
602ece8a530Spatrick   if (s->traced)
603ece8a530Spatrick     printTraceSymbolUndefined(name, file);
604ece8a530Spatrick 
605ece8a530Spatrick   if (wasInserted)
606ece8a530Spatrick     replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags,
607ece8a530Spatrick                                    file, type);
608ece8a530Spatrick   else if (auto *lazy = dyn_cast<LazySymbol>(s))
609ece8a530Spatrick     lazy->fetch();
610ece8a530Spatrick   else if (s->isDefined())
611ece8a530Spatrick     checkGlobalType(s, file, type);
612ece8a530Spatrick   return s;
613ece8a530Spatrick }
614ece8a530Spatrick 
addUndefinedTable(StringRef name,std::optional<StringRef> importName,std::optional<StringRef> importModule,uint32_t flags,InputFile * file,const WasmTableType * type)6151cf9926bSpatrick Symbol *SymbolTable::addUndefinedTable(StringRef name,
616*dfe94b16Srobert                                        std::optional<StringRef> importName,
617*dfe94b16Srobert                                        std::optional<StringRef> importModule,
6181cf9926bSpatrick                                        uint32_t flags, InputFile *file,
6191cf9926bSpatrick                                        const WasmTableType *type) {
6201cf9926bSpatrick   LLVM_DEBUG(dbgs() << "addUndefinedTable: " << name << "\n");
6211cf9926bSpatrick   assert(flags & WASM_SYMBOL_UNDEFINED);
6221cf9926bSpatrick 
6231cf9926bSpatrick   Symbol *s;
6241cf9926bSpatrick   bool wasInserted;
6251cf9926bSpatrick   std::tie(s, wasInserted) = insert(name, file);
6261cf9926bSpatrick   if (s->traced)
6271cf9926bSpatrick     printTraceSymbolUndefined(name, file);
6281cf9926bSpatrick 
6291cf9926bSpatrick   if (wasInserted)
6301cf9926bSpatrick     replaceSymbol<UndefinedTable>(s, name, importName, importModule, flags,
6311cf9926bSpatrick                                   file, type);
6321cf9926bSpatrick   else if (auto *lazy = dyn_cast<LazySymbol>(s))
6331cf9926bSpatrick     lazy->fetch();
6341cf9926bSpatrick   else if (s->isDefined())
6351cf9926bSpatrick     checkTableType(s, file, type);
6361cf9926bSpatrick   return s;
6371cf9926bSpatrick }
6381cf9926bSpatrick 
addUndefinedTag(StringRef name,std::optional<StringRef> importName,std::optional<StringRef> importModule,uint32_t flags,InputFile * file,const WasmSignature * sig)639*dfe94b16Srobert Symbol *SymbolTable::addUndefinedTag(StringRef name,
640*dfe94b16Srobert                                      std::optional<StringRef> importName,
641*dfe94b16Srobert                                      std::optional<StringRef> importModule,
642*dfe94b16Srobert                                      uint32_t flags, InputFile *file,
643*dfe94b16Srobert                                      const WasmSignature *sig) {
644*dfe94b16Srobert   LLVM_DEBUG(dbgs() << "addUndefinedTag: " << name << "\n");
645*dfe94b16Srobert   assert(flags & WASM_SYMBOL_UNDEFINED);
646*dfe94b16Srobert 
647*dfe94b16Srobert   Symbol *s;
648*dfe94b16Srobert   bool wasInserted;
649*dfe94b16Srobert   std::tie(s, wasInserted) = insert(name, file);
650*dfe94b16Srobert   if (s->traced)
651*dfe94b16Srobert     printTraceSymbolUndefined(name, file);
652*dfe94b16Srobert 
653*dfe94b16Srobert   if (wasInserted)
654*dfe94b16Srobert     replaceSymbol<UndefinedTag>(s, name, importName, importModule, flags, file,
655*dfe94b16Srobert                                 sig);
656*dfe94b16Srobert   else if (auto *lazy = dyn_cast<LazySymbol>(s))
657*dfe94b16Srobert     lazy->fetch();
658*dfe94b16Srobert   else if (s->isDefined())
659*dfe94b16Srobert     checkTagType(s, file, sig);
660*dfe94b16Srobert   return s;
661*dfe94b16Srobert }
662*dfe94b16Srobert 
createUndefinedIndirectFunctionTable(StringRef name)6631cf9926bSpatrick TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) {
6641cf9926bSpatrick   WasmLimits limits{0, 0, 0}; // Set by the writer.
6651cf9926bSpatrick   WasmTableType *type = make<WasmTableType>();
6661cf9926bSpatrick   type->ElemType = uint8_t(ValType::FUNCREF);
6671cf9926bSpatrick   type->Limits = limits;
6681cf9926bSpatrick   StringRef module(defaultModule);
6691cf9926bSpatrick   uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN;
6701cf9926bSpatrick   flags |= WASM_SYMBOL_UNDEFINED;
6711cf9926bSpatrick   Symbol *sym = addUndefinedTable(name, name, module, flags, nullptr, type);
6721cf9926bSpatrick   sym->markLive();
6731cf9926bSpatrick   sym->forceExport = config->exportTable;
6741cf9926bSpatrick   return cast<TableSymbol>(sym);
6751cf9926bSpatrick }
6761cf9926bSpatrick 
createDefinedIndirectFunctionTable(StringRef name)6771cf9926bSpatrick TableSymbol *SymbolTable::createDefinedIndirectFunctionTable(StringRef name) {
6781cf9926bSpatrick   const uint32_t invalidIndex = -1;
6791cf9926bSpatrick   WasmLimits limits{0, 0, 0}; // Set by the writer.
6801cf9926bSpatrick   WasmTableType type{uint8_t(ValType::FUNCREF), limits};
6811cf9926bSpatrick   WasmTable desc{invalidIndex, type, name};
6821cf9926bSpatrick   InputTable *table = make<InputTable>(desc, nullptr);
6831cf9926bSpatrick   uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN;
6841cf9926bSpatrick   TableSymbol *sym = addSyntheticTable(name, flags, table);
6851cf9926bSpatrick   sym->markLive();
6861cf9926bSpatrick   sym->forceExport = config->exportTable;
6871cf9926bSpatrick   return sym;
6881cf9926bSpatrick }
6891cf9926bSpatrick 
6901cf9926bSpatrick // Whether or not we need an indirect function table is usually a function of
6911cf9926bSpatrick // whether an input declares a need for it.  However sometimes it's possible for
6921cf9926bSpatrick // no input to need the indirect function table, but then a late
6931cf9926bSpatrick // addInternalGOTEntry causes a function to be allocated an address.  In that
6941cf9926bSpatrick // case address we synthesize a definition at the last minute.
resolveIndirectFunctionTable(bool required)6951cf9926bSpatrick TableSymbol *SymbolTable::resolveIndirectFunctionTable(bool required) {
6961cf9926bSpatrick   Symbol *existing = find(functionTableName);
6971cf9926bSpatrick   if (existing) {
6981cf9926bSpatrick     if (!isa<TableSymbol>(existing)) {
6991cf9926bSpatrick       error(Twine("reserved symbol must be of type table: `") +
7001cf9926bSpatrick             functionTableName + "`");
7011cf9926bSpatrick       return nullptr;
7021cf9926bSpatrick     }
7031cf9926bSpatrick     if (existing->isDefined()) {
7041cf9926bSpatrick       error(Twine("reserved symbol must not be defined in input files: `") +
7051cf9926bSpatrick             functionTableName + "`");
7061cf9926bSpatrick       return nullptr;
7071cf9926bSpatrick     }
7081cf9926bSpatrick   }
7091cf9926bSpatrick 
7101cf9926bSpatrick   if (config->importTable) {
7111cf9926bSpatrick     if (existing)
7121cf9926bSpatrick       return cast<TableSymbol>(existing);
7131cf9926bSpatrick     if (required)
7141cf9926bSpatrick       return createUndefinedIndirectFunctionTable(functionTableName);
7151cf9926bSpatrick   } else if ((existing && existing->isLive()) || config->exportTable ||
7161cf9926bSpatrick              required) {
7171cf9926bSpatrick     // A defined table is required.  Either because the user request an exported
7181cf9926bSpatrick     // table or because the table symbol is already live.  The existing table is
7191cf9926bSpatrick     // guaranteed to be undefined due to the check above.
7201cf9926bSpatrick     return createDefinedIndirectFunctionTable(functionTableName);
7211cf9926bSpatrick   }
7221cf9926bSpatrick 
7231cf9926bSpatrick   // An indirect function table will only be present in the symbol table if
7241cf9926bSpatrick   // needed by a reloc; if we get here, we don't need one.
7251cf9926bSpatrick   return nullptr;
7261cf9926bSpatrick }
7271cf9926bSpatrick 
addLazy(ArchiveFile * file,const Archive::Symbol * sym)728ece8a530Spatrick void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) {
729ece8a530Spatrick   LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n");
730ece8a530Spatrick   StringRef name = sym->getName();
731ece8a530Spatrick 
732ece8a530Spatrick   Symbol *s;
733ece8a530Spatrick   bool wasInserted;
734ece8a530Spatrick   std::tie(s, wasInserted) = insertName(name);
735ece8a530Spatrick 
736ece8a530Spatrick   if (wasInserted) {
737ece8a530Spatrick     replaceSymbol<LazySymbol>(s, name, 0, file, *sym);
738ece8a530Spatrick     return;
739ece8a530Spatrick   }
740ece8a530Spatrick 
741ece8a530Spatrick   if (!s->isUndefined())
742ece8a530Spatrick     return;
743ece8a530Spatrick 
744ece8a530Spatrick   // The existing symbol is undefined, load a new one from the archive,
745ece8a530Spatrick   // unless the existing symbol is weak in which case replace the undefined
746ece8a530Spatrick   // symbols with a LazySymbol.
747ece8a530Spatrick   if (s->isWeak()) {
748ece8a530Spatrick     const WasmSignature *oldSig = nullptr;
749ece8a530Spatrick     // In the case of an UndefinedFunction we need to preserve the expected
750ece8a530Spatrick     // signature.
751ece8a530Spatrick     if (auto *f = dyn_cast<UndefinedFunction>(s))
752ece8a530Spatrick       oldSig = f->signature;
753ece8a530Spatrick     LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
754ece8a530Spatrick     auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK,
755ece8a530Spatrick                                             file, *sym);
756ece8a530Spatrick     newSym->signature = oldSig;
757ece8a530Spatrick     return;
758ece8a530Spatrick   }
759ece8a530Spatrick 
760ece8a530Spatrick   LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
761*dfe94b16Srobert   const InputFile *oldFile = s->getFile();
762ece8a530Spatrick   file->addMember(sym);
763*dfe94b16Srobert   if (!config->whyExtract.empty())
764*dfe94b16Srobert     config->whyExtractRecords.emplace_back(toString(oldFile), s->getFile(), *s);
765ece8a530Spatrick }
766ece8a530Spatrick 
addComdat(StringRef name)767ece8a530Spatrick bool SymbolTable::addComdat(StringRef name) {
768ece8a530Spatrick   return comdatGroups.insert(CachedHashStringRef(name)).second;
769ece8a530Spatrick }
770ece8a530Spatrick 
771ece8a530Spatrick // The new signature doesn't match.  Create a variant to the symbol with the
772ece8a530Spatrick // signature encoded in the name and return that instead.  These symbols are
773ece8a530Spatrick // then unified later in handleSymbolVariants.
getFunctionVariant(Symbol * sym,const WasmSignature * sig,const InputFile * file,Symbol ** out)774ece8a530Spatrick bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig,
775ece8a530Spatrick                                      const InputFile *file, Symbol **out) {
776ece8a530Spatrick   LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> "
777ece8a530Spatrick                     << " " << toString(*sig) << "\n");
778ece8a530Spatrick   Symbol *variant = nullptr;
779ece8a530Spatrick 
780ece8a530Spatrick   // Linear search through symbol variants.  Should never be more than two
781ece8a530Spatrick   // or three entries here.
782ece8a530Spatrick   auto &variants = symVariants[CachedHashStringRef(sym->getName())];
783ece8a530Spatrick   if (variants.empty())
784ece8a530Spatrick     variants.push_back(sym);
785ece8a530Spatrick 
786ece8a530Spatrick   for (Symbol* v : variants) {
787ece8a530Spatrick     if (*v->getSignature() == *sig) {
788ece8a530Spatrick       variant = v;
789ece8a530Spatrick       break;
790ece8a530Spatrick     }
791ece8a530Spatrick   }
792ece8a530Spatrick 
793ece8a530Spatrick   bool wasAdded = !variant;
794ece8a530Spatrick   if (wasAdded) {
795ece8a530Spatrick     // Create a new variant;
796ece8a530Spatrick     LLVM_DEBUG(dbgs() << "added new variant\n");
797ece8a530Spatrick     variant = reinterpret_cast<Symbol *>(make<SymbolUnion>());
798bb684c34Spatrick     variant->isUsedInRegularObj =
799bb684c34Spatrick         !file || file->kind() == InputFile::ObjectKind;
800bb684c34Spatrick     variant->canInline = true;
801bb684c34Spatrick     variant->traced = false;
802bb684c34Spatrick     variant->forceExport = false;
803ece8a530Spatrick     variants.push_back(variant);
804ece8a530Spatrick   } else {
805ece8a530Spatrick     LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n");
806ece8a530Spatrick     assert(*variant->getSignature() == *sig);
807ece8a530Spatrick   }
808ece8a530Spatrick 
809ece8a530Spatrick   *out = variant;
810ece8a530Spatrick   return wasAdded;
811ece8a530Spatrick }
812ece8a530Spatrick 
813ece8a530Spatrick // Set a flag for --trace-symbol so that we can print out a log message
814ece8a530Spatrick // if a new symbol with the same name is inserted into the symbol table.
trace(StringRef name)815ece8a530Spatrick void SymbolTable::trace(StringRef name) {
816ece8a530Spatrick   symMap.insert({CachedHashStringRef(name), -1});
817ece8a530Spatrick }
818ece8a530Spatrick 
wrap(Symbol * sym,Symbol * real,Symbol * wrap)819ece8a530Spatrick void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) {
820ece8a530Spatrick   // Swap symbols as instructed by -wrap.
821ece8a530Spatrick   int &origIdx = symMap[CachedHashStringRef(sym->getName())];
822ece8a530Spatrick   int &realIdx= symMap[CachedHashStringRef(real->getName())];
823ece8a530Spatrick   int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())];
824ece8a530Spatrick   LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n");
825ece8a530Spatrick 
826ece8a530Spatrick   // Anyone looking up __real symbols should get the original
827ece8a530Spatrick   realIdx = origIdx;
828ece8a530Spatrick   // Anyone looking up the original should get the __wrap symbol
829ece8a530Spatrick   origIdx = wrapIdx;
830ece8a530Spatrick }
831ece8a530Spatrick 
832ece8a530Spatrick static const uint8_t unreachableFn[] = {
833ece8a530Spatrick     0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
834ece8a530Spatrick     0x00 /* opcode unreachable */, 0x0b /* opcode end */
835ece8a530Spatrick };
836ece8a530Spatrick 
837ece8a530Spatrick // Replace the given symbol body with an unreachable function.
838ece8a530Spatrick // This is used by handleWeakUndefines in order to generate a callable
839ece8a530Spatrick // equivalent of an undefined function and also handleSymbolVariants for
840ece8a530Spatrick // undefined functions that don't match the signature of the definition.
replaceWithUnreachable(Symbol * sym,const WasmSignature & sig,StringRef debugName)841ece8a530Spatrick InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym,
842ece8a530Spatrick                                                    const WasmSignature &sig,
843ece8a530Spatrick                                                    StringRef debugName) {
844ece8a530Spatrick   auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName);
845ece8a530Spatrick   func->setBody(unreachableFn);
846ece8a530Spatrick   syntheticFunctions.emplace_back(func);
847bb684c34Spatrick   // Mark new symbols as local. For relocatable output we don't want them
848bb684c34Spatrick   // to be exported outside the object file.
849bb684c34Spatrick   replaceSymbol<DefinedFunction>(sym, debugName, WASM_SYMBOL_BINDING_LOCAL,
850bb684c34Spatrick                                  nullptr, func);
8511cf9926bSpatrick   // Ensure the stub function doesn't get a table entry.  Its address
8521cf9926bSpatrick   // should always compare equal to the null pointer.
8531cf9926bSpatrick   sym->isStub = true;
854ece8a530Spatrick   return func;
855ece8a530Spatrick }
856ece8a530Spatrick 
replaceWithUndefined(Symbol * sym)8571cf9926bSpatrick void SymbolTable::replaceWithUndefined(Symbol *sym) {
8581cf9926bSpatrick   // Add a synthetic dummy for weak undefined functions.  These dummies will
8591cf9926bSpatrick   // be GC'd if not used as the target of any "call" instructions.
860*dfe94b16Srobert   StringRef debugName = saver().save("undefined_weak:" + toString(*sym));
8611cf9926bSpatrick   replaceWithUnreachable(sym, *sym->getSignature(), debugName);
8621cf9926bSpatrick   // Hide our dummy to prevent export.
8631cf9926bSpatrick   sym->setHidden(true);
8641cf9926bSpatrick }
8651cf9926bSpatrick 
866ece8a530Spatrick // For weak undefined functions, there may be "call" instructions that reference
867ece8a530Spatrick // the symbol. In this case, we need to synthesise a dummy/stub function that
868ece8a530Spatrick // will abort at runtime, so that relocations can still provided an operand to
869ece8a530Spatrick // the call instruction that passes Wasm validation.
handleWeakUndefines()870ece8a530Spatrick void SymbolTable::handleWeakUndefines() {
871*dfe94b16Srobert   for (Symbol *sym : symbols()) {
872*dfe94b16Srobert     if (sym->isUndefWeak() && sym->isUsedInRegularObj) {
8731cf9926bSpatrick       if (sym->getSignature()) {
8741cf9926bSpatrick         replaceWithUndefined(sym);
8751cf9926bSpatrick       } else {
8761cf9926bSpatrick         // It is possible for undefined functions not to have a signature (eg.
8771cf9926bSpatrick         // if added via "--undefined"), but weak undefined ones do have a
8781cf9926bSpatrick         // signature.  Lazy symbols may not be functions and therefore Sig can
8791cf9926bSpatrick         // still be null in some circumstance.
880ece8a530Spatrick         assert(!isa<FunctionSymbol>(sym));
8811cf9926bSpatrick       }
8821cf9926bSpatrick     }
8831cf9926bSpatrick   }
884ece8a530Spatrick }
885ece8a530Spatrick 
createUndefinedStub(const WasmSignature & sig)8861cf9926bSpatrick DefinedFunction *SymbolTable::createUndefinedStub(const WasmSignature &sig) {
8871cf9926bSpatrick   if (stubFunctions.count(sig))
8881cf9926bSpatrick     return stubFunctions[sig];
8891cf9926bSpatrick   LLVM_DEBUG(dbgs() << "createUndefinedStub: " << toString(sig) << "\n");
8901cf9926bSpatrick   auto *sym = reinterpret_cast<DefinedFunction *>(make<SymbolUnion>());
8911cf9926bSpatrick   sym->isUsedInRegularObj = true;
8921cf9926bSpatrick   sym->canInline = true;
8931cf9926bSpatrick   sym->traced = false;
8941cf9926bSpatrick   sym->forceExport = false;
8951cf9926bSpatrick   sym->signature = &sig;
8961cf9926bSpatrick   replaceSymbol<DefinedFunction>(
8971cf9926bSpatrick       sym, "undefined_stub", WASM_SYMBOL_VISIBILITY_HIDDEN, nullptr, nullptr);
8981cf9926bSpatrick   replaceWithUnreachable(sym, sig, "undefined_stub");
8991cf9926bSpatrick   stubFunctions[sig] = sym;
9001cf9926bSpatrick   return sym;
901ece8a530Spatrick }
902ece8a530Spatrick 
reportFunctionSignatureMismatch(StringRef symName,FunctionSymbol * a,FunctionSymbol * b,bool isError)903ece8a530Spatrick static void reportFunctionSignatureMismatch(StringRef symName,
904ece8a530Spatrick                                             FunctionSymbol *a,
905ece8a530Spatrick                                             FunctionSymbol *b, bool isError) {
906ece8a530Spatrick   std::string msg = ("function signature mismatch: " + symName +
907ece8a530Spatrick                      "\n>>> defined as " + toString(*a->signature) + " in " +
908ece8a530Spatrick                      toString(a->getFile()) + "\n>>> defined as " +
909ece8a530Spatrick                      toString(*b->signature) + " in " + toString(b->getFile()))
910ece8a530Spatrick                         .str();
911ece8a530Spatrick   if (isError)
912ece8a530Spatrick     error(msg);
913ece8a530Spatrick   else
914ece8a530Spatrick     warn(msg);
915ece8a530Spatrick }
916ece8a530Spatrick 
917ece8a530Spatrick // Remove any variant symbols that were created due to function signature
918ece8a530Spatrick // mismatches.
handleSymbolVariants()919ece8a530Spatrick void SymbolTable::handleSymbolVariants() {
920ece8a530Spatrick   for (auto pair : symVariants) {
921ece8a530Spatrick     // Push the initial symbol onto the list of variants.
922ece8a530Spatrick     StringRef symName = pair.first.val();
923ece8a530Spatrick     std::vector<Symbol *> &variants = pair.second;
924ece8a530Spatrick 
925ece8a530Spatrick #ifndef NDEBUG
926ece8a530Spatrick     LLVM_DEBUG(dbgs() << "symbol with (" << variants.size()
927ece8a530Spatrick                       << ") variants: " << symName << "\n");
928ece8a530Spatrick     for (auto *s: variants) {
929ece8a530Spatrick       auto *f = cast<FunctionSymbol>(s);
930ece8a530Spatrick       LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " "
931ece8a530Spatrick                         << toString(*f->signature) << "\n");
932ece8a530Spatrick     }
933ece8a530Spatrick #endif
934ece8a530Spatrick 
935ece8a530Spatrick     // Find the one definition.
936ece8a530Spatrick     DefinedFunction *defined = nullptr;
937ece8a530Spatrick     for (auto *symbol : variants) {
938ece8a530Spatrick       if (auto f = dyn_cast<DefinedFunction>(symbol)) {
939ece8a530Spatrick         defined = f;
940ece8a530Spatrick         break;
941ece8a530Spatrick       }
942ece8a530Spatrick     }
943ece8a530Spatrick 
944ece8a530Spatrick     // If there are no definitions, and the undefined symbols disagree on
945ece8a530Spatrick     // the signature, there is not we can do since we don't know which one
946ece8a530Spatrick     // to use as the signature on the import.
947ece8a530Spatrick     if (!defined) {
948ece8a530Spatrick       reportFunctionSignatureMismatch(symName,
949ece8a530Spatrick                                       cast<FunctionSymbol>(variants[0]),
950ece8a530Spatrick                                       cast<FunctionSymbol>(variants[1]), true);
951ece8a530Spatrick       return;
952ece8a530Spatrick     }
953ece8a530Spatrick 
954ece8a530Spatrick     for (auto *symbol : variants) {
955ece8a530Spatrick       if (symbol != defined) {
956ece8a530Spatrick         auto *f = cast<FunctionSymbol>(symbol);
957ece8a530Spatrick         reportFunctionSignatureMismatch(symName, f, defined, false);
958*dfe94b16Srobert         StringRef debugName =
959*dfe94b16Srobert             saver().save("signature_mismatch:" + toString(*f));
960ece8a530Spatrick         replaceWithUnreachable(f, *f->signature, debugName);
961ece8a530Spatrick       }
962ece8a530Spatrick     }
963ece8a530Spatrick   }
964ece8a530Spatrick }
965ece8a530Spatrick 
966ece8a530Spatrick } // namespace wasm
967ece8a530Spatrick } // namespace lld
968