1 //===- Symbols.cpp --------------------------------------------------------===//
2 //
3 // 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
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "Symbols.h"
10 #include "Config.h"
11 #include "InputChunks.h"
12 #include "InputElement.h"
13 #include "InputFiles.h"
14 #include "OutputSections.h"
15 #include "OutputSegment.h"
16 #include "lld/Common/ErrorHandler.h"
17 #include "lld/Common/Memory.h"
18 #include "lld/Common/Strings.h"
19
20 #define DEBUG_TYPE "lld"
21
22 using namespace llvm;
23 using namespace llvm::object;
24 using namespace llvm::wasm;
25
26 namespace lld {
toString(const wasm::Symbol & sym)27 std::string toString(const wasm::Symbol &sym) {
28 return maybeDemangleSymbol(sym.getName());
29 }
30
maybeDemangleSymbol(StringRef name)31 std::string maybeDemangleSymbol(StringRef name) {
32 // WebAssembly requires caller and callee signatures to match, so we mangle
33 // `main` in the case where we need to pass it arguments.
34 if (name == "__main_argc_argv")
35 return "main";
36 if (wasm::config->demangle)
37 return demangleItanium(name);
38 return std::string(name);
39 }
40
toString(wasm::Symbol::Kind kind)41 std::string toString(wasm::Symbol::Kind kind) {
42 switch (kind) {
43 case wasm::Symbol::DefinedFunctionKind:
44 return "DefinedFunction";
45 case wasm::Symbol::DefinedDataKind:
46 return "DefinedData";
47 case wasm::Symbol::DefinedGlobalKind:
48 return "DefinedGlobal";
49 case wasm::Symbol::DefinedTableKind:
50 return "DefinedTable";
51 case wasm::Symbol::DefinedTagKind:
52 return "DefinedTag";
53 case wasm::Symbol::UndefinedFunctionKind:
54 return "UndefinedFunction";
55 case wasm::Symbol::UndefinedDataKind:
56 return "UndefinedData";
57 case wasm::Symbol::UndefinedGlobalKind:
58 return "UndefinedGlobal";
59 case wasm::Symbol::UndefinedTableKind:
60 return "UndefinedTable";
61 case wasm::Symbol::LazyKind:
62 return "LazyKind";
63 case wasm::Symbol::SectionKind:
64 return "SectionKind";
65 case wasm::Symbol::OutputSectionKind:
66 return "OutputSectionKind";
67 }
68 llvm_unreachable("invalid symbol kind");
69 }
70
71 namespace wasm {
72 DefinedFunction *WasmSym::callCtors;
73 DefinedFunction *WasmSym::callDtors;
74 DefinedFunction *WasmSym::initMemory;
75 DefinedFunction *WasmSym::applyDataRelocs;
76 DefinedFunction *WasmSym::applyGlobalRelocs;
77 DefinedFunction *WasmSym::applyGlobalTLSRelocs;
78 DefinedFunction *WasmSym::initTLS;
79 DefinedFunction *WasmSym::startFunction;
80 DefinedData *WasmSym::dsoHandle;
81 DefinedData *WasmSym::dataEnd;
82 DefinedData *WasmSym::globalBase;
83 DefinedData *WasmSym::heapBase;
84 DefinedData *WasmSym::initMemoryFlag;
85 GlobalSymbol *WasmSym::stackPointer;
86 GlobalSymbol *WasmSym::tlsBase;
87 GlobalSymbol *WasmSym::tlsSize;
88 GlobalSymbol *WasmSym::tlsAlign;
89 UndefinedGlobal *WasmSym::tableBase;
90 DefinedData *WasmSym::definedTableBase;
91 UndefinedGlobal *WasmSym::tableBase32;
92 DefinedData *WasmSym::definedTableBase32;
93 UndefinedGlobal *WasmSym::memoryBase;
94 DefinedData *WasmSym::definedMemoryBase;
95 TableSymbol *WasmSym::indirectFunctionTable;
96
getWasmType() const97 WasmSymbolType Symbol::getWasmType() const {
98 if (isa<FunctionSymbol>(this))
99 return WASM_SYMBOL_TYPE_FUNCTION;
100 if (isa<DataSymbol>(this))
101 return WASM_SYMBOL_TYPE_DATA;
102 if (isa<GlobalSymbol>(this))
103 return WASM_SYMBOL_TYPE_GLOBAL;
104 if (isa<TagSymbol>(this))
105 return WASM_SYMBOL_TYPE_TAG;
106 if (isa<TableSymbol>(this))
107 return WASM_SYMBOL_TYPE_TABLE;
108 if (isa<SectionSymbol>(this) || isa<OutputSectionSymbol>(this))
109 return WASM_SYMBOL_TYPE_SECTION;
110 llvm_unreachable("invalid symbol kind");
111 }
112
getSignature() const113 const WasmSignature *Symbol::getSignature() const {
114 if (auto* f = dyn_cast<FunctionSymbol>(this))
115 return f->signature;
116 if (auto *l = dyn_cast<LazySymbol>(this))
117 return l->signature;
118 return nullptr;
119 }
120
getChunk() const121 InputChunk *Symbol::getChunk() const {
122 if (auto *f = dyn_cast<DefinedFunction>(this))
123 return f->function;
124 if (auto *f = dyn_cast<UndefinedFunction>(this))
125 if (f->stubFunction)
126 return f->stubFunction->function;
127 if (auto *d = dyn_cast<DefinedData>(this))
128 return d->segment;
129 return nullptr;
130 }
131
isDiscarded() const132 bool Symbol::isDiscarded() const {
133 if (InputChunk *c = getChunk())
134 return c->discarded;
135 return false;
136 }
137
isLive() const138 bool Symbol::isLive() const {
139 if (auto *g = dyn_cast<DefinedGlobal>(this))
140 return g->global->live;
141 if (auto *t = dyn_cast<DefinedTag>(this))
142 return t->tag->live;
143 if (auto *t = dyn_cast<DefinedTable>(this))
144 return t->table->live;
145 if (InputChunk *c = getChunk())
146 return c->live;
147 return referenced;
148 }
149
markLive()150 void Symbol::markLive() {
151 assert(!isDiscarded());
152 referenced = true;
153 if (file != NULL && isDefined())
154 file->markLive();
155 if (auto *g = dyn_cast<DefinedGlobal>(this))
156 g->global->live = true;
157 if (auto *t = dyn_cast<DefinedTag>(this))
158 t->tag->live = true;
159 if (auto *t = dyn_cast<DefinedTable>(this))
160 t->table->live = true;
161 if (InputChunk *c = getChunk()) {
162 // Usually, a whole chunk is marked as live or dead, but in mergeable
163 // (splittable) sections, each piece of data has independent liveness bit.
164 // So we explicitly tell it which offset is in use.
165 if (auto *d = dyn_cast<DefinedData>(this)) {
166 if (auto *ms = dyn_cast<MergeInputChunk>(c)) {
167 ms->getSectionPiece(d->value)->live = true;
168 }
169 }
170 c->live = true;
171 }
172 }
173
getOutputSymbolIndex() const174 uint32_t Symbol::getOutputSymbolIndex() const {
175 assert(outputSymbolIndex != INVALID_INDEX);
176 return outputSymbolIndex;
177 }
178
setOutputSymbolIndex(uint32_t index)179 void Symbol::setOutputSymbolIndex(uint32_t index) {
180 LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name << " -> " << index
181 << "\n");
182 assert(outputSymbolIndex == INVALID_INDEX);
183 outputSymbolIndex = index;
184 }
185
setGOTIndex(uint32_t index)186 void Symbol::setGOTIndex(uint32_t index) {
187 LLVM_DEBUG(dbgs() << "setGOTIndex " << name << " -> " << index << "\n");
188 assert(gotIndex == INVALID_INDEX);
189 if (config->isPic) {
190 // Any symbol that is assigned a GOT entry must be exported otherwise the
191 // dynamic linker won't be able create the entry that contains it.
192 forceExport = true;
193 }
194 gotIndex = index;
195 }
196
isWeak() const197 bool Symbol::isWeak() const {
198 return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
199 }
200
isLocal() const201 bool Symbol::isLocal() const {
202 return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
203 }
204
isHidden() const205 bool Symbol::isHidden() const {
206 return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
207 }
208
isTLS() const209 bool Symbol::isTLS() const { return flags & WASM_SYMBOL_TLS; }
210
setHidden(bool isHidden)211 void Symbol::setHidden(bool isHidden) {
212 LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n");
213 flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
214 if (isHidden)
215 flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
216 else
217 flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;
218 }
219
isExported() const220 bool Symbol::isExported() const {
221 // Shared libraries must export all weakly defined symbols
222 // in case they contain the version that will be chosed by
223 // the dynamic linker.
224 if (config->shared && isLive() && isDefined() && isWeak())
225 return true;
226
227 if (!isDefined() || isLocal())
228 return false;
229
230 if (config->exportAll || (config->exportDynamic && !isHidden()))
231 return true;
232
233 return isExportedExplicit();
234 }
235
isExportedExplicit() const236 bool Symbol::isExportedExplicit() const {
237 return forceExport || flags & WASM_SYMBOL_EXPORTED;
238 }
239
isNoStrip() const240 bool Symbol::isNoStrip() const {
241 return flags & WASM_SYMBOL_NO_STRIP;
242 }
243
getFunctionIndex() const244 uint32_t FunctionSymbol::getFunctionIndex() const {
245 if (const auto *u = dyn_cast<UndefinedFunction>(this))
246 if (u->stubFunction)
247 return u->stubFunction->getFunctionIndex();
248 if (functionIndex != INVALID_INDEX)
249 return functionIndex;
250 auto *f = cast<DefinedFunction>(this);
251 return f->function->getFunctionIndex();
252 }
253
setFunctionIndex(uint32_t index)254 void FunctionSymbol::setFunctionIndex(uint32_t index) {
255 LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n");
256 assert(functionIndex == INVALID_INDEX);
257 functionIndex = index;
258 }
259
hasFunctionIndex() const260 bool FunctionSymbol::hasFunctionIndex() const {
261 if (auto *f = dyn_cast<DefinedFunction>(this))
262 return f->function->hasFunctionIndex();
263 return functionIndex != INVALID_INDEX;
264 }
265
getTableIndex() const266 uint32_t FunctionSymbol::getTableIndex() const {
267 if (auto *f = dyn_cast<DefinedFunction>(this))
268 return f->function->getTableIndex();
269 assert(tableIndex != INVALID_INDEX);
270 return tableIndex;
271 }
272
hasTableIndex() const273 bool FunctionSymbol::hasTableIndex() const {
274 if (auto *f = dyn_cast<DefinedFunction>(this))
275 return f->function->hasTableIndex();
276 return tableIndex != INVALID_INDEX;
277 }
278
setTableIndex(uint32_t index)279 void FunctionSymbol::setTableIndex(uint32_t index) {
280 // For imports, we set the table index here on the Symbol; for defined
281 // functions we set the index on the InputFunction so that we don't export
282 // the same thing twice (keeps the table size down).
283 if (auto *f = dyn_cast<DefinedFunction>(this)) {
284 f->function->setTableIndex(index);
285 return;
286 }
287 LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n");
288 assert(tableIndex == INVALID_INDEX);
289 tableIndex = index;
290 }
291
DefinedFunction(StringRef name,uint32_t flags,InputFile * f,InputFunction * function)292 DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f,
293 InputFunction *function)
294 : FunctionSymbol(name, DefinedFunctionKind, flags, f,
295 function ? &function->signature : nullptr),
296 function(function) {}
297
getExportedFunctionIndex() const298 uint32_t DefinedFunction::getExportedFunctionIndex() const {
299 return function->getFunctionIndex();
300 }
301
getVA() const302 uint64_t DefinedData::getVA() const {
303 LLVM_DEBUG(dbgs() << "getVA: " << getName() << "\n");
304 if (segment)
305 return segment->getVA(value);
306 return value;
307 }
308
setVA(uint64_t value_)309 void DefinedData::setVA(uint64_t value_) {
310 LLVM_DEBUG(dbgs() << "setVA " << name << " -> " << value_ << "\n");
311 assert(!segment);
312 value = value_;
313 }
314
getOutputSegmentOffset() const315 uint64_t DefinedData::getOutputSegmentOffset() const {
316 LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
317 return segment->getChunkOffset(value);
318 }
319
getOutputSegmentIndex() const320 uint64_t DefinedData::getOutputSegmentIndex() const {
321 LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
322 return segment->outputSeg->index;
323 }
324
getGlobalIndex() const325 uint32_t GlobalSymbol::getGlobalIndex() const {
326 if (auto *f = dyn_cast<DefinedGlobal>(this))
327 return f->global->getAssignedIndex();
328 assert(globalIndex != INVALID_INDEX);
329 return globalIndex;
330 }
331
setGlobalIndex(uint32_t index)332 void GlobalSymbol::setGlobalIndex(uint32_t index) {
333 LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n");
334 assert(globalIndex == INVALID_INDEX);
335 globalIndex = index;
336 }
337
hasGlobalIndex() const338 bool GlobalSymbol::hasGlobalIndex() const {
339 if (auto *f = dyn_cast<DefinedGlobal>(this))
340 return f->global->hasAssignedIndex();
341 return globalIndex != INVALID_INDEX;
342 }
343
DefinedGlobal(StringRef name,uint32_t flags,InputFile * file,InputGlobal * global)344 DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,
345 InputGlobal *global)
346 : GlobalSymbol(name, DefinedGlobalKind, flags, file,
347 global ? &global->getType() : nullptr),
348 global(global) {}
349
getTagIndex() const350 uint32_t TagSymbol::getTagIndex() const {
351 if (auto *f = dyn_cast<DefinedTag>(this))
352 return f->tag->getAssignedIndex();
353 assert(tagIndex != INVALID_INDEX);
354 return tagIndex;
355 }
356
setTagIndex(uint32_t index)357 void TagSymbol::setTagIndex(uint32_t index) {
358 LLVM_DEBUG(dbgs() << "setTagIndex " << name << " -> " << index << "\n");
359 assert(tagIndex == INVALID_INDEX);
360 tagIndex = index;
361 }
362
hasTagIndex() const363 bool TagSymbol::hasTagIndex() const {
364 if (auto *f = dyn_cast<DefinedTag>(this))
365 return f->tag->hasAssignedIndex();
366 return tagIndex != INVALID_INDEX;
367 }
368
DefinedTag(StringRef name,uint32_t flags,InputFile * file,InputTag * tag)369 DefinedTag::DefinedTag(StringRef name, uint32_t flags, InputFile *file,
370 InputTag *tag)
371 : TagSymbol(name, DefinedTagKind, flags, file,
372 tag ? &tag->signature : nullptr),
373 tag(tag) {}
374
setLimits(const WasmLimits & limits)375 void TableSymbol::setLimits(const WasmLimits &limits) {
376 if (auto *t = dyn_cast<DefinedTable>(this))
377 t->table->setLimits(limits);
378 auto *newType = make<WasmTableType>(*tableType);
379 newType->Limits = limits;
380 tableType = newType;
381 }
382
getTableNumber() const383 uint32_t TableSymbol::getTableNumber() const {
384 if (const auto *t = dyn_cast<DefinedTable>(this))
385 return t->table->getAssignedIndex();
386 assert(tableNumber != INVALID_INDEX);
387 return tableNumber;
388 }
389
setTableNumber(uint32_t number)390 void TableSymbol::setTableNumber(uint32_t number) {
391 if (const auto *t = dyn_cast<DefinedTable>(this))
392 return t->table->assignIndex(number);
393 LLVM_DEBUG(dbgs() << "setTableNumber " << name << " -> " << number << "\n");
394 assert(tableNumber == INVALID_INDEX);
395 tableNumber = number;
396 }
397
hasTableNumber() const398 bool TableSymbol::hasTableNumber() const {
399 if (const auto *t = dyn_cast<DefinedTable>(this))
400 return t->table->hasAssignedIndex();
401 return tableNumber != INVALID_INDEX;
402 }
403
DefinedTable(StringRef name,uint32_t flags,InputFile * file,InputTable * table)404 DefinedTable::DefinedTable(StringRef name, uint32_t flags, InputFile *file,
405 InputTable *table)
406 : TableSymbol(name, DefinedTableKind, flags, file,
407 table ? &table->getType() : nullptr),
408 table(table) {}
409
getOutputSectionSymbol() const410 const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const {
411 assert(section->outputSec && section->outputSec->sectionSym);
412 return section->outputSec->sectionSym;
413 }
414
fetch()415 void LazySymbol::fetch() { cast<ArchiveFile>(file)->addMember(&archiveSymbol); }
416
setWeak()417 void LazySymbol::setWeak() {
418 flags |= (flags & ~WASM_SYMBOL_BINDING_MASK) | WASM_SYMBOL_BINDING_WEAK;
419 }
420
getMemberBuffer()421 MemoryBufferRef LazySymbol::getMemberBuffer() {
422 Archive::Child c =
423 CHECK(archiveSymbol.getMember(),
424 "could not get the member for symbol " + toString(*this));
425
426 return CHECK(c.getMemoryBufferRef(),
427 "could not get the buffer for the member defining symbol " +
428 toString(*this));
429 }
430
printTraceSymbolUndefined(StringRef name,const InputFile * file)431 void printTraceSymbolUndefined(StringRef name, const InputFile* file) {
432 message(toString(file) + ": reference to " + name);
433 }
434
435 // Print out a log message for --trace-symbol.
printTraceSymbol(Symbol * sym)436 void printTraceSymbol(Symbol *sym) {
437 // Undefined symbols are traced via printTraceSymbolUndefined
438 if (sym->isUndefined())
439 return;
440
441 std::string s;
442 if (sym->isLazy())
443 s = ": lazy definition of ";
444 else
445 s = ": definition of ";
446
447 message(toString(sym->getFile()) + s + sym->getName());
448 }
449
450 const char *defaultModule = "env";
451 const char *functionTableName = "__indirect_function_table";
452
453 } // namespace wasm
454 } // namespace lld
455