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 
12c94d393aSSam Clegg #include "Config.h"
13c94d393aSSam Clegg #include "Strings.h"
14*b8621596SSam Clegg #include "WriterUtils.h"
15c94d393aSSam Clegg #include "lld/Common/ErrorHandler.h"
162017d52bSRui Ueyama #include "lld/Common/Memory.h"
17c94d393aSSam Clegg 
18c94d393aSSam Clegg #include <unordered_set>
19c94d393aSSam Clegg 
20c94d393aSSam Clegg #define DEBUG_TYPE "lld"
21c94d393aSSam Clegg 
22c94d393aSSam Clegg using namespace llvm;
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() {
37c94d393aSSam Clegg   std::unordered_set<Symbol *> Undefs;
38a80d94d5SSam Clegg   for (auto &I : SymMap) {
39c94d393aSSam Clegg     Symbol *Sym = I.second;
40c94d393aSSam Clegg     if (Sym->isUndefined() && !Sym->isWeak() &&
41c94d393aSSam Clegg         Config->AllowUndefinedSymbols.count(Sym->getName()) == 0) {
42c94d393aSSam Clegg       Undefs.insert(Sym);
43c94d393aSSam Clegg     }
44c94d393aSSam Clegg   }
45c94d393aSSam Clegg 
46c94d393aSSam Clegg   if (Undefs.empty())
47c94d393aSSam Clegg     return;
48c94d393aSSam Clegg 
49c94d393aSSam Clegg   for (ObjFile *File : ObjectFiles)
50c94d393aSSam Clegg     for (Symbol *Sym : File->getSymbols())
51c94d393aSSam Clegg       if (Undefs.count(Sym))
52c94d393aSSam Clegg         error(toString(File) + ": undefined symbol: " + toString(*Sym));
53c94d393aSSam Clegg 
54c94d393aSSam Clegg   for (Symbol *Sym : Undefs)
55c94d393aSSam Clegg     if (!Sym->getFile())
56c94d393aSSam Clegg       error("undefined symbol: " + toString(*Sym));
57c94d393aSSam Clegg }
58c94d393aSSam Clegg 
59c94d393aSSam Clegg Symbol *SymbolTable::find(StringRef Name) {
60a80d94d5SSam Clegg   auto It = SymMap.find(CachedHashStringRef(Name));
61a80d94d5SSam Clegg   if (It == SymMap.end())
62c94d393aSSam Clegg     return nullptr;
63c94d393aSSam Clegg   return It->second;
64c94d393aSSam Clegg }
65c94d393aSSam Clegg 
66c94d393aSSam Clegg std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
67a80d94d5SSam Clegg   Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
68c94d393aSSam Clegg   if (Sym)
69c94d393aSSam Clegg     return {Sym, false};
70c94d393aSSam Clegg   Sym = make<Symbol>(Name, false);
71c94d393aSSam Clegg   return {Sym, true};
72c94d393aSSam Clegg }
73c94d393aSSam Clegg 
74c94d393aSSam Clegg void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
75c94d393aSSam Clegg   error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
76c94d393aSSam Clegg         toString(Existing->getFile()) + "\n>>> defined in " +
77e2ed092eSSam Clegg         toString(NewFile));
78c94d393aSSam Clegg }
79c94d393aSSam Clegg 
80*b8621596SSam Clegg // Get the signature for a given function symbol, either by looking
81*b8621596SSam Clegg // it up in function sections (for defined functions), of the imports section
82*b8621596SSam Clegg // (for imported functions).
83*b8621596SSam Clegg static const WasmSignature *getFunctionSig(const ObjFile &Obj,
84*b8621596SSam Clegg                                            const WasmSymbol &Sym) {
85*b8621596SSam Clegg   DEBUG(dbgs() << "getFunctionSig: " << Sym.Name << "\n");
86*b8621596SSam Clegg   const WasmObjectFile *WasmObj = Obj.getWasmObj();
87*b8621596SSam Clegg   uint32_t FunctionType;
88*b8621596SSam Clegg   if (Obj.isImportedFunction(Sym.ElementIndex)) {
89*b8621596SSam Clegg     const WasmImport &Import = WasmObj->imports()[Sym.ImportIndex];
90*b8621596SSam Clegg     FunctionType = Import.SigIndex;
91*b8621596SSam Clegg   } else {
92*b8621596SSam Clegg     uint32_t FuntionIndex = Sym.ElementIndex - Obj.NumFunctionImports();
93*b8621596SSam Clegg     FunctionType = WasmObj->functionTypes()[FuntionIndex];
94*b8621596SSam Clegg   }
95*b8621596SSam Clegg   return &WasmObj->types()[FunctionType];
96*b8621596SSam Clegg }
97*b8621596SSam Clegg 
98*b8621596SSam Clegg // Check the type of new symbol matches that of the symbol is replacing.
99*b8621596SSam Clegg // For functions this can also involve verifying that the signatures match.
100*b8621596SSam Clegg static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
101*b8621596SSam Clegg                              const WasmSymbol &New,
102*b8621596SSam Clegg                              const WasmSignature *NewSig) {
103*b8621596SSam Clegg   if (Existing.isLazy())
104c94d393aSSam Clegg     return;
105c94d393aSSam Clegg 
106*b8621596SSam Clegg   bool NewIsFunction = New.Type == WasmSymbol::SymbolType::FUNCTION_EXPORT ||
107*b8621596SSam Clegg                        New.Type == WasmSymbol::SymbolType::FUNCTION_IMPORT;
108*b8621596SSam Clegg 
109*b8621596SSam Clegg   // First check the symbol types match (i.e. either both are function
110*b8621596SSam Clegg   // symbols or both are data symbols).
111*b8621596SSam Clegg   if (Existing.isFunction() != NewIsFunction) {
112*b8621596SSam Clegg     error("symbol type mismatch: " + New.Name + "\n>>> defined as " +
113*b8621596SSam Clegg           (Existing.isFunction() ? "Function" : "Global") + " in " +
114*b8621596SSam Clegg           toString(Existing.getFile()) + "\n>>> defined as " +
115*b8621596SSam Clegg           (NewIsFunction ? "Function" : "Global") + " in " + F.getName());
116*b8621596SSam Clegg     return;
117*b8621596SSam Clegg   }
118*b8621596SSam Clegg 
119*b8621596SSam Clegg   // For function symbols, optionally check the function signature matches too.
120*b8621596SSam Clegg   if (!NewIsFunction || !Config->CheckSignatures)
121c94d393aSSam Clegg     return;
122c94d393aSSam Clegg 
123*b8621596SSam Clegg   DEBUG(dbgs() << "checkSymbolTypes: " << New.Name << "\n");
124*b8621596SSam Clegg   assert(NewSig);
125*b8621596SSam Clegg 
126*b8621596SSam Clegg   const WasmSignature &OldSig = Existing.getFunctionType();
127*b8621596SSam Clegg   if (*NewSig == OldSig)
128*b8621596SSam Clegg     return;
129*b8621596SSam Clegg 
130*b8621596SSam Clegg   error("function signature mismatch: " + New.Name + "\n>>> defined as " +
131*b8621596SSam Clegg         toString(OldSig) + " in " + toString(Existing.getFile()) +
132*b8621596SSam Clegg         "\n>>> defined as " + toString(*NewSig) + " in " + F.getName());
133c94d393aSSam Clegg }
134c94d393aSSam Clegg 
135c94d393aSSam Clegg Symbol *SymbolTable::addDefinedGlobal(StringRef Name) {
136c94d393aSSam Clegg   DEBUG(dbgs() << "addDefinedGlobal: " << Name << "\n");
137c94d393aSSam Clegg   Symbol *S;
138c94d393aSSam Clegg   bool WasInserted;
139c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
140c94d393aSSam Clegg   if (WasInserted)
141c94d393aSSam Clegg     S->update(Symbol::DefinedGlobalKind);
142c94d393aSSam Clegg   else if (!S->isGlobal())
143c94d393aSSam Clegg     error("symbol type mismatch: " + Name);
144c94d393aSSam Clegg   return S;
145c94d393aSSam Clegg }
146c94d393aSSam Clegg 
147c94d393aSSam Clegg Symbol *SymbolTable::addDefined(InputFile *F, const WasmSymbol *Sym,
148c94d393aSSam Clegg                                 const InputSegment *Segment) {
149c94d393aSSam Clegg   DEBUG(dbgs() << "addDefined: " << Sym->Name << "\n");
150c94d393aSSam Clegg   Symbol *S;
151c94d393aSSam Clegg   bool WasInserted;
152c94d393aSSam Clegg   Symbol::Kind Kind = Symbol::DefinedFunctionKind;
153*b8621596SSam Clegg   const WasmSignature *NewSig = nullptr;
154c94d393aSSam Clegg   if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_EXPORT)
155c94d393aSSam Clegg     Kind = Symbol::DefinedGlobalKind;
156*b8621596SSam Clegg   else
157*b8621596SSam Clegg     NewSig = getFunctionSig(*cast<ObjFile>(F), *Sym);
158c94d393aSSam Clegg 
159c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Sym->Name);
160c94d393aSSam Clegg   if (WasInserted) {
161*b8621596SSam Clegg     S->update(Kind, F, Sym, Segment, NewSig);
162*b8621596SSam Clegg   } else if (S->isLazy()) {
163*b8621596SSam Clegg     // The existing symbol is lazy. Replace it without checking types since
164*b8621596SSam Clegg     // lazy symbols don't have any type information.
165*b8621596SSam Clegg     DEBUG(dbgs() << "replacing existing lazy symbol: " << Sym->Name << "\n");
166*b8621596SSam Clegg     S->update(Kind, F, Sym, Segment, NewSig);
167c94d393aSSam Clegg   } else if (!S->isDefined()) {
168c94d393aSSam Clegg     // The existing symbol table entry is undefined. The new symbol replaces
169*b8621596SSam Clegg     // it, after checkign the type matches
170c94d393aSSam Clegg     DEBUG(dbgs() << "resolving existing undefined symbol: " << Sym->Name
171c94d393aSSam Clegg                  << "\n");
172*b8621596SSam Clegg     checkSymbolTypes(*S, *F, *Sym, NewSig);
173*b8621596SSam Clegg     S->update(Kind, F, Sym, Segment, NewSig);
174c94d393aSSam Clegg   } else if (Sym->isWeak()) {
175c94d393aSSam Clegg     // the new symbol is weak we can ignore it
176c94d393aSSam Clegg     DEBUG(dbgs() << "existing symbol takes precensence\n");
177c94d393aSSam Clegg   } else if (S->isWeak()) {
178c94d393aSSam Clegg     // the new symbol is not weak and the existing symbol is, so we replace
179c94d393aSSam Clegg     // it
180c94d393aSSam Clegg     DEBUG(dbgs() << "replacing existing weak symbol\n");
181*b8621596SSam Clegg     checkSymbolTypes(*S, *F, *Sym, NewSig);
182*b8621596SSam Clegg     S->update(Kind, F, Sym, Segment, NewSig);
183c94d393aSSam Clegg   } else {
184c94d393aSSam Clegg     // niether symbol is week. They conflict.
185c94d393aSSam Clegg     reportDuplicate(S, F);
186c94d393aSSam Clegg   }
187c94d393aSSam Clegg   return S;
188c94d393aSSam Clegg }
189c94d393aSSam Clegg 
190*b8621596SSam Clegg Symbol *SymbolTable::addUndefinedFunction(StringRef Name,
191*b8621596SSam Clegg                                           const WasmSignature *Type) {
192c94d393aSSam Clegg   Symbol *S;
193c94d393aSSam Clegg   bool WasInserted;
194c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
195*b8621596SSam Clegg   if (WasInserted) {
196*b8621596SSam Clegg     S->update(Symbol::UndefinedFunctionKind, nullptr, nullptr, nullptr, Type);
197*b8621596SSam Clegg   } else if (!S->isFunction()) {
198c94d393aSSam Clegg     error("symbol type mismatch: " + Name);
199*b8621596SSam Clegg   }
200c94d393aSSam Clegg   return S;
201c94d393aSSam Clegg }
202c94d393aSSam Clegg 
203c94d393aSSam Clegg Symbol *SymbolTable::addUndefined(InputFile *F, const WasmSymbol *Sym) {
204c94d393aSSam Clegg   DEBUG(dbgs() << "addUndefined: " << displayName(Sym->Name) << "\n");
205c94d393aSSam Clegg   Symbol *S;
206c94d393aSSam Clegg   bool WasInserted;
207c94d393aSSam Clegg   Symbol::Kind Kind = Symbol::UndefinedFunctionKind;
208*b8621596SSam Clegg   const WasmSignature *NewSig = nullptr;
209c94d393aSSam Clegg   if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_IMPORT)
210c94d393aSSam Clegg     Kind = Symbol::UndefinedGlobalKind;
211*b8621596SSam Clegg   else
212*b8621596SSam Clegg     NewSig = getFunctionSig(*cast<ObjFile>(F), *Sym);
213c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Sym->Name);
214c94d393aSSam Clegg   if (WasInserted) {
215*b8621596SSam Clegg     S->update(Kind, F, Sym, nullptr, NewSig);
216c94d393aSSam Clegg   } else if (S->isLazy()) {
217c94d393aSSam Clegg     DEBUG(dbgs() << "resolved by existing lazy\n");
218c94d393aSSam Clegg     auto *AF = cast<ArchiveFile>(S->getFile());
219c94d393aSSam Clegg     AF->addMember(&S->getArchiveSymbol());
220c94d393aSSam Clegg   } else if (S->isDefined()) {
221c94d393aSSam Clegg     DEBUG(dbgs() << "resolved by existing\n");
222*b8621596SSam Clegg     checkSymbolTypes(*S, *F, *Sym, NewSig);
223c94d393aSSam Clegg   }
224c94d393aSSam Clegg   return S;
225c94d393aSSam Clegg }
226c94d393aSSam Clegg 
227c94d393aSSam Clegg void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) {
228c94d393aSSam Clegg   DEBUG(dbgs() << "addLazy: " << displayName(Sym->getName()) << "\n");
229c94d393aSSam Clegg   StringRef Name = Sym->getName();
230c94d393aSSam Clegg   Symbol *S;
231c94d393aSSam Clegg   bool WasInserted;
232c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
233c94d393aSSam Clegg   if (WasInserted) {
234c94d393aSSam Clegg     S->update(Symbol::LazyKind, F);
235c94d393aSSam Clegg     S->setArchiveSymbol(*Sym);
236c94d393aSSam Clegg   } else if (S->isUndefined()) {
237c94d393aSSam Clegg     // There is an existing undefined symbol.  The can load from the
238c94d393aSSam Clegg     // archive.
239c94d393aSSam Clegg     DEBUG(dbgs() << "replacing existing undefined\n");
240c94d393aSSam Clegg     F->addMember(Sym);
241c94d393aSSam Clegg   }
242c94d393aSSam Clegg }
243