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(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 
118   const WasmSignature *OldSig = ExistingFunction->getFunctionType();
119   if (OldSig && NewSig && *NewSig != *OldSig) {
120     // Don't generate more than one warning per symbol.
121     if (Existing->SignatureMismatch)
122       return;
123     Existing->SignatureMismatch = true;
124 
125     std::string msg = ("function signature mismatch: " + Existing->getName() +
126                        "\n>>> defined as " + toString(*OldSig) + " in " +
127                        toString(Existing->getFile()) + "\n>>> defined as " +
128                        toString(*NewSig) + " in " + toString(File))
129                           .str();
130     // A function signature mismatch is only really problem if the mismatched
131     // symbol is included in the final output, and gc-sections can remove the
132     // offending uses.  Therefore we delay reporting this as an error when
133     // section GC is enabled.
134     if (Config->GcSections)
135       warn(msg);
136     else
137       error(msg);
138   }
139 }
140 
141 // Check the type of new symbol matches that of the symbol is replacing.
142 // For functions this can also involve verifying that the signatures match.
143 static void checkGlobalType(const Symbol *Existing, const InputFile *File,
144                             const WasmGlobalType *NewType) {
145   if (!isa<GlobalSymbol>(Existing)) {
146     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
147     return;
148   }
149 
150   const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
151   if (*NewType != *OldType) {
152     error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
153           toString(*OldType) + " in " + toString(Existing->getFile()) +
154           "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
155   }
156 }
157 
158 static void checkDataType(const Symbol *Existing, const InputFile *File) {
159   if (!isa<DataSymbol>(Existing))
160     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
161 }
162 
163 DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
164                                                    uint32_t Flags,
165                                                    InputFunction *Function) {
166   LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
167   assert(!find(Name));
168   SyntheticFunctions.emplace_back(Function);
169   return replaceSymbol<DefinedFunction>(insert(Name).first, Name, Flags,
170                                         nullptr, Function);
171 }
172 
173 DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
174                                                  uint32_t Flags) {
175   LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
176   assert(!find(Name));
177   return replaceSymbol<DefinedData>(insert(Name).first, Name, Flags);
178 }
179 
180 DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
181                                                InputGlobal *Global) {
182   LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
183                     << "\n");
184   assert(!find(Name));
185   SyntheticGlobals.emplace_back(Global);
186   return replaceSymbol<DefinedGlobal>(insert(Name).first, Name, Flags, nullptr,
187                                       Global);
188 }
189 
190 static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
191                           uint32_t NewFlags) {
192   // If existing symbol is undefined, replace it.
193   if (!Existing->isDefined()) {
194     LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
195                       << Existing->getName() << "\n");
196     return true;
197   }
198 
199   // Now we have two defined symbols. If the new one is weak, we can ignore it.
200   if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
201     LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
202     return false;
203   }
204 
205   // If the existing symbol is weak, we should replace it.
206   if (Existing->isWeak()) {
207     LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
208     return true;
209   }
210 
211   // Neither symbol is week. They conflict.
212   error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
213         toString(Existing->getFile()) + "\n>>> defined in " +
214         toString(NewFile));
215   return true;
216 }
217 
218 Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
219                                         InputFile *File,
220                                         InputFunction *Function) {
221   LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n");
222   Symbol *S;
223   bool WasInserted;
224   std::tie(S, WasInserted) = insert(Name);
225 
226   if (!File || File->kind() == InputFile::ObjectKind)
227     S->IsUsedInRegularObj = true;
228 
229   if (WasInserted || S->isLazy()) {
230     replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
231     return S;
232   }
233 
234   if (Function)
235     checkFunctionType(S, File, &Function->Signature);
236 
237   if (shouldReplace(S, File, Flags))
238     replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
239   return S;
240 }
241 
242 Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
243                                     InputFile *File, InputSegment *Segment,
244                                     uint32_t Address, uint32_t Size) {
245   LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
246                     << "\n");
247   Symbol *S;
248   bool WasInserted;
249   std::tie(S, WasInserted) = insert(Name);
250 
251   if (!File || File->kind() == InputFile::ObjectKind)
252     S->IsUsedInRegularObj = true;
253 
254   if (WasInserted || S->isLazy()) {
255     replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
256     return S;
257   }
258 
259   checkDataType(S, File);
260 
261   if (shouldReplace(S, File, Flags))
262     replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
263   return S;
264 }
265 
266 Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
267                                       InputFile *File, InputGlobal *Global) {
268   LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
269   Symbol *S;
270   bool WasInserted;
271   std::tie(S, WasInserted) = insert(Name);
272 
273   if (!File || File->kind() == InputFile::ObjectKind)
274     S->IsUsedInRegularObj = true;
275 
276   if (WasInserted || S->isLazy()) {
277     replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
278     return S;
279   }
280 
281   checkGlobalType(S, File, &Global->getType());
282 
283   if (shouldReplace(S, File, Flags))
284     replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
285   return S;
286 }
287 
288 Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags,
289                                           InputFile *File,
290                                           const WasmSignature *Sig) {
291   LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n");
292 
293   Symbol *S;
294   bool WasInserted;
295   std::tie(S, WasInserted) = insert(Name);
296 
297   if (!File || File->kind() == InputFile::ObjectKind)
298     S->IsUsedInRegularObj = true;
299 
300   if (WasInserted)
301     replaceSymbol<UndefinedFunction>(S, Name, Flags, File, Sig);
302   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
303     Lazy->fetch();
304   else if (S->isDefined())
305     checkFunctionType(S, File, Sig);
306   return S;
307 }
308 
309 Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
310                                       InputFile *File) {
311   LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
312 
313   Symbol *S;
314   bool WasInserted;
315   std::tie(S, WasInserted) = insert(Name);
316 
317   if (WasInserted)
318     replaceSymbol<UndefinedData>(S, Name, Flags, File);
319   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
320     Lazy->fetch();
321   else if (S->isDefined())
322     checkDataType(S, File);
323   return S;
324 }
325 
326 Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, uint32_t Flags,
327                                         InputFile *File,
328                                         const WasmGlobalType *Type) {
329   LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
330 
331   Symbol *S;
332   bool WasInserted;
333   std::tie(S, WasInserted) = insert(Name);
334 
335   if (!File || File->kind() == InputFile::ObjectKind)
336     S->IsUsedInRegularObj = true;
337 
338   if (WasInserted)
339     replaceSymbol<UndefinedGlobal>(S, Name, Flags, File, Type);
340   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
341     Lazy->fetch();
342   else if (S->isDefined())
343     checkGlobalType(S, File, Type);
344   return S;
345 }
346 
347 void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
348   LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
349   StringRef Name = Sym->getName();
350 
351   Symbol *S;
352   bool WasInserted;
353   std::tie(S, WasInserted) = insert(Name);
354 
355   if (WasInserted) {
356     replaceSymbol<LazySymbol>(S, Name, File, *Sym);
357     return;
358   }
359 
360   // If there is an existing undefined symbol, load a new one from the archive.
361   if (S->isUndefined()) {
362     LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
363     File->addMember(Sym);
364   }
365 }
366 
367 bool SymbolTable::addComdat(StringRef Name) {
368   return Comdats.insert(CachedHashStringRef(Name)).second;
369 }
370