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"
13b8621596SSam Clegg #include "WriterUtils.h"
14c94d393aSSam Clegg #include "lld/Common/ErrorHandler.h"
152017d52bSRui Ueyama #include "lld/Common/Memory.h"
167d67dd11SRui Ueyama #include "llvm/ADT/SetVector.h"
17c94d393aSSam Clegg 
18c94d393aSSam Clegg #define DEBUG_TYPE "lld"
19c94d393aSSam Clegg 
20c94d393aSSam Clegg using namespace llvm;
2120db381bSSam Clegg using namespace llvm::wasm;
22c94d393aSSam Clegg using namespace lld;
23c94d393aSSam Clegg using namespace lld::wasm;
24c94d393aSSam Clegg 
25c94d393aSSam Clegg SymbolTable *lld::wasm::Symtab;
26c94d393aSSam Clegg 
27c94d393aSSam Clegg void SymbolTable::addFile(InputFile *File) {
28c94d393aSSam Clegg   log("Processing: " + toString(File));
29c94d393aSSam Clegg   File->parse();
30c94d393aSSam Clegg 
31c94d393aSSam Clegg   if (auto *F = dyn_cast<ObjFile>(File))
32c94d393aSSam Clegg     ObjectFiles.push_back(F);
33c94d393aSSam Clegg }
34c94d393aSSam Clegg 
35c94d393aSSam Clegg void SymbolTable::reportRemainingUndefines() {
367d67dd11SRui Ueyama   SetVector<Symbol *> Undefs;
3774fe0ba1SSam Clegg   for (Symbol *Sym : SymVector) {
38c94d393aSSam Clegg     if (Sym->isUndefined() && !Sym->isWeak() &&
39c94d393aSSam Clegg         Config->AllowUndefinedSymbols.count(Sym->getName()) == 0) {
40c94d393aSSam Clegg       Undefs.insert(Sym);
41c94d393aSSam Clegg     }
42c94d393aSSam Clegg   }
43c94d393aSSam Clegg 
44c94d393aSSam Clegg   if (Undefs.empty())
45c94d393aSSam Clegg     return;
46c94d393aSSam Clegg 
47c94d393aSSam Clegg   for (ObjFile *File : ObjectFiles)
48c94d393aSSam Clegg     for (Symbol *Sym : File->getSymbols())
49c94d393aSSam Clegg       if (Undefs.count(Sym))
50c94d393aSSam Clegg         error(toString(File) + ": undefined symbol: " + toString(*Sym));
51c94d393aSSam Clegg 
52c94d393aSSam Clegg   for (Symbol *Sym : Undefs)
53c94d393aSSam Clegg     if (!Sym->getFile())
54c94d393aSSam Clegg       error("undefined symbol: " + toString(*Sym));
55c94d393aSSam Clegg }
56c94d393aSSam Clegg 
57c94d393aSSam Clegg Symbol *SymbolTable::find(StringRef Name) {
58a80d94d5SSam Clegg   auto It = SymMap.find(CachedHashStringRef(Name));
59a80d94d5SSam Clegg   if (It == SymMap.end())
60c94d393aSSam Clegg     return nullptr;
61c94d393aSSam Clegg   return It->second;
62c94d393aSSam Clegg }
63c94d393aSSam Clegg 
64c94d393aSSam Clegg std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
65a80d94d5SSam Clegg   Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
66c94d393aSSam Clegg   if (Sym)
67c94d393aSSam Clegg     return {Sym, false};
68dfb0b2c7SSam Clegg   Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
6974fe0ba1SSam Clegg   SymVector.emplace_back(Sym);
70c94d393aSSam Clegg   return {Sym, true};
71c94d393aSSam Clegg }
72c94d393aSSam Clegg 
73b8621596SSam Clegg // Check the type of new symbol matches that of the symbol is replacing.
74b8621596SSam Clegg // For functions this can also involve verifying that the signatures match.
75b8621596SSam Clegg static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
76dfb0b2c7SSam Clegg                              bool NewIsFunction, const WasmSignature *NewSig) {
77b8621596SSam Clegg   if (Existing.isLazy())
78c94d393aSSam Clegg     return;
79c94d393aSSam Clegg 
80b8621596SSam Clegg   // First check the symbol types match (i.e. either both are function
81b8621596SSam Clegg   // symbols or both are data symbols).
82caca8d5dSSam Clegg   if (isa<FunctionSymbol>(Existing) != NewIsFunction) {
8320db381bSSam Clegg     error("symbol type mismatch: " + Existing.getName() + "\n>>> defined as " +
84*00245539SSam Clegg           (isa<FunctionSymbol>(Existing) ? "Function" : "Data") + " in " +
85b8621596SSam Clegg           toString(Existing.getFile()) + "\n>>> defined as " +
86*00245539SSam Clegg           (NewIsFunction ? "Function" : "Data") + " in " + F.getName());
87b8621596SSam Clegg     return;
88b8621596SSam Clegg   }
89b8621596SSam Clegg 
90b8621596SSam Clegg   // For function symbols, optionally check the function signature matches too.
91dfb0b2c7SSam Clegg   auto *ExistingFunc = dyn_cast<FunctionSymbol>(&Existing);
92dfb0b2c7SSam Clegg   if (!ExistingFunc || !Config->CheckSignatures)
93c94d393aSSam Clegg     return;
94dfb0b2c7SSam Clegg 
953f8db988SSam Clegg   const WasmSignature *OldSig = ExistingFunc->getFunctionType();
963f8db988SSam Clegg 
9731de2f0cSSam Clegg   // Skip the signature check if the existing function has no signature (e.g.
9831de2f0cSSam Clegg   // if it is an undefined symbol generated by --undefined command line flag).
993f8db988SSam Clegg   if (OldSig == nullptr)
10031de2f0cSSam Clegg     return;
101c94d393aSSam Clegg 
102dfb0b2c7SSam Clegg   DEBUG(dbgs() << "checkSymbolTypes: " << ExistingFunc->getName() << "\n");
103b8621596SSam Clegg   assert(NewSig);
104b8621596SSam Clegg 
1053f8db988SSam Clegg   if (*NewSig == *OldSig)
106b8621596SSam Clegg     return;
107b8621596SSam Clegg 
108dfb0b2c7SSam Clegg   error("function signature mismatch: " + ExistingFunc->getName() +
1093f8db988SSam Clegg         "\n>>> defined as " + toString(*OldSig) + " in " +
110dfb0b2c7SSam Clegg         toString(ExistingFunc->getFile()) + "\n>>> defined as " +
111dfb0b2c7SSam Clegg         toString(*NewSig) + " in " + F.getName());
112c94d393aSSam Clegg }
113c94d393aSSam Clegg 
11424b3dcd4SSam Clegg static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
115dfb0b2c7SSam Clegg                              bool IsFunction, const InputChunk *Chunk) {
11624b3dcd4SSam Clegg   const WasmSignature *Sig = nullptr;
11724b3dcd4SSam Clegg   if (auto *F = dyn_cast_or_null<InputFunction>(Chunk))
11824b3dcd4SSam Clegg     Sig = &F->Signature;
119dfb0b2c7SSam Clegg   return checkSymbolTypes(Existing, F, IsFunction, Sig);
12024b3dcd4SSam Clegg }
12124b3dcd4SSam Clegg 
122dfb0b2c7SSam Clegg DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
12350686856SSam Clegg                                                    const WasmSignature *Type,
12450686856SSam Clegg                                                    uint32_t Flags) {
125a189230bSSam Clegg   DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
12650686856SSam Clegg   Symbol *S;
12750686856SSam Clegg   bool WasInserted;
12850686856SSam Clegg   std::tie(S, WasInserted) = insert(Name);
129a189230bSSam Clegg   assert(WasInserted);
130dfb0b2c7SSam Clegg   return replaceSymbol<DefinedFunction>(S, Name, Flags, Type);
13150686856SSam Clegg }
13250686856SSam Clegg 
133*00245539SSam Clegg DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
134*00245539SSam Clegg                                                  uint32_t Flags) {
135*00245539SSam Clegg   DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
136c94d393aSSam Clegg   Symbol *S;
137c94d393aSSam Clegg   bool WasInserted;
138c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
139a189230bSSam Clegg   assert(WasInserted);
140*00245539SSam Clegg   return replaceSymbol<DefinedData>(S, Name, Flags);
141c94d393aSSam Clegg }
142c94d393aSSam Clegg 
143f60b0d5cSSam Clegg static bool shouldReplace(const Symbol &Existing, InputFile *NewFile,
144f60b0d5cSSam Clegg                           uint32_t NewFlags, InputChunk *NewChunk,
145f60b0d5cSSam Clegg                           bool NewIsFunction) {
146c03c9040SRui Ueyama   // If existing symbol is lazy, replace it without checking types since
147b8621596SSam Clegg   // lazy symbols don't have any type information.
148c03c9040SRui Ueyama   if (Existing.isLazy()) {
14993e559b1SSam Clegg     DEBUG(dbgs() << "replacing existing lazy symbol: " << Existing.getName()
15093e559b1SSam Clegg                  << "\n");
151c03c9040SRui Ueyama     return true;
152c94d393aSSam Clegg   }
153c94d393aSSam Clegg 
154c03c9040SRui Ueyama   // Now we have two wasm symbols, and all wasm symbols that have the same
155c03c9040SRui Ueyama   // symbol name must have the same type, even if they are undefined. This
156c03c9040SRui Ueyama   // is different from ELF because symbol types are not that significant
157c03c9040SRui Ueyama   // in ELF, and undefined symbols in ELF don't have type in the first place.
158f60b0d5cSSam Clegg   checkSymbolTypes(Existing, *NewFile, NewIsFunction, NewChunk);
15993e559b1SSam Clegg 
160c03c9040SRui Ueyama   // If existing symbol is undefined, replace it.
161c03c9040SRui Ueyama   if (!Existing.isDefined()) {
162c03c9040SRui Ueyama     DEBUG(dbgs() << "resolving existing undefined symbol: "
163c03c9040SRui Ueyama                  << Existing.getName() << "\n");
164c03c9040SRui Ueyama     return true;
165c03c9040SRui Ueyama   }
166c03c9040SRui Ueyama 
167c03c9040SRui Ueyama   // Now we have two defined symbols. If the new one is weak, we can ignore it.
168c03c9040SRui Ueyama   if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
169c03c9040SRui Ueyama     DEBUG(dbgs() << "existing symbol takes precedence\n");
170c03c9040SRui Ueyama     return false;
171c03c9040SRui Ueyama   }
172c03c9040SRui Ueyama 
173c03c9040SRui Ueyama   // If the existing symbol is weak, we should replace it.
174c03c9040SRui Ueyama   if (Existing.isWeak()) {
175c03c9040SRui Ueyama     DEBUG(dbgs() << "replacing existing weak symbol\n");
176c03c9040SRui Ueyama     return true;
177c03c9040SRui Ueyama   }
178c03c9040SRui Ueyama 
179c03c9040SRui Ueyama   // Neither symbol is week. They conflict.
180c03c9040SRui Ueyama   error("duplicate symbol: " + toString(Existing) + "\n>>> defined in " +
181c03c9040SRui Ueyama         toString(Existing.getFile()) + "\n>>> defined in " + toString(NewFile));
182c03c9040SRui Ueyama   return true;
183b8621596SSam Clegg }
18493e559b1SSam Clegg 
18593e559b1SSam Clegg Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
18693e559b1SSam Clegg                                         InputFile *F, InputFunction *Function) {
18793e559b1SSam Clegg   DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n");
18893e559b1SSam Clegg   Symbol *S;
18993e559b1SSam Clegg   bool WasInserted;
19093e559b1SSam Clegg   std::tie(S, WasInserted) = insert(Name);
191f60b0d5cSSam Clegg   if (WasInserted || shouldReplace(*S, F, Flags, Function, true))
19293e559b1SSam Clegg     replaceSymbol<DefinedFunction>(S, Name, Flags, F, Function);
19393e559b1SSam Clegg   return S;
19493e559b1SSam Clegg }
19593e559b1SSam Clegg 
196*00245539SSam Clegg Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
19793e559b1SSam Clegg                                       InputFile *F, InputSegment *Segment,
19893e559b1SSam Clegg                                       uint32_t Address) {
199*00245539SSam Clegg   DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address << "\n");
20093e559b1SSam Clegg   Symbol *S;
20193e559b1SSam Clegg   bool WasInserted;
20293e559b1SSam Clegg   std::tie(S, WasInserted) = insert(Name);
203f60b0d5cSSam Clegg   if (WasInserted || shouldReplace(*S, F, Flags, Segment, false))
204*00245539SSam Clegg     replaceSymbol<DefinedData>(S, Name, Flags, F, Segment, Address);
205c94d393aSSam Clegg   return S;
206c94d393aSSam Clegg }
207c94d393aSSam Clegg 
20820db381bSSam Clegg Symbol *SymbolTable::addUndefined(StringRef Name, Symbol::Kind Kind,
20920db381bSSam Clegg                                   uint32_t Flags, InputFile *F,
2108d146bbcSSam Clegg                                   const WasmSignature *Type) {
21120db381bSSam Clegg   DEBUG(dbgs() << "addUndefined: " << Name << "\n");
212c03c9040SRui Ueyama 
213c94d393aSSam Clegg   Symbol *S;
214c94d393aSSam Clegg   bool WasInserted;
21520db381bSSam Clegg   std::tie(S, WasInserted) = insert(Name);
216c03c9040SRui Ueyama 
217dfb0b2c7SSam Clegg   bool IsFunction = Kind == Symbol::UndefinedFunctionKind;
218c94d393aSSam Clegg   if (WasInserted) {
219dfb0b2c7SSam Clegg     if (IsFunction)
220dfb0b2c7SSam Clegg       replaceSymbol<UndefinedFunction>(S, Name, Flags, F, Type);
221dfb0b2c7SSam Clegg     else
222*00245539SSam Clegg       replaceSymbol<UndefinedData>(S, Name, Flags, F);
223c03c9040SRui Ueyama     return S;
224c03c9040SRui Ueyama   }
225c03c9040SRui Ueyama 
226c03c9040SRui Ueyama   if (auto *Lazy = dyn_cast<LazySymbol>(S)) {
227c94d393aSSam Clegg     DEBUG(dbgs() << "resolved by existing lazy\n");
228c03c9040SRui Ueyama     cast<ArchiveFile>(Lazy->getFile())->addMember(&Lazy->getArchiveSymbol());
229c03c9040SRui Ueyama     return S;
230c03c9040SRui Ueyama   }
231c03c9040SRui Ueyama 
232c03c9040SRui Ueyama   if (S->isDefined()) {
233c94d393aSSam Clegg     DEBUG(dbgs() << "resolved by existing\n");
234dfb0b2c7SSam Clegg     checkSymbolTypes(*S, *F, IsFunction, Type);
235c94d393aSSam Clegg   }
236c94d393aSSam Clegg   return S;
237c94d393aSSam Clegg }
238c94d393aSSam Clegg 
239c94d393aSSam Clegg void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) {
240a681a116SSam Clegg   DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
241c94d393aSSam Clegg   StringRef Name = Sym->getName();
242c03c9040SRui Ueyama 
243c94d393aSSam Clegg   Symbol *S;
244c94d393aSSam Clegg   bool WasInserted;
245c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
246c03c9040SRui Ueyama 
247c94d393aSSam Clegg   if (WasInserted) {
248dfb0b2c7SSam Clegg     replaceSymbol<LazySymbol>(S, Name, F, *Sym);
249c03c9040SRui Ueyama     return;
250c03c9040SRui Ueyama   }
251c03c9040SRui Ueyama 
252c03c9040SRui Ueyama   // If there is an existing undefined symbol, load a new one from the archive.
253c03c9040SRui Ueyama   if (S->isUndefined()) {
254c94d393aSSam Clegg     DEBUG(dbgs() << "replacing existing undefined\n");
255c94d393aSSam Clegg     F->addMember(Sym);
256c94d393aSSam Clegg   }
257c94d393aSSam Clegg }
258e0f6fcd0SSam Clegg 
259e0f6fcd0SSam Clegg bool SymbolTable::addComdat(StringRef Name, ObjFile *F) {
260e0f6fcd0SSam Clegg   DEBUG(dbgs() << "addComdat: " << Name << "\n");
261e0f6fcd0SSam Clegg   ObjFile *&File = ComdatMap[CachedHashStringRef(Name)];
262e0f6fcd0SSam Clegg   if (File) {
263e0f6fcd0SSam Clegg     DEBUG(dbgs() << "COMDAT already defined\n");
264e0f6fcd0SSam Clegg     return false;
265e0f6fcd0SSam Clegg   }
266e0f6fcd0SSam Clegg   File = F;
267e0f6fcd0SSam Clegg   return true;
268e0f6fcd0SSam Clegg }
269e0f6fcd0SSam Clegg 
270e0f6fcd0SSam Clegg ObjFile *SymbolTable::findComdat(StringRef Name) const {
271e0f6fcd0SSam Clegg   auto It = ComdatMap.find(CachedHashStringRef(Name));
272e0f6fcd0SSam Clegg   return It == ComdatMap.end() ? nullptr : It->second;
273e0f6fcd0SSam Clegg }
274