blob: 14616f961b6dcd4ebc3dd4e8b349f17edb2190e0 [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 +000024
Fangrui Song33c59ab2019-10-10 05:25:39 +000025namespace lld {
26namespace wasm {
27SymbolTable *symtab;
Sam Cleggc94d3932017-11-17 18:14:09 +000028
Rui Ueyama136d27a2019-07-11 05:40:30 +000029void SymbolTable::addFile(InputFile *file) {
30 log("Processing: " + toString(file));
Sam Clegga282a612019-06-05 17:50:45 +000031
32 // .a file
Rui Ueyama136d27a2019-07-11 05:40:30 +000033 if (auto *f = dyn_cast<ArchiveFile>(file)) {
34 f->parse();
Sam Clegga282a612019-06-05 17:50:45 +000035 return;
36 }
37
38 // .so file
Rui Ueyama136d27a2019-07-11 05:40:30 +000039 if (auto *f = dyn_cast<SharedFile>(file)) {
40 sharedFiles.push_back(f);
Sam Clegga282a612019-06-05 17:50:45 +000041 return;
42 }
43
Rui Ueyama136d27a2019-07-11 05:40:30 +000044 if (config->trace)
45 message(toString(file));
Sam Cleggc94d3932017-11-17 18:14:09 +000046
Sam Cleggc729c1b2018-05-30 18:07:52 +000047 // LLVM bitcode file
Rui Ueyama136d27a2019-07-11 05:40:30 +000048 if (auto *f = dyn_cast<BitcodeFile>(file)) {
49 f->parse();
50 bitcodeFiles.push_back(f);
Sam Clegga282a612019-06-05 17:50:45 +000051 return;
52 }
53
54 // Regular object file
Rui Ueyama136d27a2019-07-11 05:40:30 +000055 auto *f = cast<ObjFile>(file);
56 f->parse(false);
57 objectFiles.push_back(f);
Sam Cleggc94d3932017-11-17 18:14:09 +000058}
59
Sam Cleggc729c1b2018-05-30 18:07:52 +000060// This function is where all the optimizations of link-time
61// optimization happens. When LTO is in use, some input files are
62// not in native object file format but in the LLVM bitcode format.
63// This function compiles bitcode files into a few big native files
64// using LLVM functions and replaces bitcode symbols with the results.
65// Because all bitcode files that the program consists of are passed
66// to the compiler at once, it can do whole-program optimization.
67void SymbolTable::addCombinedLTOObject() {
Rui Ueyama136d27a2019-07-11 05:40:30 +000068 if (bitcodeFiles.empty())
Sam Cleggc729c1b2018-05-30 18:07:52 +000069 return;
70
71 // Compile bitcode files and replace bitcode symbols.
Rui Ueyama136d27a2019-07-11 05:40:30 +000072 lto.reset(new BitcodeCompiler);
73 for (BitcodeFile *f : bitcodeFiles)
74 lto->add(*f);
Sam Cleggc729c1b2018-05-30 18:07:52 +000075
Rui Ueyama136d27a2019-07-11 05:40:30 +000076 for (StringRef filename : lto->compile()) {
77 auto *obj = make<ObjFile>(MemoryBufferRef(filename, "lto.tmp"), "");
78 obj->parse(true);
79 objectFiles.push_back(obj);
Sam Cleggc729c1b2018-05-30 18:07:52 +000080 }
81}
82
Rui Ueyama136d27a2019-07-11 05:40:30 +000083Symbol *SymbolTable::find(StringRef name) {
84 auto it = symMap.find(CachedHashStringRef(name));
85 if (it == symMap.end() || it->second == -1)
Sam Clegg1f3f7742019-02-06 02:35:18 +000086 return nullptr;
Rui Ueyama136d27a2019-07-11 05:40:30 +000087 return symVector[it->second];
Sam Clegg1f3f7742019-02-06 02:35:18 +000088}
89
Rui Ueyama136d27a2019-07-11 05:40:30 +000090void SymbolTable::replace(StringRef name, Symbol* sym) {
91 auto it = symMap.find(CachedHashStringRef(name));
92 symVector[it->second] = sym;
Sam Clegg6540e572019-02-20 23:19:31 +000093}
94
Rui Ueyama136d27a2019-07-11 05:40:30 +000095std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) {
96 bool trace = false;
97 auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()});
98 int &symIndex = p.first->second;
99 bool isNew = p.second;
100 if (symIndex == -1) {
101 symIndex = symVector.size();
102 trace = true;
103 isNew = true;
Sam Clegg1f3f7742019-02-06 02:35:18 +0000104 }
105
Rui Ueyama136d27a2019-07-11 05:40:30 +0000106 if (!isNew)
107 return {symVector[symIndex], false};
Sam Clegg1f3f7742019-02-06 02:35:18 +0000108
Rui Ueyama136d27a2019-07-11 05:40:30 +0000109 Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
110 sym->isUsedInRegularObj = false;
111 sym->canInline = true;
112 sym->traced = trace;
113 symVector.emplace_back(sym);
114 return {sym, true};
Sam Cleggc94d3932017-11-17 18:14:09 +0000115}
116
Rui Ueyama136d27a2019-07-11 05:40:30 +0000117std::pair<Symbol *, bool> SymbolTable::insert(StringRef name,
118 const InputFile *file) {
119 Symbol *s;
120 bool wasInserted;
121 std::tie(s, wasInserted) = insertName(name);
Sam Clegg1f3f7742019-02-06 02:35:18 +0000122
Rui Ueyama136d27a2019-07-11 05:40:30 +0000123 if (!file || file->kind() == InputFile::ObjectKind)
124 s->isUsedInRegularObj = true;
Sam Clegg1f3f7742019-02-06 02:35:18 +0000125
Rui Ueyama136d27a2019-07-11 05:40:30 +0000126 return {s, wasInserted};
Sam Cleggc94d3932017-11-17 18:14:09 +0000127}
128
Rui Ueyama136d27a2019-07-11 05:40:30 +0000129static void reportTypeError(const Symbol *existing, const InputFile *file,
130 llvm::wasm::WasmSymbolType type) {
131 error("symbol type mismatch: " + toString(*existing) + "\n>>> defined as " +
132 toString(existing->getWasmType()) + " in " +
133 toString(existing->getFile()) + "\n>>> defined as " + toString(type) +
134 " in " + toString(file));
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000135}
136
Heejin Ahn6f4286f2018-11-19 23:31:28 +0000137// Check the type of new symbol matches that of the symbol is replacing.
Sam Clegg6540e572019-02-20 23:19:31 +0000138// Returns true if the function types match, false is there is a singature
139// mismatch.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000140static bool signatureMatches(FunctionSymbol *existing,
141 const WasmSignature *newSig) {
142 const WasmSignature *oldSig = existing->signature;
Sam Cleggd506b0a2019-05-29 15:36:42 +0000143
144 // If either function is missing a signature (this happend for bitcode
145 // symbols) then assume they match. Any mismatch will be reported later
146 // when the LTO objects are added.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000147 if (!newSig || !oldSig)
Sam Clegg6540e572019-02-20 23:19:31 +0000148 return true;
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000149
Rui Ueyama136d27a2019-07-11 05:40:30 +0000150 return *newSig == *oldSig;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000151}
152
Rui Ueyama136d27a2019-07-11 05:40:30 +0000153static void checkGlobalType(const Symbol *existing, const InputFile *file,
154 const WasmGlobalType *newType) {
155 if (!isa<GlobalSymbol>(existing)) {
156 reportTypeError(existing, file, WASM_SYMBOL_TYPE_GLOBAL);
Sam Cleggb8621592017-11-30 01:40:08 +0000157 return;
158 }
159
Rui Ueyama136d27a2019-07-11 05:40:30 +0000160 const WasmGlobalType *oldType = cast<GlobalSymbol>(existing)->getGlobalType();
161 if (*newType != *oldType) {
162 error("Global type mismatch: " + existing->getName() + "\n>>> defined as " +
163 toString(*oldType) + " in " + toString(existing->getFile()) +
164 "\n>>> defined as " + toString(*newType) + " in " + toString(file));
Sam Clegg93102972018-02-23 05:08:53 +0000165 }
Sam Clegg24b3dcd2018-01-28 19:57:01 +0000166}
167
Rui Ueyama136d27a2019-07-11 05:40:30 +0000168static void checkEventType(const Symbol *existing, const InputFile *file,
169 const WasmEventType *newType,
170 const WasmSignature *newSig) {
171 auto existingEvent = dyn_cast<EventSymbol>(existing);
172 if (!isa<EventSymbol>(existing)) {
173 reportTypeError(existing, file, WASM_SYMBOL_TYPE_EVENT);
Heejin Ahne915a712018-12-08 06:17:43 +0000174 return;
175 }
176
Rui Ueyama136d27a2019-07-11 05:40:30 +0000177 const WasmEventType *oldType = cast<EventSymbol>(existing)->getEventType();
178 const WasmSignature *oldSig = existingEvent->signature;
179 if (newType->Attribute != oldType->Attribute)
180 error("Event type mismatch: " + existing->getName() + "\n>>> defined as " +
181 toString(*oldType) + " in " + toString(existing->getFile()) +
182 "\n>>> defined as " + toString(*newType) + " in " + toString(file));
183 if (*newSig != *oldSig)
184 warn("Event signature mismatch: " + existing->getName() +
185 "\n>>> defined as " + toString(*oldSig) + " in " +
186 toString(existing->getFile()) + "\n>>> defined as " +
187 toString(*newSig) + " in " + toString(file));
Heejin Ahne915a712018-12-08 06:17:43 +0000188}
189
Rui Ueyama136d27a2019-07-11 05:40:30 +0000190static void checkDataType(const Symbol *existing, const InputFile *file) {
191 if (!isa<DataSymbol>(existing))
192 reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000193}
194
Rui Ueyama136d27a2019-07-11 05:40:30 +0000195DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name,
196 uint32_t flags,
197 InputFunction *function) {
198 LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n");
199 assert(!find(name));
200 syntheticFunctions.emplace_back(function);
201 return replaceSymbol<DefinedFunction>(insertName(name).first, name,
202 flags, nullptr, function);
Sam Clegg50686852018-01-12 18:35:13 +0000203}
204
Sam Clegg8e8ddaa2019-06-04 16:35:23 +0000205// Adds an optional, linker generated, data symbols. The symbol will only be
206// added if there is an undefine reference to it, or if it is explictly exported
207// via the --export flag. Otherwise we don't add the symbol and return nullptr.
Sam Cleggcaa0db12019-08-08 16:58:36 +0000208DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name,
209 uint32_t value) {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000210 Symbol *s = find(name);
211 if (!s && (config->exportAll || config->exportedSymbols.count(name) != 0))
212 s = insertName(name).first;
213 else if (!s || s->isDefined())
Sam Clegg4bce63a2019-05-23 10:06:03 +0000214 return nullptr;
Rui Ueyama136d27a2019-07-11 05:40:30 +0000215 LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n");
Sam Cleggcaa0db12019-08-08 16:58:36 +0000216 auto *rtn = replaceSymbol<DefinedData>(s, name, WASM_SYMBOL_VISIBILITY_HIDDEN);
Rui Ueyama136d27a2019-07-11 05:40:30 +0000217 rtn->setVirtualAddress(value);
218 rtn->referenced = true;
Sam Clegg4bce63a2019-05-23 10:06:03 +0000219 return rtn;
220}
221
Rui Ueyama136d27a2019-07-11 05:40:30 +0000222DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name,
223 uint32_t flags) {
224 LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n");
225 assert(!find(name));
226 return replaceSymbol<DefinedData>(insertName(name).first, name, flags);
Sam Cleggc94d3932017-11-17 18:14:09 +0000227}
228
Rui Ueyama136d27a2019-07-11 05:40:30 +0000229DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags,
230 InputGlobal *global) {
231 LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global
Nicola Zaghene7245b42018-05-15 13:36:20 +0000232 << "\n");
Rui Ueyama136d27a2019-07-11 05:40:30 +0000233 assert(!find(name));
234 syntheticGlobals.emplace_back(global);
235 return replaceSymbol<DefinedGlobal>(insertName(name).first, name, flags,
236 nullptr, global);
Sam Clegg93102972018-02-23 05:08:53 +0000237}
238
Rui Ueyama136d27a2019-07-11 05:40:30 +0000239static bool shouldReplace(const Symbol *existing, InputFile *newFile,
240 uint32_t newFlags) {
Rui Ueyamac03c9042018-02-20 21:08:47 +0000241 // If existing symbol is undefined, replace it.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000242 if (!existing->isDefined()) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000243 LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
Rui Ueyama136d27a2019-07-11 05:40:30 +0000244 << existing->getName() << "\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000245 return true;
246 }
247
248 // Now we have two defined symbols. If the new one is weak, we can ignore it.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000249 if ((newFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000250 LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000251 return false;
252 }
253
254 // If the existing symbol is weak, we should replace it.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000255 if (existing->isWeak()) {
Nicola Zaghene7245b42018-05-15 13:36:20 +0000256 LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
Rui Ueyamac03c9042018-02-20 21:08:47 +0000257 return true;
258 }
259
260 // Neither symbol is week. They conflict.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000261 error("duplicate symbol: " + toString(*existing) + "\n>>> defined in " +
262 toString(existing->getFile()) + "\n>>> defined in " +
263 toString(newFile));
Rui Ueyamac03c9042018-02-20 21:08:47 +0000264 return true;
Sam Clegg93e559b2018-02-20 18:55:06 +0000265}
266
Rui Ueyama136d27a2019-07-11 05:40:30 +0000267Symbol *SymbolTable::addDefinedFunction(StringRef name, uint32_t flags,
268 InputFile *file,
269 InputFunction *function) {
270 LLVM_DEBUG(dbgs() << "addDefinedFunction: " << name << " ["
271 << (function ? toString(function->signature) : "none")
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000272 << "]\n");
Rui Ueyama136d27a2019-07-11 05:40:30 +0000273 Symbol *s;
274 bool wasInserted;
275 std::tie(s, wasInserted) = insert(name, file);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000276
Rui Ueyama136d27a2019-07-11 05:40:30 +0000277 auto replaceSym = [&](Symbol *sym) {
Sam Clegg6540e572019-02-20 23:19:31 +0000278 // If the new defined function doesn't have signture (i.e. bitcode
279 // functions) but the old symbol does, then preserve the old signature
Rui Ueyama136d27a2019-07-11 05:40:30 +0000280 const WasmSignature *oldSig = s->getSignature();
281 auto* newSym = replaceSymbol<DefinedFunction>(sym, name, flags, file, function);
282 if (!newSym->signature)
283 newSym->signature = oldSig;
Sam Clegg6540e572019-02-20 23:19:31 +0000284 };
285
Rui Ueyama136d27a2019-07-11 05:40:30 +0000286 if (wasInserted || s->isLazy()) {
287 replaceSym(s);
288 return s;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000289 }
290
Rui Ueyama136d27a2019-07-11 05:40:30 +0000291 auto existingFunction = dyn_cast<FunctionSymbol>(s);
292 if (!existingFunction) {
293 reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION);
294 return s;
Sam Clegg8b0b48f2018-09-28 16:50:14 +0000295 }
Sam Clegg6540e572019-02-20 23:19:31 +0000296
Rui Ueyama136d27a2019-07-11 05:40:30 +0000297 bool checkSig = true;
298 if (auto ud = dyn_cast<UndefinedFunction>(existingFunction))
299 checkSig = ud->isCalledDirectly;
Sam Clegg59f959f2019-05-24 22:45:08 +0000300
Rui Ueyama136d27a2019-07-11 05:40:30 +0000301 if (checkSig && function && !signatureMatches(existingFunction, &function->signature)) {
302 Symbol* variant;
303 if (getFunctionVariant(s, &function->signature, file, &variant))
Sam Clegg6540e572019-02-20 23:19:31 +0000304 // New variant, always replace
Rui Ueyama136d27a2019-07-11 05:40:30 +0000305 replaceSym(variant);
306 else if (shouldReplace(s, file, flags))
Sam Clegg6540e572019-02-20 23:19:31 +0000307 // Variant already exists, replace it after checking shouldReplace
Rui Ueyama136d27a2019-07-11 05:40:30 +0000308 replaceSym(variant);
Sam Clegg6540e572019-02-20 23:19:31 +0000309
310 // This variant we found take the place in the symbol table as the primary
311 // variant.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000312 replace(name, variant);
313 return variant;
Sam Clegg6540e572019-02-20 23:19:31 +0000314 }
315
316 // Existing function with matching signature.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000317 if (shouldReplace(s, file, flags))
318 replaceSym(s);
Sam Clegg6540e572019-02-20 23:19:31 +0000319
Rui Ueyama136d27a2019-07-11 05:40:30 +0000320 return s;
Sam Clegg93e559b2018-02-20 18:55:06 +0000321}
322
Rui Ueyama136d27a2019-07-11 05:40:30 +0000323Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags,
324 InputFile *file, InputSegment *segment,
325 uint32_t address, uint32_t size) {
326 LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address
Nicola Zaghene7245b42018-05-15 13:36:20 +0000327 << "\n");
Rui Ueyama136d27a2019-07-11 05:40:30 +0000328 Symbol *s;
329 bool wasInserted;
330 std::tie(s, wasInserted) = insert(name, file);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000331
Rui Ueyama136d27a2019-07-11 05:40:30 +0000332 auto replaceSym = [&]() {
333 replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size);
Sam Clegg6540e572019-02-20 23:19:31 +0000334 };
335
Rui Ueyama136d27a2019-07-11 05:40:30 +0000336 if (wasInserted || s->isLazy()) {
337 replaceSym();
338 return s;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000339 }
340
Rui Ueyama136d27a2019-07-11 05:40:30 +0000341 checkDataType(s, file);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000342
Rui Ueyama136d27a2019-07-11 05:40:30 +0000343 if (shouldReplace(s, file, flags))
344 replaceSym();
345 return s;
Sam Cleggc94d3932017-11-17 18:14:09 +0000346}
347
Rui Ueyama136d27a2019-07-11 05:40:30 +0000348Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags,
349 InputFile *file, InputGlobal *global) {
350 LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n");
Sam Clegg4c2cbfe2018-08-02 20:39:19 +0000351
Rui Ueyama136d27a2019-07-11 05:40:30 +0000352 Symbol *s;
353 bool wasInserted;
354 std::tie(s, wasInserted) = insert(name, file);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000355
Rui Ueyama136d27a2019-07-11 05:40:30 +0000356 auto replaceSym = [&]() {
357 replaceSymbol<DefinedGlobal>(s, name, flags, file, global);
Sam Clegg6540e572019-02-20 23:19:31 +0000358 };
359
Rui Ueyama136d27a2019-07-11 05:40:30 +0000360 if (wasInserted || s->isLazy()) {
361 replaceSym();
362 return s;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000363 }
364
Rui Ueyama136d27a2019-07-11 05:40:30 +0000365 checkGlobalType(s, file, &global->getType());
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000366
Rui Ueyama136d27a2019-07-11 05:40:30 +0000367 if (shouldReplace(s, file, flags))
368 replaceSym();
369 return s;
Sam Clegg93102972018-02-23 05:08:53 +0000370}
371
Rui Ueyama136d27a2019-07-11 05:40:30 +0000372Symbol *SymbolTable::addDefinedEvent(StringRef name, uint32_t flags,
373 InputFile *file, InputEvent *event) {
374 LLVM_DEBUG(dbgs() << "addDefinedEvent:" << name << "\n");
Heejin Ahne915a712018-12-08 06:17:43 +0000375
Rui Ueyama136d27a2019-07-11 05:40:30 +0000376 Symbol *s;
377 bool wasInserted;
378 std::tie(s, wasInserted) = insert(name, file);
Heejin Ahne915a712018-12-08 06:17:43 +0000379
Rui Ueyama136d27a2019-07-11 05:40:30 +0000380 auto replaceSym = [&]() {
381 replaceSymbol<DefinedEvent>(s, name, flags, file, event);
Sam Clegg6540e572019-02-20 23:19:31 +0000382 };
383
Rui Ueyama136d27a2019-07-11 05:40:30 +0000384 if (wasInserted || s->isLazy()) {
385 replaceSym();
386 return s;
Heejin Ahne915a712018-12-08 06:17:43 +0000387 }
388
Rui Ueyama136d27a2019-07-11 05:40:30 +0000389 checkEventType(s, file, &event->getType(), &event->signature);
Heejin Ahne915a712018-12-08 06:17:43 +0000390
Rui Ueyama136d27a2019-07-11 05:40:30 +0000391 if (shouldReplace(s, file, flags))
392 replaceSym();
393 return s;
Heejin Ahne915a712018-12-08 06:17:43 +0000394}
395
Sam Clegg67b05582019-10-17 05:16:54 +0000396// This function get called when an undefined symbol is added, and there is
397// already an existing one in the symbols table. In this case we check that
398// custom 'import-module' and 'import-field' symbol attributes agree.
399// With LTO these attributes are not avialable when the bitcode is read and only
400// become available when the LTO object is read. In this case we silently
401// replace the empty attributes with the valid ones.
402template <typename T>
403static void setImportAttributes(T *existing, StringRef importName,
404 StringRef importModule, InputFile *file) {
405 if (!importName.empty()) {
406 if (existing->importName.empty())
407 existing->importName = importName;
408 if (existing->importName != importName)
409 error("import name mismatch for symbol: " + toString(*existing) +
410 "\n>>> defined as " + existing->importName + " in " +
411 toString(existing->getFile()) + "\n>>> defined as " + importName +
412 " in " + toString(file));
413 }
414
415 if (!importModule.empty()) {
416 if (existing->importModule.empty())
417 existing->importModule = importModule;
418 if (existing->importModule != importModule)
419 error("import module mismatch for symbol: " + toString(*existing) +
420 "\n>>> defined as " + existing->importModule + " in " +
421 toString(existing->getFile()) + "\n>>> defined as " + importModule +
422 " in " + toString(file));
423 }
424}
425
Rui Ueyama136d27a2019-07-11 05:40:30 +0000426Symbol *SymbolTable::addUndefinedFunction(StringRef name, StringRef importName,
427 StringRef importModule,
428 uint32_t flags, InputFile *file,
429 const WasmSignature *sig,
430 bool isCalledDirectly) {
431 LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " ["
432 << (sig ? toString(*sig) : "none")
433 << "] IsCalledDirectly:" << isCalledDirectly << "\n");
Sam Cleggf6f4b982019-09-23 21:28:29 +0000434 assert(flags & WASM_SYMBOL_UNDEFINED);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000435
Rui Ueyama136d27a2019-07-11 05:40:30 +0000436 Symbol *s;
437 bool wasInserted;
438 std::tie(s, wasInserted) = insert(name, file);
439 if (s->traced)
440 printTraceSymbolUndefined(name, file);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000441
Rui Ueyama136d27a2019-07-11 05:40:30 +0000442 auto replaceSym = [&]() {
443 replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags,
444 file, sig, isCalledDirectly);
Sam Clegg6540e572019-02-20 23:19:31 +0000445 };
446
Rui Ueyama136d27a2019-07-11 05:40:30 +0000447 if (wasInserted)
448 replaceSym();
449 else if (auto *lazy = dyn_cast<LazySymbol>(s))
450 lazy->fetch();
Sam Clegg6540e572019-02-20 23:19:31 +0000451 else {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000452 auto existingFunction = dyn_cast<FunctionSymbol>(s);
453 if (!existingFunction) {
454 reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION);
455 return s;
Sam Clegg6540e572019-02-20 23:19:31 +0000456 }
Sam Clegg67b05582019-10-17 05:16:54 +0000457 auto *existingUndefined = dyn_cast<UndefinedFunction>(existingFunction);
Rui Ueyama136d27a2019-07-11 05:40:30 +0000458 if (!existingFunction->signature && sig)
459 existingFunction->signature = sig;
Sam Cleggfecfc592019-08-30 19:50:59 +0000460 if (isCalledDirectly && !signatureMatches(existingFunction, sig)) {
Sam Cleggfecfc592019-08-30 19:50:59 +0000461 // If the existing undefined functions is not called direcltly then let
462 // this one take precedence. Otherwise the existing function is either
463 // direclty called or defined, in which case we need a function variant.
464 if (existingUndefined && !existingUndefined->isCalledDirectly)
Rui Ueyama136d27a2019-07-11 05:40:30 +0000465 replaceSym();
Sam Cleggfecfc592019-08-30 19:50:59 +0000466 else if (getFunctionVariant(s, sig, file, &s))
467 replaceSym();
468 }
Sam Clegg67b05582019-10-17 05:16:54 +0000469 if (existingUndefined)
470 setImportAttributes(existingUndefined, importName, importModule, file);
Sam Clegg6540e572019-02-20 23:19:31 +0000471 }
Sam Cleggcefbf9a2018-06-28 16:53:53 +0000472
Rui Ueyama136d27a2019-07-11 05:40:30 +0000473 return s;
Sam Cleggc94d3932017-11-17 18:14:09 +0000474}
475
Rui Ueyama136d27a2019-07-11 05:40:30 +0000476Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags,
477 InputFile *file) {
478 LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n");
Sam Cleggf6f4b982019-09-23 21:28:29 +0000479 assert(flags & WASM_SYMBOL_UNDEFINED);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000480
Rui Ueyama136d27a2019-07-11 05:40:30 +0000481 Symbol *s;
482 bool wasInserted;
483 std::tie(s, wasInserted) = insert(name, file);
484 if (s->traced)
485 printTraceSymbolUndefined(name, file);
Sam Cleggf989a922018-07-17 19:15:02 +0000486
Rui Ueyama136d27a2019-07-11 05:40:30 +0000487 if (wasInserted)
488 replaceSymbol<UndefinedData>(s, name, flags, file);
489 else if (auto *lazy = dyn_cast<LazySymbol>(s))
490 lazy->fetch();
491 else if (s->isDefined())
492 checkDataType(s, file);
493 return s;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000494}
495
Rui Ueyama136d27a2019-07-11 05:40:30 +0000496Symbol *SymbolTable::addUndefinedGlobal(StringRef name, StringRef importName,
497 StringRef importModule, uint32_t flags,
498 InputFile *file,
499 const WasmGlobalType *type) {
500 LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n");
Sam Cleggf6f4b982019-09-23 21:28:29 +0000501 assert(flags & WASM_SYMBOL_UNDEFINED);
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000502
Rui Ueyama136d27a2019-07-11 05:40:30 +0000503 Symbol *s;
504 bool wasInserted;
505 std::tie(s, wasInserted) = insert(name, file);
506 if (s->traced)
507 printTraceSymbolUndefined(name, file);
Sam Cleggc729c1b2018-05-30 18:07:52 +0000508
Rui Ueyama136d27a2019-07-11 05:40:30 +0000509 if (wasInserted)
510 replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags,
511 file, type);
512 else if (auto *lazy = dyn_cast<LazySymbol>(s))
513 lazy->fetch();
514 else if (s->isDefined())
515 checkGlobalType(s, file, type);
516 return s;
Rui Ueyamae3498ec2018-02-28 00:09:22 +0000517}
518
Rui Ueyama136d27a2019-07-11 05:40:30 +0000519void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) {
520 LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n");
521 StringRef name = sym->getName();
Rui Ueyamac03c9042018-02-20 21:08:47 +0000522
Rui Ueyama136d27a2019-07-11 05:40:30 +0000523 Symbol *s;
524 bool wasInserted;
525 std::tie(s, wasInserted) = insertName(name);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000526
Rui Ueyama136d27a2019-07-11 05:40:30 +0000527 if (wasInserted) {
528 replaceSymbol<LazySymbol>(s, name, 0, file, *sym);
Rui Ueyamac03c9042018-02-20 21:08:47 +0000529 return;
530 }
531
Rui Ueyama136d27a2019-07-11 05:40:30 +0000532 if (!s->isUndefined())
Sam Clegg37b4ee52019-01-29 22:26:31 +0000533 return;
534
535 // The existing symbol is undefined, load a new one from the archive,
536 // unless the the existing symbol is weak in which case replace the undefined
537 // symbols with a LazySymbol.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000538 if (s->isWeak()) {
539 const WasmSignature *oldSig = nullptr;
Sam Clegg37b4ee52019-01-29 22:26:31 +0000540 // In the case of an UndefinedFunction we need to preserve the expected
541 // signature.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000542 if (auto *f = dyn_cast<UndefinedFunction>(s))
543 oldSig = f->signature;
Sam Clegg37b4ee52019-01-29 22:26:31 +0000544 LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
Rui Ueyama136d27a2019-07-11 05:40:30 +0000545 auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK,
546 file, *sym);
547 newSym->signature = oldSig;
Sam Clegg37b4ee52019-01-29 22:26:31 +0000548 return;
Sam Cleggc94d3932017-11-17 18:14:09 +0000549 }
Sam Clegg37b4ee52019-01-29 22:26:31 +0000550
551 LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
Rui Ueyama136d27a2019-07-11 05:40:30 +0000552 file->addMember(sym);
Sam Cleggc94d3932017-11-17 18:14:09 +0000553}
Sam Clegge0f6fcd2018-01-12 22:25:17 +0000554
Rui Ueyama136d27a2019-07-11 05:40:30 +0000555bool SymbolTable::addComdat(StringRef name) {
556 return comdatGroups.insert(CachedHashStringRef(name)).second;
Sam Clegge0f6fcd2018-01-12 22:25:17 +0000557}
Sam Clegg1f3f7742019-02-06 02:35:18 +0000558
Sam Clegg6540e572019-02-20 23:19:31 +0000559// The new signature doesn't match. Create a variant to the symbol with the
560// signature encoded in the name and return that instead. These symbols are
561// then unified later in handleSymbolVariants.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000562bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig,
563 const InputFile *file, Symbol **out) {
564 LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> "
565 << " " << toString(*sig) << "\n");
566 Symbol *variant = nullptr;
Sam Clegg6540e572019-02-20 23:19:31 +0000567
568 // Linear search through symbol variants. Should never be more than two
569 // or three entries here.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000570 auto &variants = symVariants[CachedHashStringRef(sym->getName())];
571 if (variants.empty())
572 variants.push_back(sym);
Sam Clegg6540e572019-02-20 23:19:31 +0000573
Rui Ueyama136d27a2019-07-11 05:40:30 +0000574 for (Symbol* v : variants) {
575 if (*v->getSignature() == *sig) {
576 variant = v;
Sam Clegg6540e572019-02-20 23:19:31 +0000577 break;
578 }
579 }
580
Rui Ueyama136d27a2019-07-11 05:40:30 +0000581 bool wasAdded = !variant;
582 if (wasAdded) {
Sam Clegg6540e572019-02-20 23:19:31 +0000583 // Create a new variant;
584 LLVM_DEBUG(dbgs() << "added new variant\n");
Rui Ueyama136d27a2019-07-11 05:40:30 +0000585 variant = reinterpret_cast<Symbol *>(make<SymbolUnion>());
586 variants.push_back(variant);
Sam Clegg6540e572019-02-20 23:19:31 +0000587 } else {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000588 LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n");
589 assert(*variant->getSignature() == *sig);
Sam Clegg6540e572019-02-20 23:19:31 +0000590 }
591
Rui Ueyama136d27a2019-07-11 05:40:30 +0000592 *out = variant;
593 return wasAdded;
Sam Clegg6540e572019-02-20 23:19:31 +0000594}
595
Sam Clegg1f3f7742019-02-06 02:35:18 +0000596// Set a flag for --trace-symbol so that we can print out a log message
597// if a new symbol with the same name is inserted into the symbol table.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000598void SymbolTable::trace(StringRef name) {
599 symMap.insert({CachedHashStringRef(name), -1});
Sam Clegg1f3f7742019-02-06 02:35:18 +0000600}
Sam Clegg230dc112019-02-07 22:42:16 +0000601
Rui Ueyama136d27a2019-07-11 05:40:30 +0000602void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) {
Sam Clegga5ca34e2019-05-24 14:14:25 +0000603 // Swap symbols as instructed by -wrap.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000604 int &origIdx = symMap[CachedHashStringRef(sym->getName())];
605 int &realIdx= symMap[CachedHashStringRef(real->getName())];
606 int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())];
607 LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n");
Sam Clegga5ca34e2019-05-24 14:14:25 +0000608
609 // Anyone looking up __real symbols should get the original
Rui Ueyama136d27a2019-07-11 05:40:30 +0000610 realIdx = origIdx;
Sam Clegga5ca34e2019-05-24 14:14:25 +0000611 // Anyone looking up the original should get the __wrap symbol
Rui Ueyama136d27a2019-07-11 05:40:30 +0000612 origIdx = wrapIdx;
Sam Clegga5ca34e2019-05-24 14:14:25 +0000613}
614
Rui Ueyama136d27a2019-07-11 05:40:30 +0000615static const uint8_t unreachableFn[] = {
Sam Clegg230dc112019-02-07 22:42:16 +0000616 0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
617 0x00 /* opcode unreachable */, 0x0b /* opcode end */
618};
619
620// Replace the given symbol body with an unreachable function.
621// This is used by handleWeakUndefines in order to generate a callable
Sam Clegg6540e572019-02-20 23:19:31 +0000622// equivalent of an undefined function and also handleSymbolVariants for
623// undefined functions that don't match the signature of the definition.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000624InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym,
625 const WasmSignature &sig,
626 StringRef debugName) {
627 auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName);
628 func->setBody(unreachableFn);
629 syntheticFunctions.emplace_back(func);
630 replaceSymbol<DefinedFunction>(sym, sym->getName(), sym->getFlags(), nullptr,
631 func);
632 return func;
Sam Clegg230dc112019-02-07 22:42:16 +0000633}
634
635// For weak undefined functions, there may be "call" instructions that reference
636// the symbol. In this case, we need to synthesise a dummy/stub function that
637// will abort at runtime, so that relocations can still provided an operand to
638// the call instruction that passes Wasm validation.
639void SymbolTable::handleWeakUndefines() {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000640 for (Symbol *sym : getSymbols()) {
641 if (!sym->isUndefWeak())
Sam Clegg230dc112019-02-07 22:42:16 +0000642 continue;
643
Rui Ueyama136d27a2019-07-11 05:40:30 +0000644 const WasmSignature *sig = sym->getSignature();
645 if (!sig) {
Sam Clegg230dc112019-02-07 22:42:16 +0000646 // It is possible for undefined functions not to have a signature (eg. if
647 // added via "--undefined"), but weak undefined ones do have a signature.
Sam Clegg6540e572019-02-20 23:19:31 +0000648 // Lazy symbols may not be functions and therefore Sig can still be null
649 // in some circumstantce.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000650 assert(!isa<FunctionSymbol>(sym));
Sam Clegg230dc112019-02-07 22:42:16 +0000651 continue;
Sam Clegg6540e572019-02-20 23:19:31 +0000652 }
Sam Clegg230dc112019-02-07 22:42:16 +0000653
654 // Add a synthetic dummy for weak undefined functions. These dummies will
655 // be GC'd if not used as the target of any "call" instructions.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000656 StringRef debugName = saver.save("undefined:" + toString(*sym));
657 InputFunction* func = replaceWithUnreachable(sym, *sig, debugName);
Sam Clegg230dc112019-02-07 22:42:16 +0000658 // Ensure it compares equal to the null pointer, and so that table relocs
659 // don't pull in the stub body (only call-operand relocs should do that).
Rui Ueyama136d27a2019-07-11 05:40:30 +0000660 func->setTableIndex(0);
Sam Clegg230dc112019-02-07 22:42:16 +0000661 // Hide our dummy to prevent export.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000662 sym->setHidden(true);
Sam Clegg230dc112019-02-07 22:42:16 +0000663 }
664}
Sam Clegg6540e572019-02-20 23:19:31 +0000665
Rui Ueyama136d27a2019-07-11 05:40:30 +0000666static void reportFunctionSignatureMismatch(StringRef symName,
667 FunctionSymbol *a,
668 FunctionSymbol *b, bool isError) {
669 std::string msg = ("function signature mismatch: " + symName +
670 "\n>>> defined as " + toString(*a->signature) + " in " +
671 toString(a->getFile()) + "\n>>> defined as " +
672 toString(*b->signature) + " in " + toString(b->getFile()))
Sam Clegg6540e572019-02-20 23:19:31 +0000673 .str();
Rui Ueyama136d27a2019-07-11 05:40:30 +0000674 if (isError)
Sam Clegg6540e572019-02-20 23:19:31 +0000675 error(msg);
676 else
677 warn(msg);
678}
679
680// Remove any variant symbols that were created due to function signature
681// mismatches.
682void SymbolTable::handleSymbolVariants() {
Rui Ueyama136d27a2019-07-11 05:40:30 +0000683 for (auto pair : symVariants) {
Sam Clegg6540e572019-02-20 23:19:31 +0000684 // Push the initial symbol onto the list of variants.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000685 StringRef symName = pair.first.val();
686 std::vector<Symbol *> &variants = pair.second;
Sam Clegg6540e572019-02-20 23:19:31 +0000687
688#ifndef NDEBUG
Rui Ueyama136d27a2019-07-11 05:40:30 +0000689 LLVM_DEBUG(dbgs() << "symbol with (" << variants.size()
690 << ") variants: " << symName << "\n");
691 for (auto *s: variants) {
692 auto *f = cast<FunctionSymbol>(s);
693 LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " "
694 << toString(*f->signature) << "\n");
Sam Clegg6540e572019-02-20 23:19:31 +0000695 }
696#endif
697
698 // Find the one definition.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000699 DefinedFunction *defined = nullptr;
700 for (auto *symbol : variants) {
701 if (auto f = dyn_cast<DefinedFunction>(symbol)) {
702 defined = f;
Sam Clegg6540e572019-02-20 23:19:31 +0000703 break;
704 }
705 }
706
707 // If there are no definitions, and the undefined symbols disagree on
708 // the signature, there is not we can do since we don't know which one
709 // to use as the signature on the import.
Rui Ueyama136d27a2019-07-11 05:40:30 +0000710 if (!defined) {
711 reportFunctionSignatureMismatch(symName,
712 cast<FunctionSymbol>(variants[0]),
713 cast<FunctionSymbol>(variants[1]), true);
Sam Clegg6540e572019-02-20 23:19:31 +0000714 return;
715 }
716
Rui Ueyama136d27a2019-07-11 05:40:30 +0000717 for (auto *symbol : variants) {
718 if (symbol != defined) {
719 auto *f = cast<FunctionSymbol>(symbol);
720 reportFunctionSignatureMismatch(symName, f, defined, false);
721 StringRef debugName = saver.save("unreachable:" + toString(*f));
722 replaceWithUnreachable(f, *f->signature, debugName);
Sam Clegg6540e572019-02-20 23:19:31 +0000723 }
724 }
725 }
726}
Fangrui Song33c59ab2019-10-10 05:25:39 +0000727
728} // namespace wasm
729} // namespace lld