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