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