1 //===- SymbolTable.cpp ----------------------------------------------------===//
2 //
3 //                             The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "SymbolTable.h"
11 #include "Config.h"
12 #include "InputChunks.h"
13 #include "InputGlobal.h"
14 #include "WriterUtils.h"
15 #include "lld/Common/ErrorHandler.h"
16 #include "lld/Common/Memory.h"
17 #include "llvm/ADT/SetVector.h"
18 
19 #define DEBUG_TYPE "lld"
20 
21 using namespace llvm;
22 using namespace llvm::wasm;
23 using namespace lld;
24 using namespace lld::wasm;
25 
26 SymbolTable *lld::wasm::Symtab;
27 
28 void SymbolTable::addFile(InputFile *File) {
29   log("Processing: " + toString(File));
30   File->parse();
31 
32   // LLVM bitcode file
33   if (auto *F = dyn_cast<BitcodeFile>(File))
34     BitcodeFiles.push_back(F);
35   else if (auto *F = dyn_cast<ObjFile>(File))
36     ObjectFiles.push_back(F);
37 }
38 
39 // This function is where all the optimizations of link-time
40 // optimization happens. When LTO is in use, some input files are
41 // not in native object file format but in the LLVM bitcode format.
42 // This function compiles bitcode files into a few big native files
43 // using LLVM functions and replaces bitcode symbols with the results.
44 // Because all bitcode files that the program consists of are passed
45 // to the compiler at once, it can do whole-program optimization.
46 void SymbolTable::addCombinedLTOObject() {
47   if (BitcodeFiles.empty())
48     return;
49 
50   // Compile bitcode files and replace bitcode symbols.
51   LTO.reset(new BitcodeCompiler);
52   for (BitcodeFile *F : BitcodeFiles)
53     LTO->add(*F);
54 
55   for (StringRef Filename : LTO->compile()) {
56     auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"));
57     Obj->parse();
58     ObjectFiles.push_back(Obj);
59   }
60 }
61 
62 void SymbolTable::reportRemainingUndefines() {
63   SetVector<Symbol *> Undefs;
64   for (Symbol *Sym : SymVector) {
65     if (!Sym->isUndefined() || Sym->isWeak())
66       continue;
67     if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
68       continue;
69     if (!Sym->IsUsedInRegularObj)
70       continue;
71     Undefs.insert(Sym);
72   }
73 
74   if (Undefs.empty())
75     return;
76 
77   for (ObjFile *File : ObjectFiles)
78     for (Symbol *Sym : File->getSymbols())
79       if (Undefs.count(Sym))
80         error(toString(File) + ": undefined symbol: " + toString(*Sym));
81 
82   for (Symbol *Sym : Undefs)
83     if (!Sym->getFile())
84       error("undefined symbol: " + toString(*Sym));
85 }
86 
87 Symbol *SymbolTable::find(StringRef Name) {
88   return SymMap.lookup(CachedHashStringRef(Name));
89 }
90 
91 std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
92   Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
93   if (Sym)
94     return {Sym, false};
95   Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
96   Sym->IsUsedInRegularObj = false;
97   SymVector.emplace_back(Sym);
98   return {Sym, true};
99 }
100 
101 static void reportTypeError(const Symbol *Existing, const InputFile *File,
102                             llvm::wasm::WasmSymbolType Type) {
103   error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
104         toString(Existing->getWasmType()) + " in " +
105         toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
106         " in " + toString(File));
107 }
108 
109 static void checkFunctionType(const Symbol *Existing, const InputFile *File,
110                               const WasmSignature *NewSig) {
111   auto ExistingFunction = dyn_cast<FunctionSymbol>(Existing);
112   if (!ExistingFunction) {
113     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_FUNCTION);
114     return;
115   }
116 
117   const WasmSignature *OldSig = ExistingFunction->getFunctionType();
118   if (OldSig && NewSig && *NewSig != *OldSig) {
119     warn("function signature mismatch: " + Existing->getName() +
120          "\n>>> defined as " + toString(*OldSig) + " in " +
121          toString(Existing->getFile()) + "\n>>> defined as " +
122          toString(*NewSig) + " in " + toString(File));
123   }
124 }
125 
126 // Check the type of new symbol matches that of the symbol is replacing.
127 // For functions this can also involve verifying that the signatures match.
128 static void checkGlobalType(const Symbol *Existing, const InputFile *File,
129                             const WasmGlobalType *NewType) {
130   if (!isa<GlobalSymbol>(Existing)) {
131     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
132     return;
133   }
134 
135   const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
136   if (*NewType != *OldType) {
137     error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
138           toString(*OldType) + " in " + toString(Existing->getFile()) +
139           "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
140   }
141 }
142 
143 static void checkDataType(const Symbol *Existing, const InputFile *File) {
144   if (!isa<DataSymbol>(Existing))
145     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
146 }
147 
148 DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
149                                                    uint32_t Flags,
150                                                    InputFunction *Function) {
151   LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
152   assert(!find(Name));
153   SyntheticFunctions.emplace_back(Function);
154   return replaceSymbol<DefinedFunction>(insert(Name).first, Name, Flags,
155                                         nullptr, Function);
156 }
157 
158 DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
159                                                  uint32_t Flags) {
160   LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
161   assert(!find(Name));
162   return replaceSymbol<DefinedData>(insert(Name).first, Name, Flags);
163 }
164 
165 DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
166                                                InputGlobal *Global) {
167   LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
168                     << "\n");
169   assert(!find(Name));
170   SyntheticGlobals.emplace_back(Global);
171   return replaceSymbol<DefinedGlobal>(insert(Name).first, Name, Flags, nullptr,
172                                       Global);
173 }
174 
175 static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
176                           uint32_t NewFlags) {
177   // If existing symbol is undefined, replace it.
178   if (!Existing->isDefined()) {
179     LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
180                       << Existing->getName() << "\n");
181     return true;
182   }
183 
184   // Now we have two defined symbols. If the new one is weak, we can ignore it.
185   if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
186     LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
187     return false;
188   }
189 
190   // If the existing symbol is weak, we should replace it.
191   if (Existing->isWeak()) {
192     LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
193     return true;
194   }
195 
196   // Neither symbol is week. They conflict.
197   error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
198         toString(Existing->getFile()) + "\n>>> defined in " +
199         toString(NewFile));
200   return true;
201 }
202 
203 Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
204                                         InputFile *File,
205                                         InputFunction *Function) {
206   LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n");
207   Symbol *S;
208   bool WasInserted;
209   std::tie(S, WasInserted) = insert(Name);
210 
211   if (!File || File->kind() == InputFile::ObjectKind)
212     S->IsUsedInRegularObj = true;
213 
214   if (WasInserted || S->isLazy()) {
215     replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
216     return S;
217   }
218 
219   if (Function)
220     checkFunctionType(S, File, &Function->Signature);
221 
222   if (shouldReplace(S, File, Flags))
223     replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
224   return S;
225 }
226 
227 Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
228                                     InputFile *File, InputSegment *Segment,
229                                     uint32_t Address, uint32_t Size) {
230   LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
231                     << "\n");
232   Symbol *S;
233   bool WasInserted;
234   std::tie(S, WasInserted) = insert(Name);
235 
236   if (!File || File->kind() == InputFile::ObjectKind)
237     S->IsUsedInRegularObj = true;
238 
239   if (WasInserted || S->isLazy()) {
240     replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
241     return S;
242   }
243 
244   checkDataType(S, File);
245 
246   if (shouldReplace(S, File, Flags))
247     replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
248   return S;
249 }
250 
251 Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
252                                       InputFile *File, InputGlobal *Global) {
253   LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
254   Symbol *S;
255   bool WasInserted;
256   std::tie(S, WasInserted) = insert(Name);
257 
258   if (!File || File->kind() == InputFile::ObjectKind)
259     S->IsUsedInRegularObj = true;
260 
261   if (WasInserted || S->isLazy()) {
262     replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
263     return S;
264   }
265 
266   checkGlobalType(S, File, &Global->getType());
267 
268   if (shouldReplace(S, File, Flags))
269     replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
270   return S;
271 }
272 
273 Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags,
274                                           InputFile *File,
275                                           const WasmSignature *Sig) {
276   LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n");
277 
278   Symbol *S;
279   bool WasInserted;
280   std::tie(S, WasInserted) = insert(Name);
281 
282   if (!File || File->kind() == InputFile::ObjectKind)
283     S->IsUsedInRegularObj = true;
284 
285   if (WasInserted)
286     replaceSymbol<UndefinedFunction>(S, Name, Flags, File, Sig);
287   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
288     Lazy->fetch();
289   else if (S->isDefined())
290     checkFunctionType(S, File, Sig);
291   return S;
292 }
293 
294 Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
295                                       InputFile *File) {
296   LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
297 
298   Symbol *S;
299   bool WasInserted;
300   std::tie(S, WasInserted) = insert(Name);
301 
302   if (WasInserted)
303     replaceSymbol<UndefinedData>(S, Name, Flags, File);
304   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
305     Lazy->fetch();
306   else if (S->isDefined())
307     checkDataType(S, File);
308   return S;
309 }
310 
311 Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, uint32_t Flags,
312                                         InputFile *File,
313                                         const WasmGlobalType *Type) {
314   LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
315 
316   Symbol *S;
317   bool WasInserted;
318   std::tie(S, WasInserted) = insert(Name);
319 
320   if (!File || File->kind() == InputFile::ObjectKind)
321     S->IsUsedInRegularObj = true;
322 
323   if (WasInserted)
324     replaceSymbol<UndefinedGlobal>(S, Name, Flags, File, Type);
325   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
326     Lazy->fetch();
327   else if (S->isDefined())
328     checkGlobalType(S, File, Type);
329   return S;
330 }
331 
332 void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
333   LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
334   StringRef Name = Sym->getName();
335 
336   Symbol *S;
337   bool WasInserted;
338   std::tie(S, WasInserted) = insert(Name);
339 
340   if (WasInserted) {
341     replaceSymbol<LazySymbol>(S, Name, File, *Sym);
342     return;
343   }
344 
345   // If there is an existing undefined symbol, load a new one from the archive.
346   if (S->isUndefined()) {
347     LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
348     File->addMember(Sym);
349   }
350 }
351 
352 bool SymbolTable::addComdat(StringRef Name) {
353   return Comdats.insert(CachedHashStringRef(Name)).second;
354 }
355