xref: /llvm-project-15.0.7/lld/wasm/Symbols.cpp (revision a895a446)
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 "InputEvent.h"
13 #include "InputFiles.h"
14 #include "InputGlobal.h"
15 #include "OutputSections.h"
16 #include "OutputSegment.h"
17 #include "lld/Common/ErrorHandler.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::DefinedEventKind:
50     return "DefinedEvent";
51   case wasm::Symbol::UndefinedFunctionKind:
52     return "UndefinedFunction";
53   case wasm::Symbol::UndefinedDataKind:
54     return "UndefinedData";
55   case wasm::Symbol::UndefinedGlobalKind:
56     return "UndefinedGlobal";
57   case wasm::Symbol::LazyKind:
58     return "LazyKind";
59   case wasm::Symbol::SectionKind:
60     return "SectionKind";
61   case wasm::Symbol::OutputSectionKind:
62     return "OutputSectionKind";
63   }
64   llvm_unreachable("invalid symbol kind");
65 }
66 
67 namespace wasm {
68 DefinedFunction *WasmSym::callCtors;
69 DefinedFunction *WasmSym::callDtors;
70 DefinedFunction *WasmSym::initMemory;
71 DefinedFunction *WasmSym::applyRelocs;
72 DefinedFunction *WasmSym::initTLS;
73 DefinedData *WasmSym::dsoHandle;
74 DefinedData *WasmSym::dataEnd;
75 DefinedData *WasmSym::globalBase;
76 DefinedData *WasmSym::heapBase;
77 DefinedData *WasmSym::initMemoryFlag;
78 GlobalSymbol *WasmSym::stackPointer;
79 GlobalSymbol *WasmSym::tlsBase;
80 GlobalSymbol *WasmSym::tlsSize;
81 GlobalSymbol *WasmSym::tlsAlign;
82 UndefinedGlobal *WasmSym::tableBase;
83 DefinedData *WasmSym::definedTableBase;
84 UndefinedGlobal *WasmSym::memoryBase;
85 DefinedData *WasmSym::definedMemoryBase;
86 
87 WasmSymbolType Symbol::getWasmType() const {
88   if (isa<FunctionSymbol>(this))
89     return WASM_SYMBOL_TYPE_FUNCTION;
90   if (isa<DataSymbol>(this))
91     return WASM_SYMBOL_TYPE_DATA;
92   if (isa<GlobalSymbol>(this))
93     return WASM_SYMBOL_TYPE_GLOBAL;
94   if (isa<EventSymbol>(this))
95     return WASM_SYMBOL_TYPE_EVENT;
96   if (isa<SectionSymbol>(this) || isa<OutputSectionSymbol>(this))
97     return WASM_SYMBOL_TYPE_SECTION;
98   llvm_unreachable("invalid symbol kind");
99 }
100 
101 const WasmSignature *Symbol::getSignature() const {
102   if (auto* f = dyn_cast<FunctionSymbol>(this))
103     return f->signature;
104   if (auto *l = dyn_cast<LazySymbol>(this))
105     return l->signature;
106   return nullptr;
107 }
108 
109 InputChunk *Symbol::getChunk() const {
110   if (auto *f = dyn_cast<DefinedFunction>(this))
111     return f->function;
112   if (auto *d = dyn_cast<DefinedData>(this))
113     return d->segment;
114   return nullptr;
115 }
116 
117 bool Symbol::isDiscarded() const {
118   if (InputChunk *c = getChunk())
119     return c->discarded;
120   return false;
121 }
122 
123 bool Symbol::isLive() const {
124   if (auto *g = dyn_cast<DefinedGlobal>(this))
125     return g->global->live;
126   if (auto *e = dyn_cast<DefinedEvent>(this))
127     return e->event->live;
128   if (InputChunk *c = getChunk())
129     return c->live;
130   return referenced;
131 }
132 
133 void Symbol::markLive() {
134   assert(!isDiscarded());
135   if (file != NULL)
136     file->markLive();
137   if (auto *g = dyn_cast<DefinedGlobal>(this))
138     g->global->live = true;
139   if (auto *e = dyn_cast<DefinedEvent>(this))
140     e->event->live = true;
141   if (InputChunk *c = getChunk())
142     c->live = true;
143   referenced = true;
144 }
145 
146 uint32_t Symbol::getOutputSymbolIndex() const {
147   assert(outputSymbolIndex != INVALID_INDEX);
148   return outputSymbolIndex;
149 }
150 
151 void Symbol::setOutputSymbolIndex(uint32_t index) {
152   LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name << " -> " << index
153                     << "\n");
154   assert(outputSymbolIndex == INVALID_INDEX);
155   outputSymbolIndex = index;
156 }
157 
158 void Symbol::setGOTIndex(uint32_t index) {
159   LLVM_DEBUG(dbgs() << "setGOTIndex " << name << " -> " << index << "\n");
160   assert(gotIndex == INVALID_INDEX);
161   if (config->isPic) {
162     // Any symbol that is assigned a GOT entry must be exported otherwise the
163     // dynamic linker won't be able create the entry that contains it.
164     forceExport = true;
165   }
166   gotIndex = index;
167 }
168 
169 bool Symbol::isWeak() const {
170   return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
171 }
172 
173 bool Symbol::isLocal() const {
174   return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
175 }
176 
177 bool Symbol::isHidden() const {
178   return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
179 }
180 
181 void Symbol::setHidden(bool isHidden) {
182   LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n");
183   flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
184   if (isHidden)
185     flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
186   else
187     flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;
188 }
189 
190 bool Symbol::isExported() const {
191   if (!isDefined() || isLocal())
192     return false;
193 
194   if (forceExport || config->exportAll)
195     return true;
196 
197   if (config->exportDynamic && !isHidden())
198     return true;
199 
200   return flags & WASM_SYMBOL_EXPORTED;
201 }
202 
203 bool Symbol::isNoStrip() const {
204   return flags & WASM_SYMBOL_NO_STRIP;
205 }
206 
207 uint32_t FunctionSymbol::getFunctionIndex() const {
208   if (auto *f = dyn_cast<DefinedFunction>(this))
209     return f->function->getFunctionIndex();
210   assert(functionIndex != INVALID_INDEX);
211   return functionIndex;
212 }
213 
214 void FunctionSymbol::setFunctionIndex(uint32_t index) {
215   LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n");
216   assert(functionIndex == INVALID_INDEX);
217   functionIndex = index;
218 }
219 
220 bool FunctionSymbol::hasFunctionIndex() const {
221   if (auto *f = dyn_cast<DefinedFunction>(this))
222     return f->function->hasFunctionIndex();
223   return functionIndex != INVALID_INDEX;
224 }
225 
226 uint32_t FunctionSymbol::getTableIndex() const {
227   if (auto *f = dyn_cast<DefinedFunction>(this))
228     return f->function->getTableIndex();
229   assert(tableIndex != INVALID_INDEX);
230   return tableIndex;
231 }
232 
233 bool FunctionSymbol::hasTableIndex() const {
234   if (auto *f = dyn_cast<DefinedFunction>(this))
235     return f->function->hasTableIndex();
236   return tableIndex != INVALID_INDEX;
237 }
238 
239 void FunctionSymbol::setTableIndex(uint32_t index) {
240   // For imports, we set the table index here on the Symbol; for defined
241   // functions we set the index on the InputFunction so that we don't export
242   // the same thing twice (keeps the table size down).
243   if (auto *f = dyn_cast<DefinedFunction>(this)) {
244     f->function->setTableIndex(index);
245     return;
246   }
247   LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n");
248   assert(tableIndex == INVALID_INDEX);
249   tableIndex = index;
250 }
251 
252 DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f,
253                                  InputFunction *function)
254     : FunctionSymbol(name, DefinedFunctionKind, flags, f,
255                      function ? &function->signature : nullptr),
256       function(function) {}
257 
258 uint64_t DefinedData::getVirtualAddress() const {
259   LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
260   if (segment) {
261     // For thread local data, the symbol location is relative to the start of
262     // the .tdata section, since they are used as offsets from __tls_base.
263     // Hence, we do not add in segment->outputSeg->startVA.
264     if (segment->outputSeg->name == ".tdata")
265       return segment->outputSegmentOffset + offset;
266     return segment->outputSeg->startVA + segment->outputSegmentOffset + offset;
267   }
268   return offset;
269 }
270 
271 void DefinedData::setVirtualAddress(uint64_t value) {
272   LLVM_DEBUG(dbgs() << "setVirtualAddress " << name << " -> " << value << "\n");
273   assert(!segment);
274   offset = value;
275 }
276 
277 uint64_t DefinedData::getOutputSegmentOffset() const {
278   LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
279   return segment->outputSegmentOffset + offset;
280 }
281 
282 uint64_t DefinedData::getOutputSegmentIndex() const {
283   LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
284   return segment->outputSeg->index;
285 }
286 
287 uint32_t GlobalSymbol::getGlobalIndex() const {
288   if (auto *f = dyn_cast<DefinedGlobal>(this))
289     return f->global->getGlobalIndex();
290   assert(globalIndex != INVALID_INDEX);
291   return globalIndex;
292 }
293 
294 void GlobalSymbol::setGlobalIndex(uint32_t index) {
295   LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n");
296   assert(globalIndex == INVALID_INDEX);
297   globalIndex = index;
298 }
299 
300 bool GlobalSymbol::hasGlobalIndex() const {
301   if (auto *f = dyn_cast<DefinedGlobal>(this))
302     return f->global->hasGlobalIndex();
303   return globalIndex != INVALID_INDEX;
304 }
305 
306 DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,
307                              InputGlobal *global)
308     : GlobalSymbol(name, DefinedGlobalKind, flags, file,
309                    global ? &global->getType() : nullptr),
310       global(global) {}
311 
312 uint32_t EventSymbol::getEventIndex() const {
313   if (auto *f = dyn_cast<DefinedEvent>(this))
314     return f->event->getEventIndex();
315   assert(eventIndex != INVALID_INDEX);
316   return eventIndex;
317 }
318 
319 void EventSymbol::setEventIndex(uint32_t index) {
320   LLVM_DEBUG(dbgs() << "setEventIndex " << name << " -> " << index << "\n");
321   assert(eventIndex == INVALID_INDEX);
322   eventIndex = index;
323 }
324 
325 bool EventSymbol::hasEventIndex() const {
326   if (auto *f = dyn_cast<DefinedEvent>(this))
327     return f->event->hasEventIndex();
328   return eventIndex != INVALID_INDEX;
329 }
330 
331 DefinedEvent::DefinedEvent(StringRef name, uint32_t flags, InputFile *file,
332                            InputEvent *event)
333     : EventSymbol(name, DefinedEventKind, flags, file,
334                   event ? &event->getType() : nullptr,
335                   event ? &event->signature : nullptr),
336       event(event) {}
337 
338 const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const {
339   assert(section->outputSec && section->outputSec->sectionSym);
340   return section->outputSec->sectionSym;
341 }
342 
343 void LazySymbol::fetch() { cast<ArchiveFile>(file)->addMember(&archiveSymbol); }
344 
345 void LazySymbol::setWeak() {
346   flags |= (flags & ~WASM_SYMBOL_BINDING_MASK) | WASM_SYMBOL_BINDING_WEAK;
347 }
348 
349 MemoryBufferRef LazySymbol::getMemberBuffer() {
350   Archive::Child c =
351       CHECK(archiveSymbol.getMember(),
352             "could not get the member for symbol " + toString(*this));
353 
354   return CHECK(c.getMemoryBufferRef(),
355                "could not get the buffer for the member defining symbol " +
356                    toString(*this));
357 }
358 
359 void printTraceSymbolUndefined(StringRef name, const InputFile* file) {
360   message(toString(file) + ": reference to " + name);
361 }
362 
363 // Print out a log message for --trace-symbol.
364 void printTraceSymbol(Symbol *sym) {
365   // Undefined symbols are traced via printTraceSymbolUndefined
366   if (sym->isUndefined())
367     return;
368 
369   std::string s;
370   if (sym->isLazy())
371     s = ": lazy definition of ";
372   else
373     s = ": definition of ";
374 
375   message(toString(sym->getFile()) + s + sym->getName());
376 }
377 
378 const char *defaultModule = "env";
379 const char *functionTableName = "__indirect_function_table";
380 
381 } // namespace wasm
382 } // namespace lld
383