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