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