blob: b196d5017c90dfa5220b4a2e4c5d6661aec1cac8 [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
Sam Clegg6540e572019-02-20 23:19:31 +000029static char encodeValType(ValType Type) {
30 switch (Type) {
31 case ValType::I32:
32 return 'i';
33 case ValType::I64:
34 return 'j';
35 case ValType::F32:
36 return 'f';
37 case ValType::F64:
38 return 'd';
39 case ValType::V128:
40 return 'V';
41 case ValType::EXCEPT_REF:
42 return 'e';
43 }
44 llvm_unreachable("invalid wasm type");
45}
46
47static std::string encodeSignature(const WasmSignature &Sig) {
48 std::string S = ":";
49 for (ValType Type : Sig.Returns)
50 S += encodeValType(Type);
51 S += ':';
52 for (ValType Type : Sig.Params)
53 S += encodeValType(Type);
54 return S;
55}
56
57static StringRef getVariantName(StringRef BaseName, const WasmSignature &Sig) {
58 return Saver.save(BaseName + encodeSignature(Sig));
59}
60
Sam Cleggc94d3932017-11-17 18:14:09 +000061void SymbolTable::addFile(InputFile *File) {
62 log("Processing: " + toString(File));
Sam Clegg1f3f7742019-02-06 02:35:18 +000063 if (Config->Trace)
64 message(toString(File));
Sam Cleggc94d3932017-11-17 18:14:09 +000065 File->parse();
66
Sam Cleggc729c1b2018-05-30 18:07:52 +000067 // LLVM bitcode file
68 if (auto *F = dyn_cast<BitcodeFile>(File))
69 BitcodeFiles.push_back(F);
70 else if (auto *F = dyn_cast<ObjFile>(File))
Sam Cleggc94d3932017-11-17 18:14:09 +000071 ObjectFiles.push_back(F);
72}
73
Sam Cleggc729c1b2018-05-30 18:07:52 +000074// This function is where all the optimizations of link-time
75// optimization happens. When LTO is in use, some input files are
76// not in native object file format but in the LLVM bitcode format.
77// This function compiles bitcode files into a few big native files
78// using LLVM functions and replaces bitcode symbols with the results.
79// Because all bitcode files that the program consists of are passed
80// to the compiler at once, it can do whole-program optimization.
81void SymbolTable::addCombinedLTOObject() {
82 if (BitcodeFiles.empty())
83 return;
84
85 // Compile bitcode files and replace bitcode symbols.
86 LTO.reset(new BitcodeCompiler);
87 for (BitcodeFile *F : BitcodeFiles)
88 LTO->add(*F);
89
90 for (StringRef Filename : LTO->compile()) {
91 auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"));
92 Obj->parse();
93 ObjectFiles.push_back(Obj);
94 }
95}
96
Sam Cleggc94d3932017-11-17 18:14:09 +000097void SymbolTable::reportRemainingUndefines() {
Sam Clegg74fe0ba2017-12-07 01:51:24 +000098 for (Symbol *Sym : SymVector) {
Sam Cleggc729c1b2018-05-30 18:07:52 +000099 if (!Sym->isUndefined() || Sym->isWeak())
100 continue;
101 if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
102 continue;
103 if (!Sym->IsUsedInRegularObj)
104 continue;
Sam Clegg47e2b6b2018-08-04 00:04:06 +0000105 error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym));
Sam Cleggc94d3932017-11-17 18:14:09 +0000106 }
Sam Cleggc94d3932017-11-17 18:14:09 +0000107}
108
109Symbol *SymbolTable::find(StringRef Name) {
Sam Clegg1f3f7742019-02-06 02:35:18 +0000110 auto It = SymMap.find(CachedHashStringRef(Name));
111 if (It == SymMap.end() || It->second == -1)
112 return nullptr;
113 return SymVector[It->second];
114}
115
Sam Clegg6540e572019-02-20 23:19:31 +0000116void SymbolTable::replace(StringRef Name, Symbol* Sym) {
117 auto It = SymMap.find(CachedHashStringRef(Name));
118 SymVector[It->second] = Sym;
119}
120
Sam Clegg1f3f7742019-02-06 02:35:18 +0000121std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) {
122 bool Trace = false;
123 auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()});
124 int &SymIndex = P.first->second;
125 bool IsNew = P.second;
126 if (SymIndex == -1) {
127 SymIndex = SymVector.size();
128 Trace = true;
129 IsNew = true;
130 }
131
132 if (!IsNew)
133 return {SymVector[SymIndex], false};
134
135 Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
136 Sym->IsUsedInRegularObj = false;
137 Sym->Traced = Trace;
138 SymVector.emplace_back(Sym);
139 return {Sym, true};
Sam Cleggc94d3932017-11-17 18:14:09 +0000140}
141
Sam Clegg230dc112019-02-07 22:42:16 +0000142std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name,
143 const InputFile *File) {
Sam Clegg1f3f7742019-02-06 02:35:18 +0000144 Symbol *S;
145 bool WasInserted;
146 std::tie(S, WasInserted) = insertName(Name);
147
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000148 if (!File || File->kind() == InputFile::ObjectKind)
Sam Clegg1f3f7742019-02-06 02:35:18 +0000149 S->IsUsedInRegularObj = true;
150
151 return {S, WasInserted};
Sam Cleggc94d3932017-11-17 18:14:09 +0000152}
153
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000154static void reportTypeError(const Symbol *Existing, const InputFile *File,
Sam Clegg3876d89a2018-05-14 22:42:33 +0000155 llvm::wasm::WasmSymbolType Type) {
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000156 error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
157 toString(Existing->getWasmType()) + " in " +
Sam Clegg3876d89a2018-05-14 22:42:33 +0000158 toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
159 " in " + toString(File));
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000160}
161
Heejin Ahn6f4286f2018-11-19 23:31:28 +0000162// Check the type of new symbol matches that of the symbol is replacing.
Sam Clegg6540e572019-02-20 23:19:31 +0000163// Returns true if the function types match, false is there is a singature
164// mismatch.
165bool signatureMatches(FunctionSymbol *Existing, const WasmSignature *NewSig) {
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000166 if (!NewSig)
Sam Clegg6540e572019-02-20 23:19:31 +0000167 return true;
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000168
Sam Clegg6540e572019-02-20 23:19:31 +0000169 const WasmSignature *OldSig = Existing->Signature;
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000170 if (!OldSig) {
Sam Clegg6540e572019-02-20 23:19:31 +0000171 Existing->Signature = NewSig;
172 return true;
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000173 }
174
Sam Clegg6540e572019-02-20 23:19:31 +0000175 return *NewSig == *OldSig;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000176}
177
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000178static void checkGlobalType(const Symbol *Existing, const InputFile *File,
179 const WasmGlobalType *NewType) {
180 if (!isa<GlobalSymbol>(Existing)) {
Sam Clegg3876d89a2018-05-14 22:42:33 +0000181 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
Sam Cleggb8621592017-11-30 01:40:08 +0000182 return;
183 }
184
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000185 const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
186 if (*NewType != *OldType) {
187 error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
188 toString(*OldType) + " in " + toString(Existing->getFile()) +
189 "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
Sam Clegg93102972018-02-23 05:08:53 +0000190 }
Sam Clegg24b3dcd2018-01-28 19:57:01 +0000191}
192
Heejin Ahne915a712018-12-08 06:17:43 +0000193static void checkEventType(const Symbol *Existing, const InputFile *File,
194 const WasmEventType *NewType,
195 const WasmSignature *NewSig) {
196 auto ExistingEvent = dyn_cast<EventSymbol>(Existing);
197 if (!isa<EventSymbol>(Existing)) {
198 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT);
199 return;
200 }
201
202 const WasmEventType *OldType = cast<EventSymbol>(Existing)->getEventType();
203 const WasmSignature *OldSig = ExistingEvent->Signature;
204 if (NewType->Attribute != OldType->Attribute)
205 error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " +
206 toString(*OldType) + " in " + toString(Existing->getFile()) +
207 "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
208 if (*NewSig != *OldSig)
209 warn("Event signature mismatch: " + Existing->getName() +
210 "\n>>> defined as " + toString(*OldSig) + " in " +
211 toString(Existing->getFile()) + "\n>>> defined as " +
212 toString(*NewSig) + " in " + toString(File));
213}
214
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000215static void checkDataType(const Symbol *Existing, const InputFile *File) {
216 if (!isa<DataSymbol>(Existing))
Sam Clegg3876d89a2018-05-14 22:42:33 +0000217 reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000218}
219
Sam Cleggdfb0b2c2018-02-14 18:27:59 +0000220DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
Nicholas Wilsonebda41f2018-03-09 16:43:05 +0000221 uint32_t Flags,
222 InputFunction *Function) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000223 LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
Rui Ueyamab961abc2018-02-28 22:51:51 +0000224 assert(!find(Name));
Nicholas Wilsonebda41f2018-03-09 16:43:05 +0000225 SyntheticFunctions.emplace_back(Function);
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000226 return replaceSymbol<DefinedFunction>(insert(Name, nullptr).first, Name,
227 Flags, nullptr, Function);
Sam Clegg50686852018-01-12 18:35:13 +0000228}
229
Sam Clegg00245532018-02-20 23:38:27 +0000230DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
231 uint32_t Flags) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000232 LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
Rui Ueyamab961abc2018-02-28 22:51:51 +0000233 assert(!find(Name));
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000234 return replaceSymbol<DefinedData>(insert(Name, nullptr).first, Name, Flags);
Sam Cleggc94d3932017-11-17 18:14:09 +0000235}
236
Sam Clegg93102972018-02-23 05:08:53 +0000237DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
238 InputGlobal *Global) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000239 LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
240 << "\n");
Rui Ueyamab961abc2018-02-28 22:51:51 +0000241 assert(!find(Name));
Nicholas Wilsonebda41f2018-03-09 16:43:05 +0000242 SyntheticGlobals.emplace_back(Global);
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000243 return replaceSymbol<DefinedGlobal>(insert(Name, nullptr).first, Name, Flags,
244 nullptr, Global);
Sam Clegg93102972018-02-23 05:08:53 +0000245}
246
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000247static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
248 uint32_t NewFlags) {
Rui Ueyamac03c9042018-02-20 21:08:47 +0000249 // If existing symbol is undefined, replace it.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000250 if (!Existing->isDefined()) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000251 LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
252 << Existing->getName() << "\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000253 return true;
254 }
255
256 // Now we have two defined symbols. If the new one is weak, we can ignore it.
257 if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000258 LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000259 return false;
260 }
261
262 // If the existing symbol is weak, we should replace it.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000263 if (Existing->isWeak()) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000264 LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000265 return true;
266 }
267
268 // Neither symbol is week. They conflict.
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000269 error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
270 toString(Existing->getFile()) + "\n>>> defined in " +
271 toString(NewFile));
Rui Ueyamac03c9042018-02-20 21:08:47 +0000272 return true;
Sam Clegg93e559b2018-02-20 18:55:06 +0000273}
274
275Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000276 InputFile *File,
277 InputFunction *Function) {
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000278 LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " ["
279 << (Function ? toString(Function->Signature) : "none")
280 << "]\n");
Sam Clegg93e559b2018-02-20 18:55:06 +0000281 Symbol *S;
282 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000283 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000284
Sam Clegg6540e572019-02-20 23:19:31 +0000285 auto Replace = [&](Symbol* Sym) {
286 // If the new defined function doesn't have signture (i.e. bitcode
287 // functions) but the old symbol does, then preserve the old signature
288 const WasmSignature *OldSig = S->getSignature();
289 auto* NewSym = replaceSymbol<DefinedFunction>(Sym, Name, Flags, File, Function);
290 if (!NewSym->Signature)
291 NewSym->Signature = OldSig;
292 };
293
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000294 if (WasInserted || S->isLazy()) {
Sam Clegg6540e572019-02-20 23:19:31 +0000295 Replace(S);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000296 return S;
297 }
298
Sam Clegg6540e572019-02-20 23:19:31 +0000299 auto ExistingFunction = dyn_cast<FunctionSymbol>(S);
300 if (!ExistingFunction) {
301 reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION);
302 return S;
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000303 }
Sam Clegg6540e572019-02-20 23:19:31 +0000304
305 if (Function && !signatureMatches(ExistingFunction, &Function->Signature)) {
306 Symbol* Variant;
307 if (getFunctionVariant(S, &Function->Signature, File, &Variant))
308 // New variant, always replace
309 Replace(Variant);
310 else if (shouldReplace(S, File, Flags))
311 // Variant already exists, replace it after checking shouldReplace
312 Replace(Variant);
313
314 // This variant we found take the place in the symbol table as the primary
315 // variant.
316 replace(Name, Variant);
317 return Variant;
318 }
319
320 // Existing function with matching signature.
321 if (shouldReplace(S, File, Flags))
322 Replace(S);
323
Sam Clegg93e559b2018-02-20 18:55:06 +0000324 return S;
325}
326
Sam Clegg00245532018-02-20 23:38:27 +0000327Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000328 InputFile *File, InputSegment *Segment,
Sam Clegg93102972018-02-23 05:08:53 +0000329 uint32_t Address, uint32_t Size) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000330 LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
331 << "\n");
Sam Clegg93e559b2018-02-20 18:55:06 +0000332 Symbol *S;
333 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000334 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000335
Sam Clegg6540e572019-02-20 23:19:31 +0000336 auto Replace = [&]() {
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000337 replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
Sam Clegg6540e572019-02-20 23:19:31 +0000338 };
339
340 if (WasInserted || S->isLazy()) {
341 Replace();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000342 return S;
343 }
344
345 checkDataType(S, File);
346
347 if (shouldReplace(S, File, Flags))
Sam Clegg6540e572019-02-20 23:19:31 +0000348 Replace();
Sam Cleggc94d3932017-11-17 18:14:09 +0000349 return S;
350}
351
Sam Clegg93102972018-02-23 05:08:53 +0000352Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000353 InputFile *File, InputGlobal *Global) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000354 LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000355
Sam Clegg93102972018-02-23 05:08:53 +0000356 Symbol *S;
357 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000358 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000359
Sam Clegg6540e572019-02-20 23:19:31 +0000360 auto Replace = [&]() {
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000361 replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
Sam Clegg6540e572019-02-20 23:19:31 +0000362 };
363
364 if (WasInserted || S->isLazy()) {
365 Replace();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000366 return S;
367 }
368
369 checkGlobalType(S, File, &Global->getType());
370
371 if (shouldReplace(S, File, Flags))
Sam Clegg6540e572019-02-20 23:19:31 +0000372 Replace();
Sam Clegg93102972018-02-23 05:08:53 +0000373 return S;
374}
375
Heejin Ahne915a712018-12-08 06:17:43 +0000376Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags,
377 InputFile *File, InputEvent *Event) {
378 LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n");
379
380 Symbol *S;
381 bool WasInserted;
382 std::tie(S, WasInserted) = insert(Name, File);
383
Sam Clegg6540e572019-02-20 23:19:31 +0000384 auto Replace = [&]() {
Heejin Ahne915a712018-12-08 06:17:43 +0000385 replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
Sam Clegg6540e572019-02-20 23:19:31 +0000386 };
387
388 if (WasInserted || S->isLazy()) {
389 Replace();
Heejin Ahne915a712018-12-08 06:17:43 +0000390 return S;
391 }
392
393 checkEventType(S, File, &Event->getType(), &Event->Signature);
394
395 if (shouldReplace(S, File, Flags))
Sam Clegg6540e572019-02-20 23:19:31 +0000396 Replace();
Heejin Ahne915a712018-12-08 06:17:43 +0000397 return S;
398}
399
Dan Gohman9b84eea2019-02-07 22:00:48 +0000400Symbol *SymbolTable::addUndefinedFunction(StringRef Name, StringRef ImportName,
401 StringRef ImportModule,
Sam Clegg7cc07532019-02-01 02:29:57 +0000402 uint32_t Flags, InputFile *File,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000403 const WasmSignature *Sig) {
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000404 LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name <<
405 " [" << (Sig ? toString(*Sig) : "none") << "]\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000406
Sam Cleggc94d3932017-11-17 18:14:09 +0000407 Symbol *S;
408 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000409 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000410
Sam Clegg6540e572019-02-20 23:19:31 +0000411 auto Replace = [&]() {
Dan Gohman9b84eea2019-02-07 22:00:48 +0000412 replaceSymbol<UndefinedFunction>(S, Name, ImportName, ImportModule, Flags,
413 File, Sig);
Sam Clegg6540e572019-02-20 23:19:31 +0000414 };
415
416 if (WasInserted)
417 Replace();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000418 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
Rui Ueyamab961abc2018-02-28 22:51:51 +0000419 Lazy->fetch();
Sam Clegg6540e572019-02-20 23:19:31 +0000420 else {
421 auto ExistingFunction = dyn_cast<FunctionSymbol>(S);
422 if (!ExistingFunction) {
423 reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION);
424 return S;
425 }
426 if (!signatureMatches(ExistingFunction, Sig))
427 if (getFunctionVariant(S, Sig, File, &S))
428 Replace();
429 }
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000430
Sam Cleggc94d3932017-11-17 18:14:09 +0000431 return S;
432}
433
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000434Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
435 InputFile *File) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000436 LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000437
438 Symbol *S;
439 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000440 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggf989a922018-07-17 19:15:02 +0000441
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000442 if (WasInserted)
443 replaceSymbol<UndefinedData>(S, Name, Flags, File);
444 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
Rui Ueyamab961abc2018-02-28 22:51:51 +0000445 Lazy->fetch();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000446 else if (S->isDefined())
447 checkDataType(S, File);
448 return S;
449}
450
Dan Gohman9b84eea2019-02-07 22:00:48 +0000451Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, StringRef ImportName,
452 StringRef ImportModule, uint32_t Flags,
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000453 InputFile *File,
454 const WasmGlobalType *Type) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000455 LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000456
457 Symbol *S;
458 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000459 std::tie(S, WasInserted) = insert(Name, File);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000460
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000461 if (WasInserted)
Dan Gohman9b84eea2019-02-07 22:00:48 +0000462 replaceSymbol<UndefinedGlobal>(S, Name, ImportName, ImportModule, Flags,
463 File, Type);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000464 else if (auto *Lazy = dyn_cast<LazySymbol>(S))
Rui Ueyamab961abc2018-02-28 22:51:51 +0000465 Lazy->fetch();
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000466 else if (S->isDefined())
467 checkGlobalType(S, File, Type);
468 return S;
469}
470
471void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000472 LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
Sam Cleggc94d3932017-11-17 18:14:09 +0000473 StringRef Name = Sym->getName();
Rui Ueyamac03c9042018-02-20 21:08:47 +0000474
Sam Cleggc94d3932017-11-17 18:14:09 +0000475 Symbol *S;
476 bool WasInserted;
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000477 std::tie(S, WasInserted) = insert(Name, nullptr);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000478
Sam Cleggc94d3932017-11-17 18:14:09 +0000479 if (WasInserted) {
Sam Clegg37b4ee52019-01-29 22:26:31 +0000480 replaceSymbol<LazySymbol>(S, Name, 0, File, *Sym);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000481 return;
482 }
483
Sam Clegg37b4ee52019-01-29 22:26:31 +0000484 if (!S->isUndefined())
485 return;
486
487 // The existing symbol is undefined, load a new one from the archive,
488 // unless the the existing symbol is weak in which case replace the undefined
489 // symbols with a LazySymbol.
490 if (S->isWeak()) {
491 const WasmSignature *OldSig = nullptr;
492 // In the case of an UndefinedFunction we need to preserve the expected
493 // signature.
494 if (auto *F = dyn_cast<UndefinedFunction>(S))
495 OldSig = F->Signature;
496 LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
497 auto NewSym = replaceSymbol<LazySymbol>(S, Name, WASM_SYMBOL_BINDING_WEAK,
498 File, *Sym);
499 NewSym->Signature = OldSig;
500 return;
Sam Cleggc94d3932017-11-17 18:14:09 +0000501 }
Sam Clegg37b4ee52019-01-29 22:26:31 +0000502
503 LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
504 File->addMember(Sym);
Sam Cleggc94d3932017-11-17 18:14:09 +0000505}
Sam Clegge0f6fcd2018-01-12 22:25:17 +0000506
Nicholas Wilsonc4d9aa12018-03-14 15:45:11 +0000507bool SymbolTable::addComdat(StringRef Name) {
508 return Comdats.insert(CachedHashStringRef(Name)).second;
Sam Clegge0f6fcd2018-01-12 22:25:17 +0000509}
Sam Clegg1f3f7742019-02-06 02:35:18 +0000510
Sam Clegg6540e572019-02-20 23:19:31 +0000511// The new signature doesn't match. Create a variant to the symbol with the
512// signature encoded in the name and return that instead. These symbols are
513// then unified later in handleSymbolVariants.
514bool SymbolTable::getFunctionVariant(Symbol* Sym, const WasmSignature *Sig,
515 const InputFile *File, Symbol **Out) {
516 StringRef NewName = getVariantName(Sym->getName(), *Sig);
517 LLVM_DEBUG(dbgs() << "getFunctionVariant: " << Sym->getName() << " -> " << NewName
518 << " " << toString(*Sig) << "\n");
519 Symbol *Variant = nullptr;
520
521 // Linear search through symbol variants. Should never be more than two
522 // or three entries here.
523 auto &Variants = SymVariants[CachedHashStringRef(Sym->getName())];
524 if (Variants.size() == 0)
525 Variants.push_back(Sym);
526
527 for (Symbol* V : Variants) {
528 if (*V->getSignature() == *Sig) {
529 Variant = V;
530 break;
531 }
532 }
533
534 bool WasAdded = !Variant;
535 if (WasAdded) {
536 // Create a new variant;
537 LLVM_DEBUG(dbgs() << "added new variant\n");
538 Variant = reinterpret_cast<Symbol *>(make<SymbolUnion>());
539 Variants.push_back(Variant);
540 } else {
541 LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*Variant) << "\n");
542 assert(*Variant->getSignature() == *Sig);
543 }
544
545 *Out = Variant;
546 return WasAdded;
547}
548
Sam Clegg1f3f7742019-02-06 02:35:18 +0000549// Set a flag for --trace-symbol so that we can print out a log message
550// if a new symbol with the same name is inserted into the symbol table.
551void SymbolTable::trace(StringRef Name) {
552 SymMap.insert({CachedHashStringRef(Name), -1});
553}
Sam Clegg230dc112019-02-07 22:42:16 +0000554
555static const uint8_t UnreachableFn[] = {
556 0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
557 0x00 /* opcode unreachable */, 0x0b /* opcode end */
558};
559
560// Replace the given symbol body with an unreachable function.
561// This is used by handleWeakUndefines in order to generate a callable
Sam Clegg6540e572019-02-20 23:19:31 +0000562// equivalent of an undefined function and also handleSymbolVariants for
563// undefined functions that don't match the signature of the definition.
Sam Clegg230dc112019-02-07 22:42:16 +0000564InputFunction *SymbolTable::replaceWithUnreachable(Symbol *Sym,
565 const WasmSignature &Sig,
566 StringRef DebugName) {
567 auto *Func = make<SyntheticFunction>(Sig, Sym->getName(), DebugName);
568 Func->setBody(UnreachableFn);
569 SyntheticFunctions.emplace_back(Func);
Sam Clegg6540e572019-02-20 23:19:31 +0000570 replaceSymbol<DefinedFunction>(Sym, Sym->getName(), Sym->getFlags(), nullptr,
571 Func);
Sam Clegg230dc112019-02-07 22:42:16 +0000572 return Func;
573}
574
575// For weak undefined functions, there may be "call" instructions that reference
576// the symbol. In this case, we need to synthesise a dummy/stub function that
577// will abort at runtime, so that relocations can still provided an operand to
578// the call instruction that passes Wasm validation.
579void SymbolTable::handleWeakUndefines() {
580 for (Symbol *Sym : getSymbols()) {
581 if (!Sym->isUndefWeak())
582 continue;
583
Sam Clegg6540e572019-02-20 23:19:31 +0000584 const WasmSignature *Sig = Sym->getSignature();
585 if (!Sig) {
Sam Clegg230dc112019-02-07 22:42:16 +0000586 // It is possible for undefined functions not to have a signature (eg. if
587 // added via "--undefined"), but weak undefined ones do have a signature.
Sam Clegg6540e572019-02-20 23:19:31 +0000588 // Lazy symbols may not be functions and therefore Sig can still be null
589 // in some circumstantce.
590 assert(!isa<FunctionSymbol>(Sym));
Sam Clegg230dc112019-02-07 22:42:16 +0000591 continue;
Sam Clegg6540e572019-02-20 23:19:31 +0000592 }
Sam Clegg230dc112019-02-07 22:42:16 +0000593
594 // Add a synthetic dummy for weak undefined functions. These dummies will
595 // be GC'd if not used as the target of any "call" instructions.
596 StringRef DebugName = Saver.save("undefined:" + toString(*Sym));
597 InputFunction* Func = replaceWithUnreachable(Sym, *Sig, DebugName);
598 // Ensure it compares equal to the null pointer, and so that table relocs
599 // don't pull in the stub body (only call-operand relocs should do that).
600 Func->setTableIndex(0);
601 // Hide our dummy to prevent export.
602 Sym->setHidden(true);
603 }
604}
Sam Clegg6540e572019-02-20 23:19:31 +0000605
606static void reportFunctionSignatureMismatch(StringRef SymName,
607 FunctionSymbol *A,
608 FunctionSymbol *B, bool Error) {
609 std::string msg = ("function signature mismatch: " + SymName +
610 "\n>>> defined as " + toString(*A->Signature) + " in " +
611 toString(A->getFile()) + "\n>>> defined as " +
612 toString(*B->Signature) + " in " + toString(B->getFile()))
613 .str();
614 if (Error)
615 error(msg);
616 else
617 warn(msg);
618}
619
620// Remove any variant symbols that were created due to function signature
621// mismatches.
622void SymbolTable::handleSymbolVariants() {
623 for (auto Pair : SymVariants) {
624 // Push the initial symbol onto the list of variants.
625 StringRef SymName = Pair.first.val();
626 std::vector<Symbol *> &Variants = Pair.second;
627
628#ifndef NDEBUG
629 dbgs() << "symbol with (" << Variants.size()
630 << ") variants: " << SymName << "\n";
631 for (auto *S: Variants) {
632 auto *F = cast<FunctionSymbol>(S);
633 dbgs() << " variant: " + F->getName() << " " << toString(*F->Signature) << "\n";
634 }
635#endif
636
637 // Find the one definition.
638 DefinedFunction *Defined = nullptr;
639 for (auto *Symbol : Variants) {
640 if (auto F = dyn_cast<DefinedFunction>(Symbol)) {
641 Defined = F;
642 break;
643 }
644 }
645
646 // If there are no definitions, and the undefined symbols disagree on
647 // the signature, there is not we can do since we don't know which one
648 // to use as the signature on the import.
649 if (!Defined) {
650 reportFunctionSignatureMismatch(SymName,
651 cast<FunctionSymbol>(Variants[0]),
652 cast<FunctionSymbol>(Variants[1]), true);
653 return;
654 }
655
656 for (auto *Symbol : Variants) {
657 if (Symbol != Defined) {
658 auto *F = cast<FunctionSymbol>(Symbol);
659 reportFunctionSignatureMismatch(SymName, F, Defined, false);
660 StringRef DebugName = Saver.save("unreachable:" + toString(*F));
661 replaceWithUnreachable(F, *F->Signature, DebugName);
662 }
663 }
664 }
665}