1c94d393aSSam Clegg //===- SymbolTable.cpp ----------------------------------------------------===//
2c94d393aSSam Clegg //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c94d393aSSam Clegg //
7c94d393aSSam Clegg //===----------------------------------------------------------------------===//
8c94d393aSSam Clegg 
9c94d393aSSam Clegg #include "SymbolTable.h"
10c94d393aSSam Clegg #include "Config.h"
115fa274beSSam Clegg #include "InputChunks.h"
12e915a71fSHeejin Ahn #include "InputEvent.h"
1393102974SSam Clegg #include "InputGlobal.h"
14b8621596SSam Clegg #include "WriterUtils.h"
15c94d393aSSam Clegg #include "lld/Common/ErrorHandler.h"
162017d52bSRui Ueyama #include "lld/Common/Memory.h"
177d67dd11SRui Ueyama #include "llvm/ADT/SetVector.h"
18c94d393aSSam Clegg 
19c94d393aSSam Clegg #define DEBUG_TYPE "lld"
20c94d393aSSam Clegg 
21c94d393aSSam Clegg using namespace llvm;
2220db381bSSam Clegg using namespace llvm::wasm;
2345218f4aSSam Clegg using namespace llvm::object;
24c94d393aSSam Clegg using namespace lld;
25c94d393aSSam Clegg using namespace lld::wasm;
26c94d393aSSam Clegg 
27c94d393aSSam Clegg SymbolTable *lld::wasm::Symtab;
28c94d393aSSam Clegg 
29c94d393aSSam Clegg void SymbolTable::addFile(InputFile *File) {
30c94d393aSSam Clegg   log("Processing: " + toString(File));
311f3f774fSSam Clegg   if (Config->Trace)
321f3f774fSSam Clegg     message(toString(File));
33c94d393aSSam Clegg   File->parse();
34c94d393aSSam Clegg 
35c729c1b4SSam Clegg   // LLVM bitcode file
36c729c1b4SSam Clegg   if (auto *F = dyn_cast<BitcodeFile>(File))
37c729c1b4SSam Clegg     BitcodeFiles.push_back(F);
38c729c1b4SSam Clegg   else if (auto *F = dyn_cast<ObjFile>(File))
39c94d393aSSam Clegg     ObjectFiles.push_back(F);
40c94d393aSSam Clegg }
41c94d393aSSam Clegg 
42c729c1b4SSam Clegg // This function is where all the optimizations of link-time
43c729c1b4SSam Clegg // optimization happens. When LTO is in use, some input files are
44c729c1b4SSam Clegg // not in native object file format but in the LLVM bitcode format.
45c729c1b4SSam Clegg // This function compiles bitcode files into a few big native files
46c729c1b4SSam Clegg // using LLVM functions and replaces bitcode symbols with the results.
47c729c1b4SSam Clegg // Because all bitcode files that the program consists of are passed
48c729c1b4SSam Clegg // to the compiler at once, it can do whole-program optimization.
49c729c1b4SSam Clegg void SymbolTable::addCombinedLTOObject() {
50c729c1b4SSam Clegg   if (BitcodeFiles.empty())
51c729c1b4SSam Clegg     return;
52c729c1b4SSam Clegg 
53c729c1b4SSam Clegg   // Compile bitcode files and replace bitcode symbols.
54c729c1b4SSam Clegg   LTO.reset(new BitcodeCompiler);
55c729c1b4SSam Clegg   for (BitcodeFile *F : BitcodeFiles)
56c729c1b4SSam Clegg     LTO->add(*F);
57c729c1b4SSam Clegg 
58c729c1b4SSam Clegg   for (StringRef Filename : LTO->compile()) {
59c729c1b4SSam Clegg     auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"));
60c729c1b4SSam Clegg     Obj->parse();
61c729c1b4SSam Clegg     ObjectFiles.push_back(Obj);
62c729c1b4SSam Clegg   }
63c729c1b4SSam Clegg }
64c729c1b4SSam Clegg 
65c94d393aSSam Clegg void SymbolTable::reportRemainingUndefines() {
6674fe0ba1SSam Clegg   for (Symbol *Sym : SymVector) {
67c729c1b4SSam Clegg     if (!Sym->isUndefined() || Sym->isWeak())
68c729c1b4SSam Clegg       continue;
69c729c1b4SSam Clegg     if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
70c729c1b4SSam Clegg       continue;
71c729c1b4SSam Clegg     if (!Sym->IsUsedInRegularObj)
72c729c1b4SSam Clegg       continue;
7347e2b6b2SSam Clegg     error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym));
74c94d393aSSam Clegg   }
75c94d393aSSam Clegg }
76c94d393aSSam Clegg 
77c94d393aSSam Clegg Symbol *SymbolTable::find(StringRef Name) {
781f3f774fSSam Clegg   auto It = SymMap.find(CachedHashStringRef(Name));
791f3f774fSSam Clegg   if (It == SymMap.end() || It->second == -1)
801f3f774fSSam Clegg     return nullptr;
811f3f774fSSam Clegg   return SymVector[It->second];
821f3f774fSSam Clegg }
831f3f774fSSam Clegg 
841f3f774fSSam Clegg std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) {
851f3f774fSSam Clegg   bool Trace = false;
861f3f774fSSam Clegg   auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()});
871f3f774fSSam Clegg   int &SymIndex = P.first->second;
881f3f774fSSam Clegg   bool IsNew = P.second;
891f3f774fSSam Clegg   if (SymIndex == -1) {
901f3f774fSSam Clegg     SymIndex = SymVector.size();
911f3f774fSSam Clegg     Trace = true;
921f3f774fSSam Clegg     IsNew = true;
931f3f774fSSam Clegg   }
941f3f774fSSam Clegg 
951f3f774fSSam Clegg   if (!IsNew)
961f3f774fSSam Clegg     return {SymVector[SymIndex], false};
971f3f774fSSam Clegg 
981f3f774fSSam Clegg   Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
991f3f774fSSam Clegg   Sym->IsUsedInRegularObj = false;
1001f3f774fSSam Clegg   Sym->Traced = Trace;
1011f3f774fSSam Clegg   SymVector.emplace_back(Sym);
1021f3f774fSSam Clegg   return {Sym, true};
103c94d393aSSam Clegg }
104c94d393aSSam Clegg 
105*230dc11dSSam Clegg std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name,
106*230dc11dSSam Clegg                                               const InputFile *File) {
1071f3f774fSSam Clegg   Symbol *S;
1081f3f774fSSam Clegg   bool WasInserted;
1091f3f774fSSam Clegg   std::tie(S, WasInserted) = insertName(Name);
1101f3f774fSSam Clegg 
1114c2cbfe6SSam Clegg   if (!File || File->kind() == InputFile::ObjectKind)
1121f3f774fSSam Clegg     S->IsUsedInRegularObj = true;
1131f3f774fSSam Clegg 
1141f3f774fSSam Clegg   return {S, WasInserted};
115c94d393aSSam Clegg }
116c94d393aSSam Clegg 
117e3498ec5SRui Ueyama static void reportTypeError(const Symbol *Existing, const InputFile *File,
1183876d89aSSam Clegg                             llvm::wasm::WasmSymbolType Type) {
119e3498ec5SRui Ueyama   error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
120e3498ec5SRui Ueyama         toString(Existing->getWasmType()) + " in " +
1213876d89aSSam Clegg         toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
1223876d89aSSam Clegg         " in " + toString(File));
123e3498ec5SRui Ueyama }
124e3498ec5SRui Ueyama 
1256f4286fbSHeejin Ahn // Check the type of new symbol matches that of the symbol is replacing.
1266f4286fbSHeejin Ahn // For functions this can also involve verifying that the signatures match.
127cefbf9acSSam Clegg static void checkFunctionType(Symbol *Existing, const InputFile *File,
128e3498ec5SRui Ueyama                               const WasmSignature *NewSig) {
12965d6380cSSam Clegg   auto ExistingFunction = dyn_cast<FunctionSymbol>(Existing);
13065d6380cSSam Clegg   if (!ExistingFunction) {
1313876d89aSSam Clegg     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_FUNCTION);
132e3498ec5SRui Ueyama     return;
133e3498ec5SRui Ueyama   }
134e3498ec5SRui Ueyama 
135cefbf9acSSam Clegg   if (!NewSig)
136cefbf9acSSam Clegg     return;
137cefbf9acSSam Clegg 
138e915a71fSHeejin Ahn   const WasmSignature *OldSig = ExistingFunction->Signature;
139cefbf9acSSam Clegg   if (!OldSig) {
140e915a71fSHeejin Ahn     ExistingFunction->Signature = NewSig;
141cefbf9acSSam Clegg     return;
142cefbf9acSSam Clegg   }
143cefbf9acSSam Clegg 
144cefbf9acSSam Clegg   if (*NewSig != *OldSig)
145ffd0aaf8SSam Clegg     warn("function signature mismatch: " + Existing->getName() +
146e3498ec5SRui Ueyama          "\n>>> defined as " + toString(*OldSig) + " in " +
147e3498ec5SRui Ueyama          toString(Existing->getFile()) + "\n>>> defined as " +
148ffd0aaf8SSam Clegg          toString(*NewSig) + " in " + toString(File));
149e3498ec5SRui Ueyama }
150e3498ec5SRui Ueyama 
151e3498ec5SRui Ueyama static void checkGlobalType(const Symbol *Existing, const InputFile *File,
152e3498ec5SRui Ueyama                             const WasmGlobalType *NewType) {
153e3498ec5SRui Ueyama   if (!isa<GlobalSymbol>(Existing)) {
1543876d89aSSam Clegg     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
155b8621596SSam Clegg     return;
156b8621596SSam Clegg   }
157b8621596SSam Clegg 
158e3498ec5SRui Ueyama   const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
159e3498ec5SRui Ueyama   if (*NewType != *OldType) {
160e3498ec5SRui Ueyama     error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
161e3498ec5SRui Ueyama           toString(*OldType) + " in " + toString(Existing->getFile()) +
162e3498ec5SRui Ueyama           "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
163c94d393aSSam Clegg   }
16424b3dcd4SSam Clegg }
16524b3dcd4SSam Clegg 
166e915a71fSHeejin Ahn static void checkEventType(const Symbol *Existing, const InputFile *File,
167e915a71fSHeejin Ahn                            const WasmEventType *NewType,
168e915a71fSHeejin Ahn                            const WasmSignature *NewSig) {
169e915a71fSHeejin Ahn   auto ExistingEvent = dyn_cast<EventSymbol>(Existing);
170e915a71fSHeejin Ahn   if (!isa<EventSymbol>(Existing)) {
171e915a71fSHeejin Ahn     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT);
172e915a71fSHeejin Ahn     return;
173e915a71fSHeejin Ahn   }
174e915a71fSHeejin Ahn 
175e915a71fSHeejin Ahn   const WasmEventType *OldType = cast<EventSymbol>(Existing)->getEventType();
176e915a71fSHeejin Ahn   const WasmSignature *OldSig = ExistingEvent->Signature;
177e915a71fSHeejin Ahn   if (NewType->Attribute != OldType->Attribute)
178e915a71fSHeejin Ahn     error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " +
179e915a71fSHeejin Ahn           toString(*OldType) + " in " + toString(Existing->getFile()) +
180e915a71fSHeejin Ahn           "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
181e915a71fSHeejin Ahn   if (*NewSig != *OldSig)
182e915a71fSHeejin Ahn     warn("Event signature mismatch: " + Existing->getName() +
183e915a71fSHeejin Ahn          "\n>>> defined as " + toString(*OldSig) + " in " +
184e915a71fSHeejin Ahn          toString(Existing->getFile()) + "\n>>> defined as " +
185e915a71fSHeejin Ahn          toString(*NewSig) + " in " + toString(File));
186e915a71fSHeejin Ahn }
187e915a71fSHeejin Ahn 
188e3498ec5SRui Ueyama static void checkDataType(const Symbol *Existing, const InputFile *File) {
189e3498ec5SRui Ueyama   if (!isa<DataSymbol>(Existing))
1903876d89aSSam Clegg     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
191e3498ec5SRui Ueyama }
192e3498ec5SRui Ueyama 
193dfb0b2c7SSam Clegg DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
194ebda41f8SNicholas Wilson                                                    uint32_t Flags,
195ebda41f8SNicholas Wilson                                                    InputFunction *Function) {
196e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
197b961abc8SRui Ueyama   assert(!find(Name));
198ebda41f8SNicholas Wilson   SyntheticFunctions.emplace_back(Function);
1994c2cbfe6SSam Clegg   return replaceSymbol<DefinedFunction>(insert(Name, nullptr).first, Name,
2004c2cbfe6SSam Clegg                                         Flags, nullptr, Function);
20150686856SSam Clegg }
20250686856SSam Clegg 
20300245539SSam Clegg DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
20400245539SSam Clegg                                                  uint32_t Flags) {
205e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
206b961abc8SRui Ueyama   assert(!find(Name));
2074c2cbfe6SSam Clegg   return replaceSymbol<DefinedData>(insert(Name, nullptr).first, Name, Flags);
208c94d393aSSam Clegg }
209c94d393aSSam Clegg 
21093102974SSam Clegg DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
21193102974SSam Clegg                                                InputGlobal *Global) {
212e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
213e7245b42SNicola Zaghen                     << "\n");
214b961abc8SRui Ueyama   assert(!find(Name));
215ebda41f8SNicholas Wilson   SyntheticGlobals.emplace_back(Global);
2164c2cbfe6SSam Clegg   return replaceSymbol<DefinedGlobal>(insert(Name, nullptr).first, Name, Flags,
2174c2cbfe6SSam Clegg                                       nullptr, Global);
21893102974SSam Clegg }
21993102974SSam Clegg 
220e3498ec5SRui Ueyama static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
221e3498ec5SRui Ueyama                           uint32_t NewFlags) {
222c03c9040SRui Ueyama   // If existing symbol is undefined, replace it.
223e3498ec5SRui Ueyama   if (!Existing->isDefined()) {
224e7245b42SNicola Zaghen     LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
225e3498ec5SRui Ueyama                       << Existing->getName() << "\n");
226c03c9040SRui Ueyama     return true;
227c03c9040SRui Ueyama   }
228c03c9040SRui Ueyama 
229c03c9040SRui Ueyama   // Now we have two defined symbols. If the new one is weak, we can ignore it.
230c03c9040SRui Ueyama   if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
231e7245b42SNicola Zaghen     LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
232c03c9040SRui Ueyama     return false;
233c03c9040SRui Ueyama   }
234c03c9040SRui Ueyama 
235c03c9040SRui Ueyama   // If the existing symbol is weak, we should replace it.
236e3498ec5SRui Ueyama   if (Existing->isWeak()) {
237e7245b42SNicola Zaghen     LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
238c03c9040SRui Ueyama     return true;
239c03c9040SRui Ueyama   }
240c03c9040SRui Ueyama 
241c03c9040SRui Ueyama   // Neither symbol is week. They conflict.
242e3498ec5SRui Ueyama   error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
243e3498ec5SRui Ueyama         toString(Existing->getFile()) + "\n>>> defined in " +
244e3498ec5SRui Ueyama         toString(NewFile));
245c03c9040SRui Ueyama   return true;
246b8621596SSam Clegg }
24793e559b1SSam Clegg 
24893e559b1SSam Clegg Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
249e3498ec5SRui Ueyama                                         InputFile *File,
250e3498ec5SRui Ueyama                                         InputFunction *Function) {
2518b0b48f3SSam Clegg   LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " ["
2528b0b48f3SSam Clegg                     << (Function ? toString(Function->Signature) : "none")
2538b0b48f3SSam Clegg                     << "]\n");
25493e559b1SSam Clegg   Symbol *S;
25593e559b1SSam Clegg   bool WasInserted;
2564c2cbfe6SSam Clegg   std::tie(S, WasInserted) = insert(Name, File);
257c729c1b4SSam Clegg 
258e3498ec5SRui Ueyama   if (WasInserted || S->isLazy()) {
259e3498ec5SRui Ueyama     replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
260e3498ec5SRui Ueyama     return S;
261e3498ec5SRui Ueyama   }
262e3498ec5SRui Ueyama 
263c729c1b4SSam Clegg   if (Function)
264e3498ec5SRui Ueyama     checkFunctionType(S, File, &Function->Signature);
265e3498ec5SRui Ueyama 
2668b0b48f3SSam Clegg   if (shouldReplace(S, File, Flags)) {
2678b0b48f3SSam Clegg     // If the new defined function doesn't have signture (i.e. bitcode
26837b4ee52SSam Clegg     // functions) but the old symbol does then preserve the old signature
2698b0b48f3SSam Clegg     const WasmSignature *OldSig = nullptr;
2708b0b48f3SSam Clegg     if (auto* F = dyn_cast<FunctionSymbol>(S))
271e915a71fSHeejin Ahn       OldSig = F->Signature;
27237b4ee52SSam Clegg     if (auto *L = dyn_cast<LazySymbol>(S))
27337b4ee52SSam Clegg       OldSig = L->Signature;
2748b0b48f3SSam Clegg     auto NewSym = replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
275e915a71fSHeejin Ahn     if (!NewSym->Signature)
276e915a71fSHeejin Ahn       NewSym->Signature = OldSig;
2778b0b48f3SSam Clegg   }
27893e559b1SSam Clegg   return S;
27993e559b1SSam Clegg }
28093e559b1SSam Clegg 
28100245539SSam Clegg Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
282e3498ec5SRui Ueyama                                     InputFile *File, InputSegment *Segment,
28393102974SSam Clegg                                     uint32_t Address, uint32_t Size) {
284e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
285e7245b42SNicola Zaghen                     << "\n");
28693e559b1SSam Clegg   Symbol *S;
28793e559b1SSam Clegg   bool WasInserted;
2884c2cbfe6SSam Clegg   std::tie(S, WasInserted) = insert(Name, File);
289c729c1b4SSam Clegg 
290e3498ec5SRui Ueyama   if (WasInserted || S->isLazy()) {
291e3498ec5SRui Ueyama     replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
292e3498ec5SRui Ueyama     return S;
293e3498ec5SRui Ueyama   }
294e3498ec5SRui Ueyama 
295e3498ec5SRui Ueyama   checkDataType(S, File);
296e3498ec5SRui Ueyama 
297e3498ec5SRui Ueyama   if (shouldReplace(S, File, Flags))
298e3498ec5SRui Ueyama     replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
299c94d393aSSam Clegg   return S;
300c94d393aSSam Clegg }
301c94d393aSSam Clegg 
30293102974SSam Clegg Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
303e3498ec5SRui Ueyama                                       InputFile *File, InputGlobal *Global) {
304e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
3054c2cbfe6SSam Clegg 
30693102974SSam Clegg   Symbol *S;
30793102974SSam Clegg   bool WasInserted;
3084c2cbfe6SSam Clegg   std::tie(S, WasInserted) = insert(Name, File);
309c729c1b4SSam Clegg 
310e3498ec5SRui Ueyama   if (WasInserted || S->isLazy()) {
311e3498ec5SRui Ueyama     replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
31293102974SSam Clegg     return S;
31393102974SSam Clegg   }
31493102974SSam Clegg 
315e3498ec5SRui Ueyama   checkGlobalType(S, File, &Global->getType());
316e3498ec5SRui Ueyama 
317e3498ec5SRui Ueyama   if (shouldReplace(S, File, Flags))
318e3498ec5SRui Ueyama     replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
319e3498ec5SRui Ueyama   return S;
320e3498ec5SRui Ueyama }
321e3498ec5SRui Ueyama 
322e915a71fSHeejin Ahn Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags,
323e915a71fSHeejin Ahn                                      InputFile *File, InputEvent *Event) {
324e915a71fSHeejin Ahn   LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n");
325e915a71fSHeejin Ahn 
326e915a71fSHeejin Ahn   Symbol *S;
327e915a71fSHeejin Ahn   bool WasInserted;
328e915a71fSHeejin Ahn   std::tie(S, WasInserted) = insert(Name, File);
329e915a71fSHeejin Ahn 
330e915a71fSHeejin Ahn   if (WasInserted || S->isLazy()) {
331e915a71fSHeejin Ahn     replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
332e915a71fSHeejin Ahn     return S;
333e915a71fSHeejin Ahn   }
334e915a71fSHeejin Ahn 
335e915a71fSHeejin Ahn   checkEventType(S, File, &Event->getType(), &Event->Signature);
336e915a71fSHeejin Ahn 
337e915a71fSHeejin Ahn   if (shouldReplace(S, File, Flags))
338e915a71fSHeejin Ahn     replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
339e915a71fSHeejin Ahn   return S;
340e915a71fSHeejin Ahn }
341e915a71fSHeejin Ahn 
3429b84eeaaSDan Gohman Symbol *SymbolTable::addUndefinedFunction(StringRef Name, StringRef ImportName,
3439b84eeaaSDan Gohman                                           StringRef ImportModule,
3447cc07531SSam Clegg                                           uint32_t Flags, InputFile *File,
345e3498ec5SRui Ueyama                                           const WasmSignature *Sig) {
3468b0b48f3SSam Clegg   LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name <<
3478b0b48f3SSam Clegg              " [" << (Sig ? toString(*Sig) : "none") << "]\n");
348c03c9040SRui Ueyama 
349c94d393aSSam Clegg   Symbol *S;
350c94d393aSSam Clegg   bool WasInserted;
3514c2cbfe6SSam Clegg   std::tie(S, WasInserted) = insert(Name, File);
352c729c1b4SSam Clegg 
353e3498ec5SRui Ueyama   if (WasInserted)
3549b84eeaaSDan Gohman     replaceSymbol<UndefinedFunction>(S, Name, ImportName, ImportModule, Flags,
3559b84eeaaSDan Gohman                                      File, Sig);
356e3498ec5SRui Ueyama   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
357b961abc8SRui Ueyama     Lazy->fetch();
358cefbf9acSSam Clegg   else
359e3498ec5SRui Ueyama     checkFunctionType(S, File, Sig);
360cefbf9acSSam Clegg 
361c03c9040SRui Ueyama   return S;
362c03c9040SRui Ueyama }
363c03c9040SRui Ueyama 
364e3498ec5SRui Ueyama Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
365e3498ec5SRui Ueyama                                       InputFile *File) {
366e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
36793102974SSam Clegg 
368e3498ec5SRui Ueyama   Symbol *S;
369e3498ec5SRui Ueyama   bool WasInserted;
3704c2cbfe6SSam Clegg   std::tie(S, WasInserted) = insert(Name, File);
371f989a92dSSam Clegg 
372e3498ec5SRui Ueyama   if (WasInserted)
373e3498ec5SRui Ueyama     replaceSymbol<UndefinedData>(S, Name, Flags, File);
374e3498ec5SRui Ueyama   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
375b961abc8SRui Ueyama     Lazy->fetch();
376e3498ec5SRui Ueyama   else if (S->isDefined())
377e3498ec5SRui Ueyama     checkDataType(S, File);
378c94d393aSSam Clegg   return S;
379c94d393aSSam Clegg }
380c94d393aSSam Clegg 
3819b84eeaaSDan Gohman Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, StringRef ImportName,
3829b84eeaaSDan Gohman                                         StringRef ImportModule, uint32_t Flags,
383e3498ec5SRui Ueyama                                         InputFile *File,
384e3498ec5SRui Ueyama                                         const WasmGlobalType *Type) {
385e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
386e3498ec5SRui Ueyama 
387e3498ec5SRui Ueyama   Symbol *S;
388e3498ec5SRui Ueyama   bool WasInserted;
3894c2cbfe6SSam Clegg   std::tie(S, WasInserted) = insert(Name, File);
390c729c1b4SSam Clegg 
391e3498ec5SRui Ueyama   if (WasInserted)
3929b84eeaaSDan Gohman     replaceSymbol<UndefinedGlobal>(S, Name, ImportName, ImportModule, Flags,
3939b84eeaaSDan Gohman                                    File, Type);
394e3498ec5SRui Ueyama   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
395b961abc8SRui Ueyama     Lazy->fetch();
396e3498ec5SRui Ueyama   else if (S->isDefined())
397e3498ec5SRui Ueyama     checkGlobalType(S, File, Type);
398e3498ec5SRui Ueyama   return S;
399e3498ec5SRui Ueyama }
400e3498ec5SRui Ueyama 
401e3498ec5SRui Ueyama void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
402e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
403c94d393aSSam Clegg   StringRef Name = Sym->getName();
404c03c9040SRui Ueyama 
405c94d393aSSam Clegg   Symbol *S;
406c94d393aSSam Clegg   bool WasInserted;
4074c2cbfe6SSam Clegg   std::tie(S, WasInserted) = insert(Name, nullptr);
408c03c9040SRui Ueyama 
409c94d393aSSam Clegg   if (WasInserted) {
41037b4ee52SSam Clegg     replaceSymbol<LazySymbol>(S, Name, 0, File, *Sym);
411c03c9040SRui Ueyama     return;
412c03c9040SRui Ueyama   }
413c03c9040SRui Ueyama 
41437b4ee52SSam Clegg   if (!S->isUndefined())
41537b4ee52SSam Clegg     return;
41637b4ee52SSam Clegg 
41737b4ee52SSam Clegg   // The existing symbol is undefined, load a new one from the archive,
41837b4ee52SSam Clegg   // unless the the existing symbol is weak in which case replace the undefined
41937b4ee52SSam Clegg   // symbols with a LazySymbol.
42037b4ee52SSam Clegg   if (S->isWeak()) {
42137b4ee52SSam Clegg     const WasmSignature *OldSig = nullptr;
42237b4ee52SSam Clegg     // In the case of an UndefinedFunction we need to preserve the expected
42337b4ee52SSam Clegg     // signature.
42437b4ee52SSam Clegg     if (auto *F = dyn_cast<UndefinedFunction>(S))
42537b4ee52SSam Clegg       OldSig = F->Signature;
42637b4ee52SSam Clegg     LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
42737b4ee52SSam Clegg     auto NewSym = replaceSymbol<LazySymbol>(S, Name, WASM_SYMBOL_BINDING_WEAK,
42837b4ee52SSam Clegg                                             File, *Sym);
42937b4ee52SSam Clegg     NewSym->Signature = OldSig;
43037b4ee52SSam Clegg     return;
43137b4ee52SSam Clegg   }
43237b4ee52SSam Clegg 
433e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
434e3498ec5SRui Ueyama   File->addMember(Sym);
435c94d393aSSam Clegg }
436e0f6fcd0SSam Clegg 
437c4d9aa1bSNicholas Wilson bool SymbolTable::addComdat(StringRef Name) {
438c4d9aa1bSNicholas Wilson   return Comdats.insert(CachedHashStringRef(Name)).second;
439e0f6fcd0SSam Clegg }
4401f3f774fSSam Clegg 
4411f3f774fSSam Clegg // Set a flag for --trace-symbol so that we can print out a log message
4421f3f774fSSam Clegg // if a new symbol with the same name is inserted into the symbol table.
4431f3f774fSSam Clegg void SymbolTable::trace(StringRef Name) {
4441f3f774fSSam Clegg   SymMap.insert({CachedHashStringRef(Name), -1});
4451f3f774fSSam Clegg }
446*230dc11dSSam Clegg 
447*230dc11dSSam Clegg static const uint8_t UnreachableFn[] = {
448*230dc11dSSam Clegg     0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
449*230dc11dSSam Clegg     0x00 /* opcode unreachable */, 0x0b /* opcode end */
450*230dc11dSSam Clegg };
451*230dc11dSSam Clegg 
452*230dc11dSSam Clegg // Replace the given symbol body with an unreachable function.
453*230dc11dSSam Clegg // This is used by handleWeakUndefines in order to generate a callable
454*230dc11dSSam Clegg // equivalent of an undefined function.
455*230dc11dSSam Clegg InputFunction *SymbolTable::replaceWithUnreachable(Symbol *Sym,
456*230dc11dSSam Clegg                                                    const WasmSignature &Sig,
457*230dc11dSSam Clegg                                                    StringRef DebugName) {
458*230dc11dSSam Clegg   auto *Func = make<SyntheticFunction>(Sig, Sym->getName(), DebugName);
459*230dc11dSSam Clegg   Func->setBody(UnreachableFn);
460*230dc11dSSam Clegg   SyntheticFunctions.emplace_back(Func);
461*230dc11dSSam Clegg   replaceSymbol<DefinedFunction>(Sym, Sym->getName(), Sym->getFlags(), nullptr, Func);
462*230dc11dSSam Clegg   return Func;
463*230dc11dSSam Clegg }
464*230dc11dSSam Clegg 
465*230dc11dSSam Clegg // For weak undefined functions, there may be "call" instructions that reference
466*230dc11dSSam Clegg // the symbol. In this case, we need to synthesise a dummy/stub function that
467*230dc11dSSam Clegg // will abort at runtime, so that relocations can still provided an operand to
468*230dc11dSSam Clegg // the call instruction that passes Wasm validation.
469*230dc11dSSam Clegg void SymbolTable::handleWeakUndefines() {
470*230dc11dSSam Clegg   for (Symbol *Sym : getSymbols()) {
471*230dc11dSSam Clegg     if (!Sym->isUndefWeak())
472*230dc11dSSam Clegg       continue;
473*230dc11dSSam Clegg 
474*230dc11dSSam Clegg     const WasmSignature *Sig = nullptr;
475*230dc11dSSam Clegg 
476*230dc11dSSam Clegg     if (auto *FuncSym = dyn_cast<FunctionSymbol>(Sym)) {
477*230dc11dSSam Clegg       // It is possible for undefined functions not to have a signature (eg. if
478*230dc11dSSam Clegg       // added via "--undefined"), but weak undefined ones do have a signature.
479*230dc11dSSam Clegg       assert(FuncSym->Signature);
480*230dc11dSSam Clegg       Sig = FuncSym->Signature;
481*230dc11dSSam Clegg     } else if (auto *LazySym = dyn_cast<LazySymbol>(Sym)) {
482*230dc11dSSam Clegg       // Lazy symbols may not be functions and therefore can have a null
483*230dc11dSSam Clegg       // signature.
484*230dc11dSSam Clegg       Sig = LazySym->Signature;
485*230dc11dSSam Clegg     }
486*230dc11dSSam Clegg 
487*230dc11dSSam Clegg     if (!Sig)
488*230dc11dSSam Clegg       continue;
489*230dc11dSSam Clegg 
490*230dc11dSSam Clegg     // Add a synthetic dummy for weak undefined functions.  These dummies will
491*230dc11dSSam Clegg     // be GC'd if not used as the target of any "call" instructions.
492*230dc11dSSam Clegg     StringRef DebugName = Saver.save("undefined:" + toString(*Sym));
493*230dc11dSSam Clegg     InputFunction* Func = replaceWithUnreachable(Sym, *Sig, DebugName);
494*230dc11dSSam Clegg     // Ensure it compares equal to the null pointer, and so that table relocs
495*230dc11dSSam Clegg     // don't pull in the stub body (only call-operand relocs should do that).
496*230dc11dSSam Clegg     Func->setTableIndex(0);
497*230dc11dSSam Clegg     // Hide our dummy to prevent export.
498*230dc11dSSam Clegg     Sym->setHidden(true);
499*230dc11dSSam Clegg   }
500*230dc11dSSam Clegg }
501