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