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"
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 
74b8621596SSam Clegg // Check the type of new symbol matches that of the symbol is replacing.
75b8621596SSam Clegg // For functions this can also involve verifying that the signatures match.
76b8621596SSam Clegg static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
77dfb0b2c7SSam Clegg                              bool NewIsFunction, const WasmSignature *NewSig) {
78b8621596SSam Clegg   if (Existing.isLazy())
79c94d393aSSam Clegg     return;
80c94d393aSSam Clegg 
81b8621596SSam Clegg   // First check the symbol types match (i.e. either both are function
82b8621596SSam Clegg   // symbols or both are data symbols).
83caca8d5dSSam Clegg   if (isa<FunctionSymbol>(Existing) != NewIsFunction) {
8420db381bSSam Clegg     error("symbol type mismatch: " + Existing.getName() + "\n>>> defined as " +
85caca8d5dSSam Clegg           (isa<FunctionSymbol>(Existing) ? "Function" : "Global") + " in " +
86b8621596SSam Clegg           toString(Existing.getFile()) + "\n>>> defined as " +
87b8621596SSam Clegg           (NewIsFunction ? "Function" : "Global") + " in " + F.getName());
88b8621596SSam Clegg     return;
89b8621596SSam Clegg   }
90b8621596SSam Clegg 
91b8621596SSam Clegg   // For function symbols, optionally check the function signature matches too.
92dfb0b2c7SSam Clegg   auto *ExistingFunc = dyn_cast<FunctionSymbol>(&Existing);
93dfb0b2c7SSam Clegg   if (!ExistingFunc || !Config->CheckSignatures)
94c94d393aSSam Clegg     return;
95dfb0b2c7SSam Clegg 
963f8db988SSam Clegg   const WasmSignature *OldSig = ExistingFunc->getFunctionType();
973f8db988SSam Clegg 
9831de2f0cSSam Clegg   // Skip the signature check if the existing function has no signature (e.g.
9931de2f0cSSam Clegg   // if it is an undefined symbol generated by --undefined command line flag).
1003f8db988SSam Clegg   if (OldSig == nullptr)
10131de2f0cSSam Clegg     return;
102c94d393aSSam Clegg 
103dfb0b2c7SSam Clegg   DEBUG(dbgs() << "checkSymbolTypes: " << ExistingFunc->getName() << "\n");
104b8621596SSam Clegg   assert(NewSig);
105b8621596SSam Clegg 
1063f8db988SSam Clegg   if (*NewSig == *OldSig)
107b8621596SSam Clegg     return;
108b8621596SSam Clegg 
109dfb0b2c7SSam Clegg   error("function signature mismatch: " + ExistingFunc->getName() +
1103f8db988SSam Clegg         "\n>>> defined as " + toString(*OldSig) + " in " +
111dfb0b2c7SSam Clegg         toString(ExistingFunc->getFile()) + "\n>>> defined as " +
112dfb0b2c7SSam Clegg         toString(*NewSig) + " in " + F.getName());
113c94d393aSSam Clegg }
114c94d393aSSam Clegg 
11524b3dcd4SSam Clegg static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
116dfb0b2c7SSam Clegg                              bool IsFunction, const InputChunk *Chunk) {
11724b3dcd4SSam Clegg   const WasmSignature *Sig = nullptr;
11824b3dcd4SSam Clegg   if (auto *F = dyn_cast_or_null<InputFunction>(Chunk))
11924b3dcd4SSam Clegg     Sig = &F->Signature;
120dfb0b2c7SSam Clegg   return checkSymbolTypes(Existing, F, IsFunction, Sig);
12124b3dcd4SSam Clegg }
12224b3dcd4SSam Clegg 
123dfb0b2c7SSam Clegg DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
12450686856SSam Clegg                                                    const WasmSignature *Type,
12550686856SSam Clegg                                                    uint32_t Flags) {
126a189230bSSam Clegg   DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
12750686856SSam Clegg   Symbol *S;
12850686856SSam Clegg   bool WasInserted;
12950686856SSam Clegg   std::tie(S, WasInserted) = insert(Name);
130a189230bSSam Clegg   assert(WasInserted);
131dfb0b2c7SSam Clegg   return replaceSymbol<DefinedFunction>(S, Name, Flags, Type);
13250686856SSam Clegg }
13350686856SSam Clegg 
134dfb0b2c7SSam Clegg DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags) {
135a189230bSSam Clegg   DEBUG(dbgs() << "addSyntheticGlobal: " << Name << "\n");
136c94d393aSSam Clegg   Symbol *S;
137c94d393aSSam Clegg   bool WasInserted;
138c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
139a189230bSSam Clegg   assert(WasInserted);
140dfb0b2c7SSam Clegg   return replaceSymbol<DefinedGlobal>(S, Name, Flags);
141c94d393aSSam Clegg }
142c94d393aSSam Clegg 
143*93e559b1SSam Clegg struct NewSymbol {
144*93e559b1SSam Clegg   InputFile *File;
145*93e559b1SSam Clegg   uint32_t Flags;
146*93e559b1SSam Clegg   InputChunk *Chunk;
147*93e559b1SSam Clegg   bool IsFunction;
148*93e559b1SSam Clegg };
149*93e559b1SSam Clegg 
150*93e559b1SSam Clegg static bool shouldReplace(const Symbol &Existing, const NewSymbol &New) {
151dfb0b2c7SSam Clegg   bool Replace = false;
152dfb0b2c7SSam Clegg   bool CheckTypes = false;
153c94d393aSSam Clegg 
154*93e559b1SSam Clegg   if (Existing.isLazy()) {
155dfb0b2c7SSam Clegg     // Existing symbol is lazy. Replace it without checking types since
156b8621596SSam Clegg     // lazy symbols don't have any type information.
157*93e559b1SSam Clegg     DEBUG(dbgs() << "replacing existing lazy symbol: " << Existing.getName()
158*93e559b1SSam Clegg                  << "\n");
159dfb0b2c7SSam Clegg     Replace = true;
160*93e559b1SSam Clegg   } else if (!Existing.isDefined()) {
161dfb0b2c7SSam Clegg     // Existing symbol is undefined: replace it, while check types.
162*93e559b1SSam Clegg     DEBUG(dbgs() << "resolving existing undefined symbol: "
163*93e559b1SSam Clegg                  << Existing.getName() << "\n");
164dfb0b2c7SSam Clegg     Replace = true;
165dfb0b2c7SSam Clegg     CheckTypes = true;
166*93e559b1SSam Clegg   } else if ((New.Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
167c94d393aSSam Clegg     // the new symbol is weak we can ignore it
16849ed9262SSam Clegg     DEBUG(dbgs() << "existing symbol takes precedence\n");
169c7e885b5SSam Clegg     CheckTypes = true;
170*93e559b1SSam Clegg   } else if (Existing.isWeak()) {
171dfb0b2c7SSam Clegg     // the existing symbol is, so we replace it
172c94d393aSSam Clegg     DEBUG(dbgs() << "replacing existing weak symbol\n");
173dfb0b2c7SSam Clegg     Replace = true;
174dfb0b2c7SSam Clegg     CheckTypes = true;
175c94d393aSSam Clegg   } else {
17649ed9262SSam Clegg     // neither symbol is week. They conflict.
177*93e559b1SSam Clegg     error("duplicate symbol: " + toString(Existing) + "\n>>> defined in " +
178*93e559b1SSam Clegg           toString(Existing.getFile()) + "\n>>> defined in " +
179*93e559b1SSam Clegg           toString(New.File));
180c94d393aSSam Clegg   }
181c94d393aSSam Clegg 
182dfb0b2c7SSam Clegg   if (CheckTypes)
183*93e559b1SSam Clegg     checkSymbolTypes(Existing, *New.File, New.IsFunction, New.Chunk);
184*93e559b1SSam Clegg 
185*93e559b1SSam Clegg   return Replace;
186b8621596SSam Clegg }
187*93e559b1SSam Clegg 
188*93e559b1SSam Clegg Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
189*93e559b1SSam Clegg                                         InputFile *F, InputFunction *Function) {
190*93e559b1SSam Clegg   DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n");
191*93e559b1SSam Clegg   Symbol *S;
192*93e559b1SSam Clegg   bool WasInserted;
193*93e559b1SSam Clegg   std::tie(S, WasInserted) = insert(Name);
194*93e559b1SSam Clegg   NewSymbol New{F, Flags, Function, true};
195*93e559b1SSam Clegg   if (WasInserted || shouldReplace(*S, New))
196*93e559b1SSam Clegg     replaceSymbol<DefinedFunction>(S, Name, Flags, F, Function);
197*93e559b1SSam Clegg   return S;
198*93e559b1SSam Clegg }
199*93e559b1SSam Clegg 
200*93e559b1SSam Clegg Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
201*93e559b1SSam Clegg                                       InputFile *F, InputSegment *Segment,
202*93e559b1SSam Clegg                                       uint32_t Address) {
203*93e559b1SSam Clegg   DEBUG(dbgs() << "addDefinedGlobal:" << Name << " addr:" << Address << "\n");
204*93e559b1SSam Clegg   Symbol *S;
205*93e559b1SSam Clegg   bool WasInserted;
206*93e559b1SSam Clegg   std::tie(S, WasInserted) = insert(Name);
207*93e559b1SSam Clegg   NewSymbol New{F, Flags, Segment, false};
208*93e559b1SSam Clegg   if (WasInserted || shouldReplace(*S, New))
209*93e559b1SSam Clegg     replaceSymbol<DefinedGlobal>(S, Name, Flags, F, Segment, Address);
210c94d393aSSam Clegg   return S;
211c94d393aSSam Clegg }
212c94d393aSSam Clegg 
21320db381bSSam Clegg Symbol *SymbolTable::addUndefined(StringRef Name, Symbol::Kind Kind,
21420db381bSSam Clegg                                   uint32_t Flags, InputFile *F,
2158d146bbcSSam Clegg                                   const WasmSignature *Type) {
21620db381bSSam Clegg   DEBUG(dbgs() << "addUndefined: " << Name << "\n");
217c94d393aSSam Clegg   Symbol *S;
218c94d393aSSam Clegg   bool WasInserted;
21920db381bSSam Clegg   std::tie(S, WasInserted) = insert(Name);
220dfb0b2c7SSam Clegg   bool IsFunction = Kind == Symbol::UndefinedFunctionKind;
221c94d393aSSam Clegg   if (WasInserted) {
222dfb0b2c7SSam Clegg     if (IsFunction)
223dfb0b2c7SSam Clegg       replaceSymbol<UndefinedFunction>(S, Name, Flags, F, Type);
224dfb0b2c7SSam Clegg     else
225dfb0b2c7SSam Clegg       replaceSymbol<UndefinedGlobal>(S, Name, Flags, F);
226dfb0b2c7SSam Clegg   } else if (auto *LazySym = dyn_cast<LazySymbol>(S)) {
227c94d393aSSam Clegg     DEBUG(dbgs() << "resolved by existing lazy\n");
228dfb0b2c7SSam Clegg     auto *AF = cast<ArchiveFile>(LazySym->getFile());
229dfb0b2c7SSam Clegg     AF->addMember(&LazySym->getArchiveSymbol());
230c94d393aSSam Clegg   } else if (S->isDefined()) {
231c94d393aSSam Clegg     DEBUG(dbgs() << "resolved by existing\n");
232dfb0b2c7SSam Clegg     checkSymbolTypes(*S, *F, IsFunction, Type);
233c94d393aSSam Clegg   }
234c94d393aSSam Clegg   return S;
235c94d393aSSam Clegg }
236c94d393aSSam Clegg 
237c94d393aSSam Clegg void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) {
238a681a116SSam Clegg   DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
239c94d393aSSam Clegg   StringRef Name = Sym->getName();
240c94d393aSSam Clegg   Symbol *S;
241c94d393aSSam Clegg   bool WasInserted;
242c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
243c94d393aSSam Clegg   if (WasInserted) {
244dfb0b2c7SSam Clegg     replaceSymbol<LazySymbol>(S, Name, F, *Sym);
245c94d393aSSam Clegg   } else if (S->isUndefined()) {
246c94d393aSSam Clegg     // There is an existing undefined symbol.  The can load from the
247c94d393aSSam Clegg     // archive.
248c94d393aSSam Clegg     DEBUG(dbgs() << "replacing existing undefined\n");
249c94d393aSSam Clegg     F->addMember(Sym);
250c94d393aSSam Clegg   }
251c94d393aSSam Clegg }
252e0f6fcd0SSam Clegg 
253e0f6fcd0SSam Clegg bool SymbolTable::addComdat(StringRef Name, ObjFile *F) {
254e0f6fcd0SSam Clegg   DEBUG(dbgs() << "addComdat: " << Name << "\n");
255e0f6fcd0SSam Clegg   ObjFile *&File = ComdatMap[CachedHashStringRef(Name)];
256e0f6fcd0SSam Clegg   if (File) {
257e0f6fcd0SSam Clegg     DEBUG(dbgs() << "COMDAT already defined\n");
258e0f6fcd0SSam Clegg     return false;
259e0f6fcd0SSam Clegg   }
260e0f6fcd0SSam Clegg   File = F;
261e0f6fcd0SSam Clegg   return true;
262e0f6fcd0SSam Clegg }
263e0f6fcd0SSam Clegg 
264e0f6fcd0SSam Clegg ObjFile *SymbolTable::findComdat(StringRef Name) const {
265e0f6fcd0SSam Clegg   auto It = ComdatMap.find(CachedHashStringRef(Name));
266e0f6fcd0SSam Clegg   return It == ComdatMap.end() ? nullptr : It->second;
267e0f6fcd0SSam Clegg }
268