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"
135fa274beSSam Clegg #include "InputChunks.h"
14b8621596SSam 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;
2320db381bSSam Clegg using namespace llvm::wasm;
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));
31c94d393aSSam Clegg   File->parse();
32c94d393aSSam Clegg 
33c94d393aSSam Clegg   if (auto *F = dyn_cast<ObjFile>(File))
34c94d393aSSam Clegg     ObjectFiles.push_back(F);
35c94d393aSSam Clegg }
36c94d393aSSam Clegg 
37c94d393aSSam Clegg void SymbolTable::reportRemainingUndefines() {
38c94d393aSSam Clegg   std::unordered_set<Symbol *> Undefs;
3974fe0ba1SSam Clegg   for (Symbol *Sym : SymVector) {
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);
7174fe0ba1SSam Clegg   SymVector.emplace_back(Sym);
72c94d393aSSam Clegg   return {Sym, true};
73c94d393aSSam Clegg }
74c94d393aSSam Clegg 
75c94d393aSSam Clegg void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
76c94d393aSSam Clegg   error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
77c94d393aSSam Clegg         toString(Existing->getFile()) + "\n>>> defined in " +
78e2ed092eSSam Clegg         toString(NewFile));
79c94d393aSSam Clegg }
80c94d393aSSam Clegg 
81b8621596SSam Clegg // Check the type of new symbol matches that of the symbol is replacing.
82b8621596SSam Clegg // For functions this can also involve verifying that the signatures match.
83b8621596SSam Clegg static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
8420db381bSSam Clegg                              Symbol::Kind Kind, const WasmSignature *NewSig) {
85b8621596SSam Clegg   if (Existing.isLazy())
86c94d393aSSam Clegg     return;
87c94d393aSSam Clegg 
8820db381bSSam Clegg   bool NewIsFunction = Kind == Symbol::Kind::UndefinedFunctionKind ||
8920db381bSSam Clegg                        Kind == Symbol::Kind::DefinedFunctionKind;
90b8621596SSam Clegg 
91b8621596SSam Clegg   // First check the symbol types match (i.e. either both are function
92b8621596SSam Clegg   // symbols or both are data symbols).
93b8621596SSam Clegg   if (Existing.isFunction() != NewIsFunction) {
9420db381bSSam Clegg     error("symbol type mismatch: " + Existing.getName() + "\n>>> defined as " +
95b8621596SSam Clegg           (Existing.isFunction() ? "Function" : "Global") + " in " +
96b8621596SSam Clegg           toString(Existing.getFile()) + "\n>>> defined as " +
97b8621596SSam Clegg           (NewIsFunction ? "Function" : "Global") + " in " + F.getName());
98b8621596SSam Clegg     return;
99b8621596SSam Clegg   }
100b8621596SSam Clegg 
101b8621596SSam Clegg   // For function symbols, optionally check the function signature matches too.
102b8621596SSam Clegg   if (!NewIsFunction || !Config->CheckSignatures)
103c94d393aSSam Clegg     return;
10431de2f0cSSam Clegg   // Skip the signature check if the existing function has no signature (e.g.
10531de2f0cSSam Clegg   // if it is an undefined symbol generated by --undefined command line flag).
10631de2f0cSSam Clegg   if (!Existing.hasFunctionType())
10731de2f0cSSam Clegg     return;
108c94d393aSSam Clegg 
10920db381bSSam Clegg   DEBUG(dbgs() << "checkSymbolTypes: " << Existing.getName() << "\n");
110b8621596SSam Clegg   assert(NewSig);
111b8621596SSam Clegg 
112b8621596SSam Clegg   const WasmSignature &OldSig = Existing.getFunctionType();
113b8621596SSam Clegg   if (*NewSig == OldSig)
114b8621596SSam Clegg     return;
115b8621596SSam Clegg 
11620db381bSSam Clegg   error("function signature mismatch: " + Existing.getName() +
11720db381bSSam Clegg         "\n>>> defined as " + toString(OldSig) + " in " +
11820db381bSSam Clegg         toString(Existing.getFile()) + "\n>>> defined as " + toString(*NewSig) +
11920db381bSSam Clegg         " in " + F.getName());
120c94d393aSSam Clegg }
121c94d393aSSam Clegg 
12250686856SSam Clegg Symbol *SymbolTable::addDefinedFunction(StringRef Name,
12350686856SSam Clegg                                         const WasmSignature *Type,
12450686856SSam Clegg                                         uint32_t Flags) {
12550686856SSam Clegg   DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n");
12650686856SSam Clegg   Symbol *S;
12750686856SSam Clegg   bool WasInserted;
12850686856SSam Clegg   std::tie(S, WasInserted) = insert(Name);
12950686856SSam Clegg   if (WasInserted) {
13050686856SSam Clegg     S->update(Symbol::DefinedFunctionKind, nullptr, Flags);
13150686856SSam Clegg     S->setFunctionType(Type);
13250686856SSam Clegg   } else if (!S->isFunction()) {
13350686856SSam Clegg     error("symbol type mismatch: " + Name);
134*0f0a4287SSam Clegg   } else if (!S->isDefined()) {
135*0f0a4287SSam Clegg     DEBUG(dbgs() << "resolving existing undefined function: " << Name << "\n");
136*0f0a4287SSam Clegg     S->update(Symbol::DefinedFunctionKind, nullptr, Flags);
13750686856SSam Clegg   }
13850686856SSam Clegg   return S;
13950686856SSam Clegg }
14050686856SSam Clegg 
141c94d393aSSam Clegg Symbol *SymbolTable::addDefinedGlobal(StringRef Name) {
142c94d393aSSam Clegg   DEBUG(dbgs() << "addDefinedGlobal: " << Name << "\n");
143c94d393aSSam Clegg   Symbol *S;
144c94d393aSSam Clegg   bool WasInserted;
145c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
146*0f0a4287SSam Clegg   if (WasInserted) {
147c94d393aSSam Clegg     S->update(Symbol::DefinedGlobalKind);
148*0f0a4287SSam Clegg   } else if (!S->isGlobal()) {
149c94d393aSSam Clegg     error("symbol type mismatch: " + Name);
150*0f0a4287SSam Clegg   } else {
151*0f0a4287SSam Clegg     DEBUG(dbgs() << "resolving existing undefined global: " << Name << "\n");
152*0f0a4287SSam Clegg     S->update(Symbol::DefinedGlobalKind);
153*0f0a4287SSam Clegg   }
154c94d393aSSam Clegg   return S;
155c94d393aSSam Clegg }
156c94d393aSSam Clegg 
15720db381bSSam Clegg Symbol *SymbolTable::addDefined(StringRef Name, Symbol::Kind Kind,
15820db381bSSam Clegg                                 uint32_t Flags, InputFile *F,
1598d146bbcSSam Clegg                                 const InputSegment *Segment,
16020db381bSSam Clegg                                 InputFunction *Function, uint32_t Address) {
16120db381bSSam Clegg   DEBUG(dbgs() << "addDefined: " << Name << " addr:" << Address << "\n");
162c94d393aSSam Clegg   Symbol *S;
163c94d393aSSam Clegg   bool WasInserted;
164c94d393aSSam Clegg 
16520db381bSSam Clegg   std::tie(S, WasInserted) = insert(Name);
166c94d393aSSam Clegg   if (WasInserted) {
16720db381bSSam Clegg     S->update(Kind, F, Flags, Segment, Function, Address);
168b8621596SSam Clegg   } else if (S->isLazy()) {
169b8621596SSam Clegg     // The existing symbol is lazy. Replace it without checking types since
170b8621596SSam Clegg     // lazy symbols don't have any type information.
17120db381bSSam Clegg     DEBUG(dbgs() << "replacing existing lazy symbol: " << Name << "\n");
17220db381bSSam Clegg     S->update(Kind, F, Flags, Segment, Function, Address);
173c94d393aSSam Clegg   } else if (!S->isDefined()) {
174c94d393aSSam Clegg     // The existing symbol table entry is undefined. The new symbol replaces
17549ed9262SSam Clegg     // it, after checking the type matches
17620db381bSSam Clegg     DEBUG(dbgs() << "resolving existing undefined symbol: " << Name << "\n");
17720db381bSSam Clegg     checkSymbolTypes(*S, *F, Kind, Function ? &Function->Signature : nullptr);
17820db381bSSam Clegg     S->update(Kind, F, Flags, Segment, Function, Address);
17920db381bSSam Clegg   } else if ((Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
180c94d393aSSam Clegg     // the new symbol is weak we can ignore it
18149ed9262SSam Clegg     DEBUG(dbgs() << "existing symbol takes precedence\n");
182c94d393aSSam Clegg   } else if (S->isWeak()) {
183c94d393aSSam Clegg     // the new symbol is not weak and the existing symbol is, so we replace
184c94d393aSSam Clegg     // it
185c94d393aSSam Clegg     DEBUG(dbgs() << "replacing existing weak symbol\n");
18620db381bSSam Clegg     checkSymbolTypes(*S, *F, Kind, Function ? &Function->Signature : nullptr);
18720db381bSSam Clegg     S->update(Kind, F, Flags, Segment, Function, Address);
188c94d393aSSam Clegg   } else {
18949ed9262SSam Clegg     // neither symbol is week. They conflict.
190c94d393aSSam Clegg     reportDuplicate(S, F);
191c94d393aSSam Clegg   }
192c94d393aSSam Clegg   return S;
193c94d393aSSam Clegg }
194c94d393aSSam Clegg 
195b8621596SSam Clegg Symbol *SymbolTable::addUndefinedFunction(StringRef Name,
196b8621596SSam Clegg                                           const WasmSignature *Type) {
197096aa50bSSam Clegg   DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n");
198c94d393aSSam Clegg   Symbol *S;
199c94d393aSSam Clegg   bool WasInserted;
200c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
201b8621596SSam Clegg   if (WasInserted) {
2028d146bbcSSam Clegg     S->update(Symbol::UndefinedFunctionKind);
2038d146bbcSSam Clegg     S->setFunctionType(Type);
204b8621596SSam Clegg   } else if (!S->isFunction()) {
205c94d393aSSam Clegg     error("symbol type mismatch: " + Name);
206b8621596SSam Clegg   }
207c94d393aSSam Clegg   return S;
208c94d393aSSam Clegg }
209c94d393aSSam Clegg 
21020db381bSSam Clegg Symbol *SymbolTable::addUndefined(StringRef Name, Symbol::Kind Kind,
21120db381bSSam Clegg                                   uint32_t Flags, InputFile *F,
2128d146bbcSSam Clegg                                   const WasmSignature *Type) {
21320db381bSSam Clegg   DEBUG(dbgs() << "addUndefined: " << Name << "\n");
214c94d393aSSam Clegg   Symbol *S;
215c94d393aSSam Clegg   bool WasInserted;
21620db381bSSam Clegg   std::tie(S, WasInserted) = insert(Name);
217c94d393aSSam Clegg   if (WasInserted) {
21820db381bSSam Clegg     S->update(Kind, F, Flags);
2198d146bbcSSam Clegg     if (Type)
2208d146bbcSSam Clegg       S->setFunctionType(Type);
221c94d393aSSam Clegg   } else if (S->isLazy()) {
222c94d393aSSam Clegg     DEBUG(dbgs() << "resolved by existing lazy\n");
223c94d393aSSam Clegg     auto *AF = cast<ArchiveFile>(S->getFile());
224c94d393aSSam Clegg     AF->addMember(&S->getArchiveSymbol());
225c94d393aSSam Clegg   } else if (S->isDefined()) {
226c94d393aSSam Clegg     DEBUG(dbgs() << "resolved by existing\n");
22720db381bSSam Clegg     checkSymbolTypes(*S, *F, Kind, Type);
228c94d393aSSam Clegg   }
229c94d393aSSam Clegg   return S;
230c94d393aSSam Clegg }
231c94d393aSSam Clegg 
232c94d393aSSam Clegg void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) {
233a681a116SSam Clegg   DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
234c94d393aSSam Clegg   StringRef Name = Sym->getName();
235c94d393aSSam Clegg   Symbol *S;
236c94d393aSSam Clegg   bool WasInserted;
237c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
238c94d393aSSam Clegg   if (WasInserted) {
239c94d393aSSam Clegg     S->update(Symbol::LazyKind, F);
240c94d393aSSam Clegg     S->setArchiveSymbol(*Sym);
241c94d393aSSam Clegg   } else if (S->isUndefined()) {
242c94d393aSSam Clegg     // There is an existing undefined symbol.  The can load from the
243c94d393aSSam Clegg     // archive.
244c94d393aSSam Clegg     DEBUG(dbgs() << "replacing existing undefined\n");
245c94d393aSSam Clegg     F->addMember(Sym);
246c94d393aSSam Clegg   }
247c94d393aSSam Clegg }
248e0f6fcd0SSam Clegg 
249e0f6fcd0SSam Clegg bool SymbolTable::addComdat(StringRef Name, ObjFile *F) {
250e0f6fcd0SSam Clegg   DEBUG(dbgs() << "addComdat: " << Name << "\n");
251e0f6fcd0SSam Clegg   ObjFile *&File = ComdatMap[CachedHashStringRef(Name)];
252e0f6fcd0SSam Clegg   if (File) {
253e0f6fcd0SSam Clegg     DEBUG(dbgs() << "COMDAT already defined\n");
254e0f6fcd0SSam Clegg     return false;
255e0f6fcd0SSam Clegg   }
256e0f6fcd0SSam Clegg   File = F;
257e0f6fcd0SSam Clegg   return true;
258e0f6fcd0SSam Clegg }
259e0f6fcd0SSam Clegg 
260e0f6fcd0SSam Clegg ObjFile *SymbolTable::findComdat(StringRef Name) const {
261e0f6fcd0SSam Clegg   auto It = ComdatMap.find(CachedHashStringRef(Name));
262e0f6fcd0SSam Clegg   return It == ComdatMap.end() ? nullptr : It->second;
263e0f6fcd0SSam Clegg }
264