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 "Memory.h"
14c94d393aSSam Clegg #include "Strings.h"
15c94d393aSSam Clegg #include "lld/Common/ErrorHandler.h"
16c94d393aSSam Clegg 
17c94d393aSSam Clegg #include <unordered_set>
18c94d393aSSam Clegg 
19c94d393aSSam Clegg #define DEBUG_TYPE "lld"
20c94d393aSSam Clegg 
21c94d393aSSam Clegg using namespace llvm;
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() {
36c94d393aSSam Clegg   std::unordered_set<Symbol *> Undefs;
37*a80d94d5SSam Clegg   for (auto &I : SymMap) {
38c94d393aSSam Clegg     Symbol *Sym = I.second;
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) {
59*a80d94d5SSam Clegg   auto It = SymMap.find(CachedHashStringRef(Name));
60*a80d94d5SSam 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) {
66*a80d94d5SSam Clegg   Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
67c94d393aSSam Clegg   if (Sym)
68c94d393aSSam Clegg     return {Sym, false};
69c94d393aSSam Clegg   Sym = make<Symbol>(Name, false);
70c94d393aSSam Clegg   return {Sym, true};
71c94d393aSSam Clegg }
72c94d393aSSam Clegg 
73c94d393aSSam Clegg void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
74c94d393aSSam Clegg   error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
75c94d393aSSam Clegg         toString(Existing->getFile()) + "\n>>> defined in " +
76e2ed092eSSam Clegg         toString(NewFile));
77c94d393aSSam Clegg }
78c94d393aSSam Clegg 
79c94d393aSSam Clegg static void checkSymbolTypes(Symbol *Existing, InputFile *F,
80c94d393aSSam Clegg                              const WasmSymbol *New) {
81c94d393aSSam Clegg   if (Existing->isLazy())
82c94d393aSSam Clegg     return;
83c94d393aSSam Clegg 
84c94d393aSSam Clegg   bool NewIsFunction = New->Type == WasmSymbol::SymbolType::FUNCTION_EXPORT ||
85c94d393aSSam Clegg                        New->Type == WasmSymbol::SymbolType::FUNCTION_IMPORT;
86c94d393aSSam Clegg   if (Existing->isFunction() == NewIsFunction)
87c94d393aSSam Clegg     return;
88c94d393aSSam Clegg 
89c94d393aSSam Clegg   error("symbol type mismatch: " + New->Name + "\n>>> defined as " +
90e2ed092eSSam Clegg         (Existing->isFunction() ? "Function" : "Global") + " in " +
91e2ed092eSSam Clegg         toString(Existing->getFile()) + "\n>>> defined as " +
92e2ed092eSSam Clegg         (NewIsFunction ? "Function" : "Global") + " in " + F->getName());
93c94d393aSSam Clegg }
94c94d393aSSam Clegg 
95c94d393aSSam Clegg Symbol *SymbolTable::addDefinedGlobal(StringRef Name) {
96c94d393aSSam Clegg   DEBUG(dbgs() << "addDefinedGlobal: " << Name << "\n");
97c94d393aSSam Clegg   Symbol *S;
98c94d393aSSam Clegg   bool WasInserted;
99c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
100c94d393aSSam Clegg   if (WasInserted)
101c94d393aSSam Clegg     S->update(Symbol::DefinedGlobalKind);
102c94d393aSSam Clegg   else if (!S->isGlobal())
103c94d393aSSam Clegg     error("symbol type mismatch: " + Name);
104c94d393aSSam Clegg   return S;
105c94d393aSSam Clegg }
106c94d393aSSam Clegg 
107c94d393aSSam Clegg Symbol *SymbolTable::addDefined(InputFile *F, const WasmSymbol *Sym,
108c94d393aSSam Clegg                                 const InputSegment *Segment) {
109c94d393aSSam Clegg   DEBUG(dbgs() << "addDefined: " << Sym->Name << "\n");
110c94d393aSSam Clegg   Symbol *S;
111c94d393aSSam Clegg   bool WasInserted;
112c94d393aSSam Clegg   Symbol::Kind Kind = Symbol::DefinedFunctionKind;
113c94d393aSSam Clegg   if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_EXPORT)
114c94d393aSSam Clegg     Kind = Symbol::DefinedGlobalKind;
115c94d393aSSam Clegg 
116c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Sym->Name);
117c94d393aSSam Clegg   if (WasInserted) {
118c94d393aSSam Clegg     S->update(Kind, F, Sym, Segment);
119c94d393aSSam Clegg   } else if (!S->isDefined()) {
120c94d393aSSam Clegg     // The existing symbol table entry is undefined. The new symbol replaces
121c94d393aSSam Clegg     // it
122c94d393aSSam Clegg     DEBUG(dbgs() << "resolving existing undefined symbol: " << Sym->Name
123c94d393aSSam Clegg                  << "\n");
124c94d393aSSam Clegg     checkSymbolTypes(S, F, Sym);
125c94d393aSSam Clegg     S->update(Kind, F, Sym, Segment);
126c94d393aSSam Clegg   } else if (Sym->isWeak()) {
127c94d393aSSam Clegg     // the new symbol is weak we can ignore it
128c94d393aSSam Clegg     DEBUG(dbgs() << "existing symbol takes precensence\n");
129c94d393aSSam Clegg   } else if (S->isWeak()) {
130c94d393aSSam Clegg     // the new symbol is not weak and the existing symbol is, so we replace
131c94d393aSSam Clegg     // it
132c94d393aSSam Clegg     DEBUG(dbgs() << "replacing existing weak symbol\n");
133c94d393aSSam Clegg     S->update(Kind, F, Sym, Segment);
134c94d393aSSam Clegg   } else {
135c94d393aSSam Clegg     // niether symbol is week. They conflict.
136c94d393aSSam Clegg     reportDuplicate(S, F);
137c94d393aSSam Clegg   }
138c94d393aSSam Clegg   return S;
139c94d393aSSam Clegg }
140c94d393aSSam Clegg 
141c94d393aSSam Clegg Symbol *SymbolTable::addUndefinedFunction(StringRef Name) {
142c94d393aSSam Clegg   Symbol *S;
143c94d393aSSam Clegg   bool WasInserted;
144c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
145c94d393aSSam Clegg   if (WasInserted)
146c94d393aSSam Clegg     S->update(Symbol::UndefinedFunctionKind);
147c94d393aSSam Clegg   else if (!S->isFunction())
148c94d393aSSam Clegg     error("symbol type mismatch: " + Name);
149c94d393aSSam Clegg   return S;
150c94d393aSSam Clegg }
151c94d393aSSam Clegg 
152c94d393aSSam Clegg Symbol *SymbolTable::addUndefined(InputFile *F, const WasmSymbol *Sym) {
153c94d393aSSam Clegg   DEBUG(dbgs() << "addUndefined: " << displayName(Sym->Name) << "\n");
154c94d393aSSam Clegg   Symbol *S;
155c94d393aSSam Clegg   bool WasInserted;
156c94d393aSSam Clegg   Symbol::Kind Kind = Symbol::UndefinedFunctionKind;
157c94d393aSSam Clegg   if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_IMPORT)
158c94d393aSSam Clegg     Kind = Symbol::UndefinedGlobalKind;
159c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Sym->Name);
160c94d393aSSam Clegg   if (WasInserted) {
161c94d393aSSam Clegg     S->update(Kind, F, Sym);
162c94d393aSSam Clegg   } else if (S->isLazy()) {
163c94d393aSSam Clegg     DEBUG(dbgs() << "resolved by existing lazy\n");
164c94d393aSSam Clegg     auto *AF = cast<ArchiveFile>(S->getFile());
165c94d393aSSam Clegg     AF->addMember(&S->getArchiveSymbol());
166c94d393aSSam Clegg   } else if (S->isDefined()) {
167c94d393aSSam Clegg     DEBUG(dbgs() << "resolved by existing\n");
168c94d393aSSam Clegg     checkSymbolTypes(S, F, Sym);
169c94d393aSSam Clegg   }
170c94d393aSSam Clegg   return S;
171c94d393aSSam Clegg }
172c94d393aSSam Clegg 
173c94d393aSSam Clegg void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) {
174c94d393aSSam Clegg   DEBUG(dbgs() << "addLazy: " << displayName(Sym->getName()) << "\n");
175c94d393aSSam Clegg   StringRef Name = Sym->getName();
176c94d393aSSam Clegg   Symbol *S;
177c94d393aSSam Clegg   bool WasInserted;
178c94d393aSSam Clegg   std::tie(S, WasInserted) = insert(Name);
179c94d393aSSam Clegg   if (WasInserted) {
180c94d393aSSam Clegg     S->update(Symbol::LazyKind, F);
181c94d393aSSam Clegg     S->setArchiveSymbol(*Sym);
182c94d393aSSam Clegg   } else if (S->isUndefined()) {
183c94d393aSSam Clegg     // There is an existing undefined symbol.  The can load from the
184c94d393aSSam Clegg     // archive.
185c94d393aSSam Clegg     DEBUG(dbgs() << "replacing existing undefined\n");
186c94d393aSSam Clegg     F->addMember(Sym);
187c94d393aSSam Clegg   }
188c94d393aSSam Clegg }
189