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 {
toString(const wasm::Symbol & sym)27 std::string toString(const wasm::Symbol &sym) {
28 return maybeDemangleSymbol(sym.getName());
29 }
30
maybeDemangleSymbol(StringRef name)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
toString(wasm::Symbol::Kind kind)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
getWasmType() const87 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
getSignature() const101 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
getChunk() const109 InputChunk *Symbol::getChunk() const {
110 if (auto *f = dyn_cast<DefinedFunction>(this))
111 return f->function;
112 if (auto *f = dyn_cast<UndefinedFunction>(this))
113 if (f->stubFunction)
114 return f->stubFunction->function;
115 if (auto *d = dyn_cast<DefinedData>(this))
116 return d->segment;
117 return nullptr;
118 }
119
isDiscarded() const120 bool Symbol::isDiscarded() const {
121 if (InputChunk *c = getChunk())
122 return c->discarded;
123 return false;
124 }
125
isLive() const126 bool Symbol::isLive() const {
127 if (auto *g = dyn_cast<DefinedGlobal>(this))
128 return g->global->live;
129 if (auto *e = dyn_cast<DefinedEvent>(this))
130 return e->event->live;
131 if (InputChunk *c = getChunk())
132 return c->live;
133 return referenced;
134 }
135
markLive()136 void Symbol::markLive() {
137 assert(!isDiscarded());
138 if (file != NULL)
139 file->markLive();
140 if (auto *g = dyn_cast<DefinedGlobal>(this))
141 g->global->live = true;
142 if (auto *e = dyn_cast<DefinedEvent>(this))
143 e->event->live = true;
144 if (InputChunk *c = getChunk())
145 c->live = true;
146 referenced = true;
147 }
148
getOutputSymbolIndex() const149 uint32_t Symbol::getOutputSymbolIndex() const {
150 assert(outputSymbolIndex != INVALID_INDEX);
151 return outputSymbolIndex;
152 }
153
setOutputSymbolIndex(uint32_t index)154 void Symbol::setOutputSymbolIndex(uint32_t index) {
155 LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name << " -> " << index
156 << "\n");
157 assert(outputSymbolIndex == INVALID_INDEX);
158 outputSymbolIndex = index;
159 }
160
setGOTIndex(uint32_t index)161 void Symbol::setGOTIndex(uint32_t index) {
162 LLVM_DEBUG(dbgs() << "setGOTIndex " << name << " -> " << index << "\n");
163 assert(gotIndex == INVALID_INDEX);
164 if (config->isPic) {
165 // Any symbol that is assigned a GOT entry must be exported otherwise the
166 // dynamic linker won't be able create the entry that contains it.
167 forceExport = true;
168 }
169 gotIndex = index;
170 }
171
isWeak() const172 bool Symbol::isWeak() const {
173 return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
174 }
175
isLocal() const176 bool Symbol::isLocal() const {
177 return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
178 }
179
isHidden() const180 bool Symbol::isHidden() const {
181 return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
182 }
183
setHidden(bool isHidden)184 void Symbol::setHidden(bool isHidden) {
185 LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n");
186 flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
187 if (isHidden)
188 flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
189 else
190 flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;
191 }
192
isExported() const193 bool Symbol::isExported() const {
194 if (!isDefined() || isLocal())
195 return false;
196
197 if (forceExport || config->exportAll)
198 return true;
199
200 if (config->exportDynamic && !isHidden())
201 return true;
202
203 return flags & WASM_SYMBOL_EXPORTED;
204 }
205
isNoStrip() const206 bool Symbol::isNoStrip() const {
207 return flags & WASM_SYMBOL_NO_STRIP;
208 }
209
getFunctionIndex() const210 uint32_t FunctionSymbol::getFunctionIndex() const {
211 if (auto *f = dyn_cast<DefinedFunction>(this))
212 return f->function->getFunctionIndex();
213 if (const auto *u = dyn_cast<UndefinedFunction>(this)) {
214 if (u->stubFunction) {
215 return u->stubFunction->getFunctionIndex();
216 }
217 }
218 assert(functionIndex != INVALID_INDEX);
219 return functionIndex;
220 }
221
setFunctionIndex(uint32_t index)222 void FunctionSymbol::setFunctionIndex(uint32_t index) {
223 LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n");
224 assert(functionIndex == INVALID_INDEX);
225 functionIndex = index;
226 }
227
hasFunctionIndex() const228 bool FunctionSymbol::hasFunctionIndex() const {
229 if (auto *f = dyn_cast<DefinedFunction>(this))
230 return f->function->hasFunctionIndex();
231 return functionIndex != INVALID_INDEX;
232 }
233
getTableIndex() const234 uint32_t FunctionSymbol::getTableIndex() const {
235 if (auto *f = dyn_cast<DefinedFunction>(this))
236 return f->function->getTableIndex();
237 assert(tableIndex != INVALID_INDEX);
238 return tableIndex;
239 }
240
hasTableIndex() const241 bool FunctionSymbol::hasTableIndex() const {
242 if (auto *f = dyn_cast<DefinedFunction>(this))
243 return f->function->hasTableIndex();
244 return tableIndex != INVALID_INDEX;
245 }
246
setTableIndex(uint32_t index)247 void FunctionSymbol::setTableIndex(uint32_t index) {
248 // For imports, we set the table index here on the Symbol; for defined
249 // functions we set the index on the InputFunction so that we don't export
250 // the same thing twice (keeps the table size down).
251 if (auto *f = dyn_cast<DefinedFunction>(this)) {
252 f->function->setTableIndex(index);
253 return;
254 }
255 LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n");
256 assert(tableIndex == INVALID_INDEX);
257 tableIndex = index;
258 }
259
DefinedFunction(StringRef name,uint32_t flags,InputFile * f,InputFunction * function)260 DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f,
261 InputFunction *function)
262 : FunctionSymbol(name, DefinedFunctionKind, flags, f,
263 function ? &function->signature : nullptr),
264 function(function) {}
265
getVirtualAddress() const266 uint64_t DefinedData::getVirtualAddress() const {
267 LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
268 if (segment)
269 return segment->outputSeg->startVA + segment->outputSegmentOffset + offset;
270 return offset;
271 }
272
setVirtualAddress(uint64_t value)273 void DefinedData::setVirtualAddress(uint64_t value) {
274 LLVM_DEBUG(dbgs() << "setVirtualAddress " << name << " -> " << value << "\n");
275 assert(!segment);
276 offset = value;
277 }
278
getOutputSegmentOffset() const279 uint64_t DefinedData::getOutputSegmentOffset() const {
280 LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
281 return segment->outputSegmentOffset + offset;
282 }
283
getOutputSegmentIndex() const284 uint64_t DefinedData::getOutputSegmentIndex() const {
285 LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
286 return segment->outputSeg->index;
287 }
288
getGlobalIndex() const289 uint32_t GlobalSymbol::getGlobalIndex() const {
290 if (auto *f = dyn_cast<DefinedGlobal>(this))
291 return f->global->getGlobalIndex();
292 assert(globalIndex != INVALID_INDEX);
293 return globalIndex;
294 }
295
setGlobalIndex(uint32_t index)296 void GlobalSymbol::setGlobalIndex(uint32_t index) {
297 LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n");
298 assert(globalIndex == INVALID_INDEX);
299 globalIndex = index;
300 }
301
hasGlobalIndex() const302 bool GlobalSymbol::hasGlobalIndex() const {
303 if (auto *f = dyn_cast<DefinedGlobal>(this))
304 return f->global->hasGlobalIndex();
305 return globalIndex != INVALID_INDEX;
306 }
307
DefinedGlobal(StringRef name,uint32_t flags,InputFile * file,InputGlobal * global)308 DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,
309 InputGlobal *global)
310 : GlobalSymbol(name, DefinedGlobalKind, flags, file,
311 global ? &global->getType() : nullptr),
312 global(global) {}
313
getEventIndex() const314 uint32_t EventSymbol::getEventIndex() const {
315 if (auto *f = dyn_cast<DefinedEvent>(this))
316 return f->event->getEventIndex();
317 assert(eventIndex != INVALID_INDEX);
318 return eventIndex;
319 }
320
setEventIndex(uint32_t index)321 void EventSymbol::setEventIndex(uint32_t index) {
322 LLVM_DEBUG(dbgs() << "setEventIndex " << name << " -> " << index << "\n");
323 assert(eventIndex == INVALID_INDEX);
324 eventIndex = index;
325 }
326
hasEventIndex() const327 bool EventSymbol::hasEventIndex() const {
328 if (auto *f = dyn_cast<DefinedEvent>(this))
329 return f->event->hasEventIndex();
330 return eventIndex != INVALID_INDEX;
331 }
332
DefinedEvent(StringRef name,uint32_t flags,InputFile * file,InputEvent * event)333 DefinedEvent::DefinedEvent(StringRef name, uint32_t flags, InputFile *file,
334 InputEvent *event)
335 : EventSymbol(name, DefinedEventKind, flags, file,
336 event ? &event->getType() : nullptr,
337 event ? &event->signature : nullptr),
338 event(event) {}
339
getOutputSectionSymbol() const340 const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const {
341 assert(section->outputSec && section->outputSec->sectionSym);
342 return section->outputSec->sectionSym;
343 }
344
fetch()345 void LazySymbol::fetch() { cast<ArchiveFile>(file)->addMember(&archiveSymbol); }
346
setWeak()347 void LazySymbol::setWeak() {
348 flags |= (flags & ~WASM_SYMBOL_BINDING_MASK) | WASM_SYMBOL_BINDING_WEAK;
349 }
350
getMemberBuffer()351 MemoryBufferRef LazySymbol::getMemberBuffer() {
352 Archive::Child c =
353 CHECK(archiveSymbol.getMember(),
354 "could not get the member for symbol " + toString(*this));
355
356 return CHECK(c.getMemoryBufferRef(),
357 "could not get the buffer for the member defining symbol " +
358 toString(*this));
359 }
360
printTraceSymbolUndefined(StringRef name,const InputFile * file)361 void printTraceSymbolUndefined(StringRef name, const InputFile* file) {
362 message(toString(file) + ": reference to " + name);
363 }
364
365 // Print out a log message for --trace-symbol.
printTraceSymbol(Symbol * sym)366 void printTraceSymbol(Symbol *sym) {
367 // Undefined symbols are traced via printTraceSymbolUndefined
368 if (sym->isUndefined())
369 return;
370
371 std::string s;
372 if (sym->isLazy())
373 s = ": lazy definition of ";
374 else
375 s = ": definition of ";
376
377 message(toString(sym->getFile()) + s + sym->getName());
378 }
379
380 const char *defaultModule = "env";
381 const char *functionTableName = "__indirect_function_table";
382
383 } // namespace wasm
384 } // namespace lld
385