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