blob: 1e7357d5d608fa6ff12e5b6c832d0c16595d1b81 [file] [log] [blame]
Sam Cleggc94d3932017-11-17 18:14:09 +00001//===- SymbolTable.cpp ----------------------------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Sam Cleggc94d3932017-11-17 18:14:09 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "SymbolTable.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000010#include "Config.h"
Sam Clegg5fa274b2018-01-10 01:13:34 +000011#include "InputChunks.h"
Heejin Ahne915a712018-12-08 06:17:43 +000012#include "InputEvent.h"
Sam Clegg93102972018-02-23 05:08:53 +000013#include "InputGlobal.h"
Sam Cleggb8621592017-11-30 01:40:08 +000014#include "WriterUtils.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000015#include "lld/Common/ErrorHandler.h"
Rui Ueyama2017d522017-11-28 20:39:17 +000016#include "lld/Common/Memory.h"
Rui Ueyama7d67dd12018-02-13 22:30:52 +000017#include "llvm/ADT/SetVector.h"
Sam Cleggc94d3932017-11-17 18:14:09 +000018
19#define DEBUG_TYPE "lld"
20
21using namespace llvm;
Sam Clegg20db3812018-01-10 00:52:20 +000022using namespace llvm::wasm;
Sam Clegg45218f42018-11-27 01:08:16 +000023using namespace llvm::object;
Sam Cleggc94d3932017-11-17 18:14:09 +000024using namespace lld;
25using namespace lld::wasm;
26
27SymbolTable *lld::wasm::Symtab;
28
29void SymbolTable::addFile(InputFile *File) {
30 log("Processing: " + toString(File));
Sam Clegg1f3f7742019-02-06 02:35:18 +000031 if (Config->Trace)
32 message(toString(File));
Sam Cleggc94d3932017-11-17 18:14:09 +000033 File->parse();
34
Sam Cleggc729c1b2018-05-30 18:07:52 +000035 // LLVM bitcode file
36 if (auto *F = dyn_cast<BitcodeFile>(File))
37 BitcodeFiles.push_back(F);
38 else if (auto *F = dyn_cast<ObjFile>(File))
Sam Cleggc94d3932017-11-17 18:14:09 +000039 ObjectFiles.push_back(F);
40}
41
Sam Cleggc729c1b2018-05-30 18:07:52 +000042// This function is where all the optimizations of link-time
43// optimization happens. When LTO is in use, some input files are
44// not in native object file format but in the LLVM bitcode format.
45// This function compiles bitcode files into a few big native files
46// using LLVM functions and replaces bitcode symbols with the results.
47// Because all bitcode files that the program consists of are passed
48// to the compiler at once, it can do whole-program optimization.
49void SymbolTable::addCombinedLTOObject() {
50 if (BitcodeFiles.empty())
51 return;
52
53 // Compile bitcode files and replace bitcode symbols.
54 LTO.reset(new BitcodeCompiler);
55 for (BitcodeFile *F : BitcodeFiles)
56 LTO->add(*F);
57
58 for (StringRef Filename : LTO->compile()) {
59 auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"));
60 Obj->parse();
61 ObjectFiles.push_back(Obj);
62 }
63}
64
Sam Cleggc94d3932017-11-17 18:14:09 +000065void SymbolTable::reportRemainingUndefines() {
Sam Clegg74fe0ba2017-12-07 01:51:24 +000066 for (Symbol *Sym : SymVector) {
Sam Cleggc729c1b2018-05-30 18:07:52 +000067 if (!Sym->isUndefined() || Sym->isWeak())
68 continue;
69 if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
70 continue;
71 if (!Sym->IsUsedInRegularObj)
72 continue;
Sam Clegg47e2b6b2018-08-04 00:04:06 +000073 error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym));
Sam Cleggc94d3932017-11-17 18:14:09 +000074 }
Sam Cleggc94d3932017-11-17 18:14:09 +000075}
76
77Symbol *SymbolTable::find(StringRef Name) {
Sam Clegg1f3f7742019-02-06 02:35:18 +000078 auto It = SymMap.find(CachedHashStringRef(Name));
79 if (It == SymMap.end() || It->second == -1)
80 return nullptr;
81 return SymVector[It->second];
82}
83
Sam Clegg6540e572019-02-20 23:19:31 +000084void SymbolTable::replace(StringRef Name, Symbol* Sym) {
85 auto It = SymMap.find(CachedHashStringRef(Name));
86 SymVector[It->second] = Sym;
87}
88
Sam Clegg1f3f7742019-02-06 02:35:18 +000089std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) {
90 bool Trace = false;
91 auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()});
92 int &SymIndex = P.first->second;
93 bool IsNew = P.second;
94 if (SymIndex == -1) {
95 SymIndex = SymVector.size();
96 Trace = true;
97 IsNew = true;
98 }
99
100 if (!IsNew)
101 return {SymVector[SymIndex], false};
102
103 Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
104 Sym->IsUsedInRegularObj = false;
105 Sym->Traced = Trace;
106 SymVector.emplace_back(Sym);
107 return {Sym, true};
Sam Cleggc94d3932017-11-17 18:14:09 +0000108}
109
Sam Clegg230dc112019-02-07 22:42:16 +0000110std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name,
111 const InputFile *File) {
Sam Clegg1f3f7742019-02-06 02:35:18 +0000112 Symbol *S;
113 bool WasInserted;
114 std::tie(S, WasInserted) = insertName(Name);
115
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000116 if (!File || File->kind() == InputFile::ObjectKind)
Sam Clegg1f3f7742019-02-06 02:35:18 +0000117 S->IsUsedInRegularObj = true;
118
119 return {S, WasInserted};
Sam Cleggc94d3932017-11-17 18:14:09 +0000120}
121
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000122static void reportTypeError(const Symbol *Existing, const InputFile *File,
Sam Clegg3876d89a2018-05-14 22:42:33 +0000123 llvm::wasm::WasmSymbolType Type) {
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000124 error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
125 toString(Existing->getWasmType()) + " in " +
Sam Clegg3876d89a2018-05-14 22:42:33 +0000126 toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
127 " in " + toString(File));
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000128}
129
Heejin Ahn6f4286f2018-11-19 23:31:28 +0000130// Check the type of new symbol matches that of the symbol is replacing.
Sam Clegg6540e572019-02-20 23:19:31 +0000131// Returns true if the function types match, false is there is a singature
132// mismatch.
133bool signatureMatches(FunctionSymbol *Existing, const WasmSignature *NewSig) {
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000134 if (!NewSig)
Sam Clegg6540e572019-02-20 23:19:31 +0000135 return true;
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000136
Sam Clegg6540e572019-02-20 23:19:31 +0000137 const WasmSignature *OldSig = Existing->Signature;
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000138 if (!OldSig) {
Sam Clegg6540e572019-02-20 23:19:31 +0000139 Existing->Signature = NewSig;
140 return true;
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000141 }
142
Sam Clegg6540e572019-02-20 23:19:31 +0000143 return *NewSig == *OldSig;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000144}
145
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000146static void checkGlobalType(const Symbol *Existing, const InputFile *File,
147 const WasmGlobalType *NewType) {
148 if (!isa<GlobalSymbol>(Existing)) {
Sam Clegg3876d89a2018-05-14 22:42:33 +0000149 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
Sam Cleggb8621592017-11-30 01:40:08 +0000150 return;
151 }
152
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000153 const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
154 if (*NewType != *OldType) {
155 error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
156 toString(*OldType) + " in " + toString(Existing->getFile()) +
157 "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
Sam Clegg93102972018-02-23 05:08:53 +0000158 }
Sam Clegg24b3dcd2018-01-28 19:57:01 +0000159}
160
Heejin Ahne915a712018-12-08 06:17:43 +0000161static void checkEventType(const Symbol *Existing, const InputFile *File,
162 const WasmEventType *NewType,
163 const WasmSignature *NewSig) {
164 auto ExistingEvent = dyn_cast<EventSymbol>(Existing);
165 if (!isa<EventSymbol>(Existing)) {
166 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT);
167 return;
168 }
169
170 const WasmEventType *OldType = cast<EventSymbol>(Existing)->getEventType();
171 const WasmSignature *OldSig = ExistingEvent->Signature;
172 if (NewType->Attribute != OldType->Attribute)
173 error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " +
174 toString(*OldType) + " in " + toString(Existing->getFile()) +
175 "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
176 if (*NewSig != *OldSig)
177 warn("Event signature mismatch: " + Existing->getName() +
178 "\n>>> defined as " + toString(*OldSig) + " in " +
179 toString(Existing->getFile()) + "\n>>> defined as " +
180 toString(*NewSig) + " in " + toString(File));
181}
182
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000183static void checkDataType(const Symbol *Existing, const InputFile *File) {
184 if (!isa<DataSymbol>(Existing))
Sam Clegg3876d89a2018-05-14 22:42:33 +0000185 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000186}
187
Sam Cleggdfb0b2c2018-02-14 18:27:59 +0000188DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
Nicholas Wilsonebda41f2018-03-09 16:43:05 +0000189 uint32_t Flags,
190 InputFunction *Function) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000191 LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
Rui Ueyamab961abc2018-02-28 22:51:51 +0000192 assert(!find(Name));
Nicholas Wilsonebda41f2018-03-09 16:43:05 +0000193 SyntheticFunctions.emplace_back(Function);
Sam Cleggd15a41542019-03-08 21:10:48 +0000194 return replaceSymbol<DefinedFunction>(insertName(Name).first, Name,
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000195 Flags, nullptr, Function);
Sam Clegg50686852018-01-12 18:35:13 +0000196}
197
Sam Clegg00245532018-02-20 23:38:27 +0000198DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
199 uint32_t Flags) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000200 LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
Rui Ueyamab961abc2018-02-28 22:51:51 +0000201 assert(!find(Name));
Sam Cleggd15a41542019-03-08 21:10:48 +0000202 return replaceSymbol<DefinedData>(insertName(Name).first, Name, Flags);
Sam Cleggc94d3932017-11-17 18:14:09 +0000203}
204
Sam Clegg93102972018-02-23 05:08:53 +0000205DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
206 InputGlobal *Global) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000207 LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
208 << "\n");
Rui Ueyamab961abc2018-02-28 22:51:51 +0000209 assert(!find(Name));
Nicholas Wilsonebda41f2018-03-09 16:43:05 +0000210 SyntheticGlobals.emplace_back(Global);
Sam Cleggd15a41542019-03-08 21:10:48 +0000211 return replaceSymbol<DefinedGlobal>(insertName(Name).first, Name, Flags,
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000212 nullptr, Global);
Sam Clegg93102972018-02-23 05:08:53 +0000213}
214
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000215static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
216 uint32_t NewFlags) {
Rui Ueyamac03c9042018-02-20 21:08:47 +0000217 // If existing symbol is undefined, replace it.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000218 if (!Existing->isDefined()) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000219 LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
220 << Existing->getName() << "\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000221 return true;
222 }
223
224 // Now we have two defined symbols. If the new one is weak, we can ignore it.
225 if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000226 LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000227 return false;
228 }
229
230 // If the existing symbol is weak, we should replace it.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000231 if (Existing->isWeak()) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000232 LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000233 return true;
234 }
235
236 // Neither symbol is week. They conflict.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000237 error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
238 toString(Existing->getFile()) + "\n>>> defined in " +
239 toString(NewFile));
Rui Ueyamac03c9042018-02-20 21:08:47 +0000240 return true;
Sam Clegg93e559b2018-02-20 18:55:06 +0000241}
242
243Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000244 InputFile *File,
245 InputFunction *Function) {
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000246 LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " ["
247 << (Function ? toString(Function->Signature) : "none")
248 << "]\n");
Sam Clegg93e559b2018-02-20 18:55:06 +0000249 Symbol *S;
250 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000251 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000252
Sam Clegg6540e572019-02-20 23:19:31 +0000253 auto Replace = [&](Symbol* Sym) {
254 // If the new defined function doesn't have signture (i.e. bitcode
255 // functions) but the old symbol does, then preserve the old signature
256 const WasmSignature *OldSig = S->getSignature();
257 auto* NewSym = replaceSymbol<DefinedFunction>(Sym, Name, Flags, File, Function);
258 if (!NewSym->Signature)
259 NewSym->Signature = OldSig;
260 };
261
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000262 if (WasInserted || S->isLazy()) {
Sam Clegg6540e572019-02-20 23:19:31 +0000263 Replace(S);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000264 return S;
265 }
266
Sam Clegg6540e572019-02-20 23:19:31 +0000267 auto ExistingFunction = dyn_cast<FunctionSymbol>(S);
268 if (!ExistingFunction) {
269 reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION);
270 return S;
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000271 }
Sam Clegg6540e572019-02-20 23:19:31 +0000272
273 if (Function && !signatureMatches(ExistingFunction, &Function->Signature)) {
274 Symbol* Variant;
275 if (getFunctionVariant(S, &Function->Signature, File, &Variant))
276 // New variant, always replace
277 Replace(Variant);
278 else if (shouldReplace(S, File, Flags))
279 // Variant already exists, replace it after checking shouldReplace
280 Replace(Variant);
281
282 // This variant we found take the place in the symbol table as the primary
283 // variant.
284 replace(Name, Variant);
285 return Variant;
286 }
287
288 // Existing function with matching signature.
289 if (shouldReplace(S, File, Flags))
290 Replace(S);
291
Sam Clegg93e559b2018-02-20 18:55:06 +0000292 return S;
293}
294
Sam Clegg00245532018-02-20 23:38:27 +0000295Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000296 InputFile *File, InputSegment *Segment,
Sam Clegg93102972018-02-23 05:08:53 +0000297 uint32_t Address, uint32_t Size) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000298 LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
299 << "\n");
Sam Clegg93e559b2018-02-20 18:55:06 +0000300 Symbol *S;
301 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000302 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000303
Sam Clegg6540e572019-02-20 23:19:31 +0000304 auto Replace = [&]() {
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000305 replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
Sam Clegg6540e572019-02-20 23:19:31 +0000306 };
307
308 if (WasInserted || S->isLazy()) {
309 Replace();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000310 return S;
311 }
312
313 checkDataType(S, File);
314
315 if (shouldReplace(S, File, Flags))
Sam Clegg6540e572019-02-20 23:19:31 +0000316 Replace();
Sam Cleggc94d3932017-11-17 18:14:09 +0000317 return S;
318}
319
Sam Clegg93102972018-02-23 05:08:53 +0000320Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000321 InputFile *File, InputGlobal *Global) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000322 LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000323
Sam Clegg93102972018-02-23 05:08:53 +0000324 Symbol *S;
325 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000326 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000327
Sam Clegg6540e572019-02-20 23:19:31 +0000328 auto Replace = [&]() {
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000329 replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
Sam Clegg6540e572019-02-20 23:19:31 +0000330 };
331
332 if (WasInserted || S->isLazy()) {
333 Replace();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000334 return S;
335 }
336
337 checkGlobalType(S, File, &Global->getType());
338
339 if (shouldReplace(S, File, Flags))
Sam Clegg6540e572019-02-20 23:19:31 +0000340 Replace();
Sam Clegg93102972018-02-23 05:08:53 +0000341 return S;
342}
343
Heejin Ahne915a712018-12-08 06:17:43 +0000344Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags,
345 InputFile *File, InputEvent *Event) {
346 LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n");
347
348 Symbol *S;
349 bool WasInserted;
350 std::tie(S, WasInserted) = insert(Name, File);
351
Sam Clegg6540e572019-02-20 23:19:31 +0000352 auto Replace = [&]() {
Heejin Ahne915a712018-12-08 06:17:43 +0000353 replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
Sam Clegg6540e572019-02-20 23:19:31 +0000354 };
355
356 if (WasInserted || S->isLazy()) {
357 Replace();
Heejin Ahne915a712018-12-08 06:17:43 +0000358 return S;
359 }
360
361 checkEventType(S, File, &Event->getType(), &Event->Signature);
362
363 if (shouldReplace(S, File, Flags))
Sam Clegg6540e572019-02-20 23:19:31 +0000364 Replace();
Heejin Ahne915a712018-12-08 06:17:43 +0000365 return S;
366}
367
Dan Gohman9b84eea2019-02-07 22:00:48 +0000368Symbol *SymbolTable::addUndefinedFunction(StringRef Name, StringRef ImportName,
369 StringRef ImportModule,
Sam Clegg7cc07532019-02-01 02:29:57 +0000370 uint32_t Flags, InputFile *File,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000371 const WasmSignature *Sig) {
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000372 LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name <<
373 " [" << (Sig ? toString(*Sig) : "none") << "]\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000374
Sam Cleggc94d3932017-11-17 18:14:09 +0000375 Symbol *S;
376 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000377 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000378
Sam Clegg6540e572019-02-20 23:19:31 +0000379 auto Replace = [&]() {
Dan Gohman9b84eea2019-02-07 22:00:48 +0000380 replaceSymbol<UndefinedFunction>(S, Name, ImportName, ImportModule, Flags,
381 File, Sig);
Sam Clegg6540e572019-02-20 23:19:31 +0000382 };
383
384 if (WasInserted)
385 Replace();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000386 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
Rui Ueyamab961abc2018-02-28 22:51:51 +0000387 Lazy->fetch();
Sam Clegg6540e572019-02-20 23:19:31 +0000388 else {
389 auto ExistingFunction = dyn_cast<FunctionSymbol>(S);
390 if (!ExistingFunction) {
391 reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION);
392 return S;
393 }
394 if (!signatureMatches(ExistingFunction, Sig))
395 if (getFunctionVariant(S, Sig, File, &S))
396 Replace();
397 }
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000398
Sam Cleggc94d3932017-11-17 18:14:09 +0000399 return S;
400}
401
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000402Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
403 InputFile *File) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000404 LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000405
406 Symbol *S;
407 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000408 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggf989a922018-07-17 19:15:02 +0000409
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000410 if (WasInserted)
411 replaceSymbol<UndefinedData>(S, Name, Flags, File);
412 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
Rui Ueyamab961abc2018-02-28 22:51:51 +0000413 Lazy->fetch();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000414 else if (S->isDefined())
415 checkDataType(S, File);
416 return S;
417}
418
Dan Gohman9b84eea2019-02-07 22:00:48 +0000419Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, StringRef ImportName,
420 StringRef ImportModule, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000421 InputFile *File,
422 const WasmGlobalType *Type) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000423 LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000424
425 Symbol *S;
426 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000427 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000428
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000429 if (WasInserted)
Dan Gohman9b84eea2019-02-07 22:00:48 +0000430 replaceSymbol<UndefinedGlobal>(S, Name, ImportName, ImportModule, Flags,
431 File, Type);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000432 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
Rui Ueyamab961abc2018-02-28 22:51:51 +0000433 Lazy->fetch();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000434 else if (S->isDefined())
435 checkGlobalType(S, File, Type);
436 return S;
437}
438
439void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000440 LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
Sam Cleggc94d3932017-11-17 18:14:09 +0000441 StringRef Name = Sym->getName();
Rui Ueyamac03c9042018-02-20 21:08:47 +0000442
Sam Cleggc94d3932017-11-17 18:14:09 +0000443 Symbol *S;
444 bool WasInserted;
Sam Cleggd15a41542019-03-08 21:10:48 +0000445 std::tie(S, WasInserted) = insertName(Name);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000446
Sam Cleggc94d3932017-11-17 18:14:09 +0000447 if (WasInserted) {
Sam Clegg37b4ee52019-01-29 22:26:31 +0000448 replaceSymbol<LazySymbol>(S, Name, 0, File, *Sym);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000449 return;
450 }
451
Sam Clegg37b4ee52019-01-29 22:26:31 +0000452 if (!S->isUndefined())
453 return;
454
455 // The existing symbol is undefined, load a new one from the archive,
456 // unless the the existing symbol is weak in which case replace the undefined
457 // symbols with a LazySymbol.
458 if (S->isWeak()) {
459 const WasmSignature *OldSig = nullptr;
460 // In the case of an UndefinedFunction we need to preserve the expected
461 // signature.
462 if (auto *F = dyn_cast<UndefinedFunction>(S))
463 OldSig = F->Signature;
464 LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
465 auto NewSym = replaceSymbol<LazySymbol>(S, Name, WASM_SYMBOL_BINDING_WEAK,
466 File, *Sym);
467 NewSym->Signature = OldSig;
468 return;
Sam Cleggc94d3932017-11-17 18:14:09 +0000469 }
Sam Clegg37b4ee52019-01-29 22:26:31 +0000470
471 LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
472 File->addMember(Sym);
Sam Cleggc94d3932017-11-17 18:14:09 +0000473}
Sam Clegge0f6fcd2018-01-12 22:25:17 +0000474
Nicholas Wilsonc4d9aa12018-03-14 15:45:11 +0000475bool SymbolTable::addComdat(StringRef Name) {
476 return Comdats.insert(CachedHashStringRef(Name)).second;
Sam Clegge0f6fcd2018-01-12 22:25:17 +0000477}
Sam Clegg1f3f7742019-02-06 02:35:18 +0000478
Sam Clegg6540e572019-02-20 23:19:31 +0000479// The new signature doesn't match. Create a variant to the symbol with the
480// signature encoded in the name and return that instead. These symbols are
481// then unified later in handleSymbolVariants.
482bool SymbolTable::getFunctionVariant(Symbol* Sym, const WasmSignature *Sig,
483 const InputFile *File, Symbol **Out) {
Richard Trieu14bab092019-02-21 00:36:14 +0000484 LLVM_DEBUG(dbgs() << "getFunctionVariant: " << Sym->getName() << " -> "
Sam Clegg6540e572019-02-20 23:19:31 +0000485 << " " << toString(*Sig) << "\n");
486 Symbol *Variant = nullptr;
487
488 // Linear search through symbol variants. Should never be more than two
489 // or three entries here.
490 auto &Variants = SymVariants[CachedHashStringRef(Sym->getName())];
491 if (Variants.size() == 0)
492 Variants.push_back(Sym);
493
494 for (Symbol* V : Variants) {
495 if (*V->getSignature() == *Sig) {
496 Variant = V;
497 break;
498 }
499 }
500
501 bool WasAdded = !Variant;
502 if (WasAdded) {
503 // Create a new variant;
504 LLVM_DEBUG(dbgs() << "added new variant\n");
505 Variant = reinterpret_cast<Symbol *>(make<SymbolUnion>());
506 Variants.push_back(Variant);
507 } else {
508 LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*Variant) << "\n");
509 assert(*Variant->getSignature() == *Sig);
510 }
511
512 *Out = Variant;
513 return WasAdded;
514}
515
Sam Clegg1f3f7742019-02-06 02:35:18 +0000516// Set a flag for --trace-symbol so that we can print out a log message
517// if a new symbol with the same name is inserted into the symbol table.
518void SymbolTable::trace(StringRef Name) {
519 SymMap.insert({CachedHashStringRef(Name), -1});
520}
Sam Clegg230dc112019-02-07 22:42:16 +0000521
522static const uint8_t UnreachableFn[] = {
523 0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
524 0x00 /* opcode unreachable */, 0x0b /* opcode end */
525};
526
527// Replace the given symbol body with an unreachable function.
528// This is used by handleWeakUndefines in order to generate a callable
Sam Clegg6540e572019-02-20 23:19:31 +0000529// equivalent of an undefined function and also handleSymbolVariants for
530// undefined functions that don't match the signature of the definition.
Sam Clegg230dc112019-02-07 22:42:16 +0000531InputFunction *SymbolTable::replaceWithUnreachable(Symbol *Sym,
532 const WasmSignature &Sig,
533 StringRef DebugName) {
534 auto *Func = make<SyntheticFunction>(Sig, Sym->getName(), DebugName);
535 Func->setBody(UnreachableFn);
536 SyntheticFunctions.emplace_back(Func);
Sam Clegg6540e572019-02-20 23:19:31 +0000537 replaceSymbol<DefinedFunction>(Sym, Sym->getName(), Sym->getFlags(), nullptr,
538 Func);
Sam Clegg230dc112019-02-07 22:42:16 +0000539 return Func;
540}
541
542// For weak undefined functions, there may be "call" instructions that reference
543// the symbol. In this case, we need to synthesise a dummy/stub function that
544// will abort at runtime, so that relocations can still provided an operand to
545// the call instruction that passes Wasm validation.
546void SymbolTable::handleWeakUndefines() {
547 for (Symbol *Sym : getSymbols()) {
548 if (!Sym->isUndefWeak())
549 continue;
550
Sam Clegg6540e572019-02-20 23:19:31 +0000551 const WasmSignature *Sig = Sym->getSignature();
552 if (!Sig) {
Sam Clegg230dc112019-02-07 22:42:16 +0000553 // It is possible for undefined functions not to have a signature (eg. if
554 // added via "--undefined"), but weak undefined ones do have a signature.
Sam Clegg6540e572019-02-20 23:19:31 +0000555 // Lazy symbols may not be functions and therefore Sig can still be null
556 // in some circumstantce.
557 assert(!isa<FunctionSymbol>(Sym));
Sam Clegg230dc112019-02-07 22:42:16 +0000558 continue;
Sam Clegg6540e572019-02-20 23:19:31 +0000559 }
Sam Clegg230dc112019-02-07 22:42:16 +0000560
561 // Add a synthetic dummy for weak undefined functions. These dummies will
562 // be GC'd if not used as the target of any "call" instructions.
563 StringRef DebugName = Saver.save("undefined:" + toString(*Sym));
564 InputFunction* Func = replaceWithUnreachable(Sym, *Sig, DebugName);
565 // Ensure it compares equal to the null pointer, and so that table relocs
566 // don't pull in the stub body (only call-operand relocs should do that).
567 Func->setTableIndex(0);
568 // Hide our dummy to prevent export.
569 Sym->setHidden(true);
570 }
571}
Sam Clegg6540e572019-02-20 23:19:31 +0000572
573static void reportFunctionSignatureMismatch(StringRef SymName,
574 FunctionSymbol *A,
575 FunctionSymbol *B, bool Error) {
576 std::string msg = ("function signature mismatch: " + SymName +
577 "\n>>> defined as " + toString(*A->Signature) + " in " +
578 toString(A->getFile()) + "\n>>> defined as " +
579 toString(*B->Signature) + " in " + toString(B->getFile()))
580 .str();
581 if (Error)
582 error(msg);
583 else
584 warn(msg);
585}
586
587// Remove any variant symbols that were created due to function signature
588// mismatches.
589void SymbolTable::handleSymbolVariants() {
590 for (auto Pair : SymVariants) {
591 // Push the initial symbol onto the list of variants.
592 StringRef SymName = Pair.first.val();
593 std::vector<Symbol *> &Variants = Pair.second;
594
595#ifndef NDEBUG
Sam Cleggf8d736f2019-02-21 01:33:26 +0000596 LLVM_DEBUG(dbgs() << "symbol with (" << Variants.size()
597 << ") variants: " << SymName << "\n");
Sam Clegg6540e572019-02-20 23:19:31 +0000598 for (auto *S: Variants) {
599 auto *F = cast<FunctionSymbol>(S);
Sam Cleggf8d736f2019-02-21 01:33:26 +0000600 LLVM_DEBUG(dbgs() << " variant: " + F->getName() << " "
601 << toString(*F->Signature) << "\n");
Sam Clegg6540e572019-02-20 23:19:31 +0000602 }
603#endif
604
605 // Find the one definition.
606 DefinedFunction *Defined = nullptr;
607 for (auto *Symbol : Variants) {
608 if (auto F = dyn_cast<DefinedFunction>(Symbol)) {
609 Defined = F;
610 break;
611 }
612 }
613
614 // If there are no definitions, and the undefined symbols disagree on
615 // the signature, there is not we can do since we don't know which one
616 // to use as the signature on the import.
617 if (!Defined) {
618 reportFunctionSignatureMismatch(SymName,
619 cast<FunctionSymbol>(Variants[0]),
620 cast<FunctionSymbol>(Variants[1]), true);
621 return;
622 }
623
624 for (auto *Symbol : Variants) {
625 if (Symbol != Defined) {
626 auto *F = cast<FunctionSymbol>(Symbol);
627 reportFunctionSignatureMismatch(SymName, F, Defined, false);
628 StringRef DebugName = Saver.save("unreachable:" + toString(*F));
629 replaceWithUnreachable(F, *F->Signature, DebugName);
630 }
631 }
632 }
633}