1c94d393aSSam Clegg //===- SymbolTable.cpp ----------------------------------------------------===//
2c94d393aSSam Clegg //
3c94d393aSSam Clegg //                             The LLVM Linker
4c94d393aSSam Clegg //
5c94d393aSSam Clegg // This file is distributed under the University of Illinois Open Source
6c94d393aSSam Clegg // License. See LICENSE.TXT for details.
7c94d393aSSam Clegg //
8c94d393aSSam Clegg //===----------------------------------------------------------------------===//
9c94d393aSSam Clegg 
10c94d393aSSam Clegg #include "SymbolTable.h"
11c94d393aSSam Clegg #include "Config.h"
125fa274beSSam Clegg #include "InputChunks.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;
23c94d393aSSam Clegg using namespace lld;
24c94d393aSSam Clegg using namespace lld::wasm;
25c94d393aSSam Clegg 
26c94d393aSSam Clegg SymbolTable *lld::wasm::Symtab;
27c94d393aSSam Clegg 
28c94d393aSSam Clegg void SymbolTable::addFile(InputFile *File) {
29c94d393aSSam Clegg   log("Processing: " + toString(File));
30c94d393aSSam Clegg   File->parse();
31c94d393aSSam Clegg 
32c94d393aSSam Clegg   if (auto *F = dyn_cast<ObjFile>(File))
33c94d393aSSam Clegg     ObjectFiles.push_back(F);
34c94d393aSSam Clegg }
35c94d393aSSam Clegg 
36c94d393aSSam Clegg void SymbolTable::reportRemainingUndefines() {
377d67dd11SRui Ueyama   SetVector<Symbol *> Undefs;
3874fe0ba1SSam Clegg   for (Symbol *Sym : SymVector) {
39c94d393aSSam Clegg     if (Sym->isUndefined() && !Sym->isWeak() &&
40c94d393aSSam Clegg         Config->AllowUndefinedSymbols.count(Sym->getName()) == 0) {
41c94d393aSSam Clegg       Undefs.insert(Sym);
42c94d393aSSam Clegg     }
43c94d393aSSam Clegg   }
44c94d393aSSam Clegg 
45c94d393aSSam Clegg   if (Undefs.empty())
46c94d393aSSam Clegg     return;
47c94d393aSSam Clegg 
48c94d393aSSam Clegg   for (ObjFile *File : ObjectFiles)
49c94d393aSSam Clegg     for (Symbol *Sym : File->getSymbols())
50c94d393aSSam Clegg       if (Undefs.count(Sym))
51c94d393aSSam Clegg         error(toString(File) + ": undefined symbol: " + toString(*Sym));
52c94d393aSSam Clegg 
53c94d393aSSam Clegg   for (Symbol *Sym : Undefs)
54c94d393aSSam Clegg     if (!Sym->getFile())
55c94d393aSSam Clegg       error("undefined symbol: " + toString(*Sym));
56c94d393aSSam Clegg }
57c94d393aSSam Clegg 
58c94d393aSSam Clegg Symbol *SymbolTable::find(StringRef Name) {
59a80d94d5SSam Clegg   auto It = SymMap.find(CachedHashStringRef(Name));
60a80d94d5SSam Clegg   if (It == SymMap.end())
61c94d393aSSam Clegg     return nullptr;
62c94d393aSSam Clegg   return It->second;
63c94d393aSSam Clegg }
64c94d393aSSam Clegg 
65c94d393aSSam Clegg std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
66a80d94d5SSam Clegg   Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
67c94d393aSSam Clegg   if (Sym)
68c94d393aSSam Clegg     return {Sym, false};
69dfb0b2c7SSam Clegg   Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
7074fe0ba1SSam Clegg   SymVector.emplace_back(Sym);
71c94d393aSSam Clegg   return {Sym, true};
72c94d393aSSam Clegg }
73c94d393aSSam Clegg 
74*e3498ec5SRui Ueyama static void reportTypeError(const Symbol *Existing, const InputFile *File,
75*e3498ec5SRui Ueyama                             StringRef Type) {
76*e3498ec5SRui Ueyama   error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
77*e3498ec5SRui Ueyama         toString(Existing->getWasmType()) + " in " +
78*e3498ec5SRui Ueyama         toString(Existing->getFile()) + "\n>>> defined as " + Type + " in " +
79*e3498ec5SRui Ueyama         toString(File));
80*e3498ec5SRui Ueyama }
81*e3498ec5SRui Ueyama 
82*e3498ec5SRui Ueyama static void checkFunctionType(const Symbol *Existing, const InputFile *File,
83*e3498ec5SRui Ueyama                               const WasmSignature *NewSig) {
84*e3498ec5SRui Ueyama   if (!isa<FunctionSymbol>(Existing)) {
85*e3498ec5SRui Ueyama     reportTypeError(Existing, File, "Function");
86*e3498ec5SRui Ueyama     return;
87*e3498ec5SRui Ueyama   }
88*e3498ec5SRui Ueyama 
89*e3498ec5SRui Ueyama   if (!Config->CheckSignatures)
90*e3498ec5SRui Ueyama     return;
91*e3498ec5SRui Ueyama 
92*e3498ec5SRui Ueyama   const WasmSignature *OldSig =
93*e3498ec5SRui Ueyama       cast<FunctionSymbol>(Existing)->getFunctionType();
94*e3498ec5SRui Ueyama   if (OldSig && *NewSig != *OldSig) {
95*e3498ec5SRui Ueyama     error("Function type mismatch: " + Existing->getName() +
96*e3498ec5SRui Ueyama           "\n>>> defined as " + toString(*OldSig) + " in " +
97*e3498ec5SRui Ueyama           toString(Existing->getFile()) + "\n>>> defined as " +
98*e3498ec5SRui Ueyama           toString(*NewSig) + " in " + toString(File));
99*e3498ec5SRui Ueyama   }
100*e3498ec5SRui Ueyama }
101*e3498ec5SRui Ueyama 
102b8621596SSam Clegg // Check the type of new symbol matches that of the symbol is replacing.
103b8621596SSam Clegg // For functions this can also involve verifying that the signatures match.
104*e3498ec5SRui Ueyama static void checkGlobalType(const Symbol *Existing, const InputFile *File,
105*e3498ec5SRui Ueyama                             const WasmGlobalType *NewType) {
106*e3498ec5SRui Ueyama   if (!isa<GlobalSymbol>(Existing)) {
107*e3498ec5SRui Ueyama     reportTypeError(Existing, File, "Global");
108b8621596SSam Clegg     return;
109b8621596SSam Clegg   }
110b8621596SSam Clegg 
111*e3498ec5SRui Ueyama   const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
112*e3498ec5SRui Ueyama   if (*NewType != *OldType) {
113*e3498ec5SRui Ueyama     error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
114*e3498ec5SRui Ueyama           toString(*OldType) + " in " + toString(Existing->getFile()) +
115*e3498ec5SRui Ueyama           "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
116c94d393aSSam Clegg   }
11724b3dcd4SSam Clegg }
11824b3dcd4SSam Clegg 
119*e3498ec5SRui Ueyama static void checkDataType(const Symbol *Existing, const InputFile *File) {
120*e3498ec5SRui Ueyama   if (!isa<DataSymbol>(Existing))
121*e3498ec5SRui Ueyama     reportTypeError(Existing, File, "Data");
122*e3498ec5SRui Ueyama }
123*e3498ec5SRui Ueyama 
124dfb0b2c7SSam Clegg DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
12550686856SSam Clegg                                                    const WasmSignature *Type,
12650686856SSam Clegg                                                    uint32_t Flags) {
127a189230bSSam Clegg   DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
12850686856SSam Clegg   Symbol *S;
12950686856SSam Clegg   bool WasInserted;
13050686856SSam Clegg   std::tie(S, WasInserted) = insert(Name);
131a189230bSSam Clegg   assert(WasInserted);
132dfb0b2c7SSam Clegg   return replaceSymbol<DefinedFunction>(S, Name, Flags, Type);
13350686856SSam Clegg }
13450686856SSam Clegg 
13500245539SSam Clegg DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
13600245539SSam Clegg                                                  uint32_t Flags) {
13700245539SSam Clegg   DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
138c94d393aSSam Clegg   Symbol *S;
139c94d393aSSam Clegg   bool WasInserted;
140c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
141a189230bSSam Clegg   assert(WasInserted);
14200245539SSam Clegg   return replaceSymbol<DefinedData>(S, Name, Flags);
143c94d393aSSam Clegg }
144c94d393aSSam Clegg 
14593102974SSam Clegg DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
14693102974SSam Clegg                                                InputGlobal *Global) {
14793102974SSam Clegg   DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global << "\n");
14893102974SSam Clegg   Symbol *S;
14993102974SSam Clegg   bool WasInserted;
15093102974SSam Clegg   std::tie(S, WasInserted) = insert(Name);
15193102974SSam Clegg   assert(WasInserted);
15293102974SSam Clegg   return replaceSymbol<DefinedGlobal>(S, Name, Flags, nullptr, Global);
15393102974SSam Clegg }
15493102974SSam Clegg 
155*e3498ec5SRui Ueyama static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
156*e3498ec5SRui Ueyama                           uint32_t NewFlags) {
157c03c9040SRui Ueyama   // If existing symbol is undefined, replace it.
158*e3498ec5SRui Ueyama   if (!Existing->isDefined()) {
159c03c9040SRui Ueyama     DEBUG(dbgs() << "resolving existing undefined symbol: "
160*e3498ec5SRui Ueyama                  << Existing->getName() << "\n");
161c03c9040SRui Ueyama     return true;
162c03c9040SRui Ueyama   }
163c03c9040SRui Ueyama 
164c03c9040SRui Ueyama   // Now we have two defined symbols. If the new one is weak, we can ignore it.
165c03c9040SRui Ueyama   if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
166c03c9040SRui Ueyama     DEBUG(dbgs() << "existing symbol takes precedence\n");
167c03c9040SRui Ueyama     return false;
168c03c9040SRui Ueyama   }
169c03c9040SRui Ueyama 
170c03c9040SRui Ueyama   // If the existing symbol is weak, we should replace it.
171*e3498ec5SRui Ueyama   if (Existing->isWeak()) {
172c03c9040SRui Ueyama     DEBUG(dbgs() << "replacing existing weak symbol\n");
173c03c9040SRui Ueyama     return true;
174c03c9040SRui Ueyama   }
175c03c9040SRui Ueyama 
176c03c9040SRui Ueyama   // Neither symbol is week. They conflict.
177*e3498ec5SRui Ueyama   error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
178*e3498ec5SRui Ueyama         toString(Existing->getFile()) + "\n>>> defined in " +
179*e3498ec5SRui Ueyama         toString(NewFile));
180c03c9040SRui Ueyama   return true;
181b8621596SSam Clegg }
18293e559b1SSam Clegg 
18393e559b1SSam Clegg Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
184*e3498ec5SRui Ueyama                                         InputFile *File,
185*e3498ec5SRui Ueyama                                         InputFunction *Function) {
18693e559b1SSam Clegg   DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n");
18793e559b1SSam Clegg   Symbol *S;
18893e559b1SSam Clegg   bool WasInserted;
18993e559b1SSam Clegg   std::tie(S, WasInserted) = insert(Name);
190*e3498ec5SRui Ueyama 
191*e3498ec5SRui Ueyama   if (WasInserted || S->isLazy()) {
192*e3498ec5SRui Ueyama     replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
193*e3498ec5SRui Ueyama     return S;
194*e3498ec5SRui Ueyama   }
195*e3498ec5SRui Ueyama 
196*e3498ec5SRui Ueyama   checkFunctionType(S, File, &Function->Signature);
197*e3498ec5SRui Ueyama 
198*e3498ec5SRui Ueyama   if (shouldReplace(S, File, Flags))
199*e3498ec5SRui Ueyama     replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
20093e559b1SSam Clegg   return S;
20193e559b1SSam Clegg }
20293e559b1SSam Clegg 
20300245539SSam Clegg Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
204*e3498ec5SRui Ueyama                                     InputFile *File, InputSegment *Segment,
20593102974SSam Clegg                                     uint32_t Address, uint32_t Size) {
20600245539SSam Clegg   DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address << "\n");
20793e559b1SSam Clegg   Symbol *S;
20893e559b1SSam Clegg   bool WasInserted;
20993e559b1SSam Clegg   std::tie(S, WasInserted) = insert(Name);
210*e3498ec5SRui Ueyama 
211*e3498ec5SRui Ueyama   if (WasInserted || S->isLazy()) {
212*e3498ec5SRui Ueyama     replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
213*e3498ec5SRui Ueyama     return S;
214*e3498ec5SRui Ueyama   }
215*e3498ec5SRui Ueyama 
216*e3498ec5SRui Ueyama   checkDataType(S, File);
217*e3498ec5SRui Ueyama 
218*e3498ec5SRui Ueyama   if (shouldReplace(S, File, Flags))
219*e3498ec5SRui Ueyama     replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
220c94d393aSSam Clegg   return S;
221c94d393aSSam Clegg }
222c94d393aSSam Clegg 
22393102974SSam Clegg Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
224*e3498ec5SRui Ueyama                                       InputFile *File, InputGlobal *Global) {
22593102974SSam Clegg   DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
22693102974SSam Clegg   Symbol *S;
22793102974SSam Clegg   bool WasInserted;
22893102974SSam Clegg   std::tie(S, WasInserted) = insert(Name);
229*e3498ec5SRui Ueyama 
230*e3498ec5SRui Ueyama   if (WasInserted || S->isLazy()) {
231*e3498ec5SRui Ueyama     replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
23293102974SSam Clegg     return S;
23393102974SSam Clegg   }
23493102974SSam Clegg 
235*e3498ec5SRui Ueyama   checkGlobalType(S, File, &Global->getType());
236*e3498ec5SRui Ueyama 
237*e3498ec5SRui Ueyama   if (shouldReplace(S, File, Flags))
238*e3498ec5SRui Ueyama     replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
239*e3498ec5SRui Ueyama   return S;
240*e3498ec5SRui Ueyama }
241*e3498ec5SRui Ueyama 
242*e3498ec5SRui Ueyama Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags,
243*e3498ec5SRui Ueyama                                           InputFile *File,
244*e3498ec5SRui Ueyama                                           const WasmSignature *Sig) {
245*e3498ec5SRui Ueyama   DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n");
246c03c9040SRui Ueyama 
247c94d393aSSam Clegg   Symbol *S;
248c94d393aSSam Clegg   bool WasInserted;
24920db381bSSam Clegg   std::tie(S, WasInserted) = insert(Name);
250c03c9040SRui Ueyama 
251*e3498ec5SRui Ueyama   if (WasInserted)
252*e3498ec5SRui Ueyama     replaceSymbol<UndefinedFunction>(S, Name, Flags, File, Sig);
253*e3498ec5SRui Ueyama   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
254c03c9040SRui Ueyama     cast<ArchiveFile>(Lazy->getFile())->addMember(&Lazy->getArchiveSymbol());
255*e3498ec5SRui Ueyama   else if (S->isDefined())
256*e3498ec5SRui Ueyama     checkFunctionType(S, File, Sig);
257c03c9040SRui Ueyama   return S;
258c03c9040SRui Ueyama }
259c03c9040SRui Ueyama 
260*e3498ec5SRui Ueyama Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
261*e3498ec5SRui Ueyama                                       InputFile *File) {
262*e3498ec5SRui Ueyama   DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
26393102974SSam Clegg 
264*e3498ec5SRui Ueyama   Symbol *S;
265*e3498ec5SRui Ueyama   bool WasInserted;
266*e3498ec5SRui Ueyama   std::tie(S, WasInserted) = insert(Name);
267*e3498ec5SRui Ueyama 
268*e3498ec5SRui Ueyama   if (WasInserted)
269*e3498ec5SRui Ueyama     replaceSymbol<UndefinedData>(S, Name, Flags, File);
270*e3498ec5SRui Ueyama   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
271*e3498ec5SRui Ueyama     cast<ArchiveFile>(Lazy->getFile())->addMember(&Lazy->getArchiveSymbol());
272*e3498ec5SRui Ueyama   else if (S->isDefined())
273*e3498ec5SRui Ueyama     checkDataType(S, File);
274c94d393aSSam Clegg   return S;
275c94d393aSSam Clegg }
276c94d393aSSam Clegg 
277*e3498ec5SRui Ueyama Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, uint32_t Flags,
278*e3498ec5SRui Ueyama                                         InputFile *File,
279*e3498ec5SRui Ueyama                                         const WasmGlobalType *Type) {
280*e3498ec5SRui Ueyama   DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
281*e3498ec5SRui Ueyama 
282*e3498ec5SRui Ueyama   Symbol *S;
283*e3498ec5SRui Ueyama   bool WasInserted;
284*e3498ec5SRui Ueyama   std::tie(S, WasInserted) = insert(Name);
285*e3498ec5SRui Ueyama 
286*e3498ec5SRui Ueyama   if (WasInserted)
287*e3498ec5SRui Ueyama     replaceSymbol<UndefinedGlobal>(S, Name, Flags, File, Type);
288*e3498ec5SRui Ueyama   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
289*e3498ec5SRui Ueyama     cast<ArchiveFile>(Lazy->getFile())->addMember(&Lazy->getArchiveSymbol());
290*e3498ec5SRui Ueyama   else if (S->isDefined())
291*e3498ec5SRui Ueyama     checkGlobalType(S, File, Type);
292*e3498ec5SRui Ueyama   return S;
293*e3498ec5SRui Ueyama }
294*e3498ec5SRui Ueyama 
295*e3498ec5SRui Ueyama void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
296a681a116SSam Clegg   DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
297c94d393aSSam Clegg   StringRef Name = Sym->getName();
298c03c9040SRui Ueyama 
299c94d393aSSam Clegg   Symbol *S;
300c94d393aSSam Clegg   bool WasInserted;
301c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
302c03c9040SRui Ueyama 
303c94d393aSSam Clegg   if (WasInserted) {
304*e3498ec5SRui Ueyama     replaceSymbol<LazySymbol>(S, Name, File, *Sym);
305c03c9040SRui Ueyama     return;
306c03c9040SRui Ueyama   }
307c03c9040SRui Ueyama 
308c03c9040SRui Ueyama   // If there is an existing undefined symbol, load a new one from the archive.
309c03c9040SRui Ueyama   if (S->isUndefined()) {
310c94d393aSSam Clegg     DEBUG(dbgs() << "replacing existing undefined\n");
311*e3498ec5SRui Ueyama     File->addMember(Sym);
312c94d393aSSam Clegg   }
313c94d393aSSam Clegg }
314e0f6fcd0SSam Clegg 
315e0f6fcd0SSam Clegg bool SymbolTable::addComdat(StringRef Name, ObjFile *F) {
316e0f6fcd0SSam Clegg   DEBUG(dbgs() << "addComdat: " << Name << "\n");
317e0f6fcd0SSam Clegg   ObjFile *&File = ComdatMap[CachedHashStringRef(Name)];
318e0f6fcd0SSam Clegg   if (File) {
319e0f6fcd0SSam Clegg     DEBUG(dbgs() << "COMDAT already defined\n");
320e0f6fcd0SSam Clegg     return false;
321e0f6fcd0SSam Clegg   }
322e0f6fcd0SSam Clegg   File = F;
323e0f6fcd0SSam Clegg   return true;
324e0f6fcd0SSam Clegg }
325e0f6fcd0SSam Clegg 
326e0f6fcd0SSam Clegg ObjFile *SymbolTable::findComdat(StringRef Name) const {
327e0f6fcd0SSam Clegg   auto It = ComdatMap.find(CachedHashStringRef(Name));
328e0f6fcd0SSam Clegg   return It == ComdatMap.end() ? nullptr : It->second;
329e0f6fcd0SSam Clegg }
330