1 //===- Symbols.cpp --------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
11 #include "InputChunks.h"
12 #include "InputElement.h"
13 #include "InputFiles.h"
14 #include "OutputSections.h"
15 #include "OutputSegment.h"
16 #include "SymbolTable.h"
17 #include "lld/Common/ErrorHandler.h"
18 #include "lld/Common/Memory.h"
19 #include "llvm/Demangle/Demangle.h"
21 #define DEBUG_TYPE "lld"
24 using namespace llvm::object
;
25 using namespace llvm::wasm
;
26 using namespace lld::wasm
;
29 std::string
toString(const wasm::Symbol
&sym
) {
30 return maybeDemangleSymbol(sym
.getName());
33 std::string
maybeDemangleSymbol(StringRef name
) {
34 // WebAssembly requires caller and callee signatures to match, so we mangle
35 // `main` in the case where we need to pass it arguments.
36 if (name
== "__main_argc_argv")
38 if (wasm::config
->demangle
)
39 return demangle(name
);
43 std::string
toString(wasm::Symbol::Kind kind
) {
45 case wasm::Symbol::DefinedFunctionKind
:
46 return "DefinedFunction";
47 case wasm::Symbol::DefinedDataKind
:
49 case wasm::Symbol::DefinedGlobalKind
:
50 return "DefinedGlobal";
51 case wasm::Symbol::DefinedTableKind
:
52 return "DefinedTable";
53 case wasm::Symbol::DefinedTagKind
:
55 case wasm::Symbol::UndefinedFunctionKind
:
56 return "UndefinedFunction";
57 case wasm::Symbol::UndefinedDataKind
:
58 return "UndefinedData";
59 case wasm::Symbol::UndefinedGlobalKind
:
60 return "UndefinedGlobal";
61 case wasm::Symbol::UndefinedTableKind
:
62 return "UndefinedTable";
63 case wasm::Symbol::UndefinedTagKind
:
64 return "UndefinedTag";
65 case wasm::Symbol::LazyKind
:
67 case wasm::Symbol::SectionKind
:
69 case wasm::Symbol::OutputSectionKind
:
70 return "OutputSectionKind";
71 case wasm::Symbol::SharedFunctionKind
:
72 return "SharedFunctionKind";
73 case wasm::Symbol::SharedDataKind
:
74 return "SharedDataKind";
76 llvm_unreachable("invalid symbol kind");
80 DefinedFunction
*WasmSym::callCtors
;
81 DefinedFunction
*WasmSym::callDtors
;
82 DefinedFunction
*WasmSym::initMemory
;
83 DefinedFunction
*WasmSym::applyGlobalRelocs
;
84 DefinedFunction
*WasmSym::applyTLSRelocs
;
85 DefinedFunction
*WasmSym::applyGlobalTLSRelocs
;
86 DefinedFunction
*WasmSym::initTLS
;
87 DefinedFunction
*WasmSym::startFunction
;
88 DefinedData
*WasmSym::dsoHandle
;
89 DefinedData
*WasmSym::dataEnd
;
90 DefinedData
*WasmSym::globalBase
;
91 DefinedData
*WasmSym::heapBase
;
92 DefinedData
*WasmSym::heapEnd
;
93 DefinedData
*WasmSym::initMemoryFlag
;
94 GlobalSymbol
*WasmSym::stackPointer
;
95 DefinedData
*WasmSym::stackLow
;
96 DefinedData
*WasmSym::stackHigh
;
97 GlobalSymbol
*WasmSym::tlsBase
;
98 GlobalSymbol
*WasmSym::tlsSize
;
99 GlobalSymbol
*WasmSym::tlsAlign
;
100 UndefinedGlobal
*WasmSym::tableBase
;
101 DefinedData
*WasmSym::definedTableBase
;
102 UndefinedGlobal
*WasmSym::memoryBase
;
103 DefinedData
*WasmSym::definedMemoryBase
;
104 TableSymbol
*WasmSym::indirectFunctionTable
;
106 WasmSymbolType
Symbol::getWasmType() const {
107 if (isa
<FunctionSymbol
>(this))
108 return WASM_SYMBOL_TYPE_FUNCTION
;
109 if (isa
<DataSymbol
>(this))
110 return WASM_SYMBOL_TYPE_DATA
;
111 if (isa
<GlobalSymbol
>(this))
112 return WASM_SYMBOL_TYPE_GLOBAL
;
113 if (isa
<TagSymbol
>(this))
114 return WASM_SYMBOL_TYPE_TAG
;
115 if (isa
<TableSymbol
>(this))
116 return WASM_SYMBOL_TYPE_TABLE
;
117 if (isa
<SectionSymbol
>(this) || isa
<OutputSectionSymbol
>(this))
118 return WASM_SYMBOL_TYPE_SECTION
;
119 llvm_unreachable("invalid symbol kind");
122 const WasmSignature
*Symbol::getSignature() const {
123 if (auto* f
= dyn_cast
<FunctionSymbol
>(this))
125 if (auto *t
= dyn_cast
<TagSymbol
>(this))
127 if (auto *l
= dyn_cast
<LazySymbol
>(this))
132 InputChunk
*Symbol::getChunk() const {
133 if (auto *f
= dyn_cast
<DefinedFunction
>(this))
135 if (auto *f
= dyn_cast
<UndefinedFunction
>(this))
137 return f
->stubFunction
->function
;
138 if (auto *d
= dyn_cast
<DefinedData
>(this))
143 bool Symbol::isDiscarded() const {
144 if (InputChunk
*c
= getChunk())
149 bool Symbol::isLive() const {
150 if (auto *g
= dyn_cast
<DefinedGlobal
>(this))
151 return g
->global
->live
;
152 if (auto *t
= dyn_cast
<DefinedTag
>(this))
154 if (auto *t
= dyn_cast
<DefinedTable
>(this))
155 return t
->table
->live
;
156 if (InputChunk
*c
= getChunk())
161 void Symbol::markLive() {
162 assert(!isDiscarded());
164 if (file
!= nullptr && isDefined())
166 if (auto *g
= dyn_cast
<DefinedGlobal
>(this))
167 g
->global
->live
= true;
168 if (auto *t
= dyn_cast
<DefinedTag
>(this))
170 if (auto *t
= dyn_cast
<DefinedTable
>(this))
171 t
->table
->live
= true;
172 if (InputChunk
*c
= getChunk()) {
173 // Usually, a whole chunk is marked as live or dead, but in mergeable
174 // (splittable) sections, each piece of data has independent liveness bit.
175 // So we explicitly tell it which offset is in use.
176 if (auto *d
= dyn_cast
<DefinedData
>(this)) {
177 if (auto *ms
= dyn_cast
<MergeInputChunk
>(c
)) {
178 ms
->getSectionPiece(d
->value
)->live
= true;
185 uint32_t Symbol::getOutputSymbolIndex() const {
186 assert(outputSymbolIndex
!= INVALID_INDEX
);
187 return outputSymbolIndex
;
190 void Symbol::setOutputSymbolIndex(uint32_t index
) {
191 LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name
<< " -> " << index
193 assert(outputSymbolIndex
== INVALID_INDEX
);
194 outputSymbolIndex
= index
;
197 void Symbol::setGOTIndex(uint32_t index
) {
198 LLVM_DEBUG(dbgs() << "setGOTIndex " << name
<< " -> " << index
<< "\n");
199 assert(gotIndex
== INVALID_INDEX
);
203 bool Symbol::isWeak() const {
204 return (flags
& WASM_SYMBOL_BINDING_MASK
) == WASM_SYMBOL_BINDING_WEAK
;
207 bool Symbol::isLocal() const {
208 return (flags
& WASM_SYMBOL_BINDING_MASK
) == WASM_SYMBOL_BINDING_LOCAL
;
211 bool Symbol::isHidden() const {
212 return (flags
& WASM_SYMBOL_VISIBILITY_MASK
) == WASM_SYMBOL_VISIBILITY_HIDDEN
;
215 bool Symbol::isTLS() const { return flags
& WASM_SYMBOL_TLS
; }
217 void Symbol::setHidden(bool isHidden
) {
218 LLVM_DEBUG(dbgs() << "setHidden: " << name
<< " -> " << isHidden
<< "\n");
219 flags
&= ~WASM_SYMBOL_VISIBILITY_MASK
;
221 flags
|= WASM_SYMBOL_VISIBILITY_HIDDEN
;
223 flags
|= WASM_SYMBOL_VISIBILITY_DEFAULT
;
226 bool Symbol::isImported() const {
228 (isUndefined() && (importName
.has_value() || forceImport
));
231 bool Symbol::isExported() const {
232 if (!isDefined() || isShared() || isLocal())
235 // Shared libraries must export all weakly defined symbols
236 // in case they contain the version that will be chosen by
237 // the dynamic linker.
238 if (config
->shared
&& isLive() && isWeak() && !isHidden())
241 if (config
->exportAll
|| (config
->exportDynamic
&& !isHidden()))
244 return isExportedExplicit();
247 bool Symbol::isExportedExplicit() const {
248 return forceExport
|| flags
& WASM_SYMBOL_EXPORTED
;
251 bool Symbol::isNoStrip() const {
252 return flags
& WASM_SYMBOL_NO_STRIP
;
255 uint32_t FunctionSymbol::getFunctionIndex() const {
256 if (const auto *u
= dyn_cast
<UndefinedFunction
>(this))
258 return u
->stubFunction
->getFunctionIndex();
259 if (functionIndex
!= INVALID_INDEX
)
260 return functionIndex
;
261 auto *f
= cast
<DefinedFunction
>(this);
262 return f
->function
->getFunctionIndex();
265 void FunctionSymbol::setFunctionIndex(uint32_t index
) {
266 LLVM_DEBUG(dbgs() << "setFunctionIndex " << name
<< " -> " << index
<< "\n");
267 assert(functionIndex
== INVALID_INDEX
);
268 functionIndex
= index
;
271 bool FunctionSymbol::hasFunctionIndex() const {
272 if (auto *f
= dyn_cast
<DefinedFunction
>(this))
273 return f
->function
->hasFunctionIndex();
274 return functionIndex
!= INVALID_INDEX
;
277 uint32_t FunctionSymbol::getTableIndex() const {
278 if (auto *f
= dyn_cast
<DefinedFunction
>(this))
279 return f
->function
->getTableIndex();
280 assert(tableIndex
!= INVALID_INDEX
);
284 bool FunctionSymbol::hasTableIndex() const {
285 if (auto *f
= dyn_cast
<DefinedFunction
>(this))
286 return f
->function
->hasTableIndex();
287 return tableIndex
!= INVALID_INDEX
;
290 void FunctionSymbol::setTableIndex(uint32_t index
) {
291 // For imports, we set the table index here on the Symbol; for defined
292 // functions we set the index on the InputFunction so that we don't export
293 // the same thing twice (keeps the table size down).
294 if (auto *f
= dyn_cast
<DefinedFunction
>(this)) {
295 f
->function
->setTableIndex(index
);
298 LLVM_DEBUG(dbgs() << "setTableIndex " << name
<< " -> " << index
<< "\n");
299 assert(tableIndex
== INVALID_INDEX
);
303 DefinedFunction::DefinedFunction(StringRef name
, uint32_t flags
, InputFile
*f
,
304 InputFunction
*function
)
305 : FunctionSymbol(name
, DefinedFunctionKind
, flags
, f
,
306 function
? &function
->signature
: nullptr),
307 function(function
) {}
309 uint32_t DefinedFunction::getExportedFunctionIndex() const {
310 return function
->getFunctionIndex();
313 uint64_t DefinedData::getVA(bool absolute
) const {
314 LLVM_DEBUG(dbgs() << "getVA: " << getName() << "\n");
315 // TLS symbols (by default) are relative to the start of the TLS output
316 // segment (__tls_base).
317 if (isTLS() && !absolute
)
318 return getOutputSegmentOffset();
320 return segment
->getVA(value
);
324 void DefinedData::setVA(uint64_t value_
) {
325 LLVM_DEBUG(dbgs() << "setVA " << name
<< " -> " << value_
<< "\n");
330 uint64_t DefinedData::getOutputSegmentOffset() const {
331 LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
332 return segment
->getChunkOffset(value
);
335 uint64_t DefinedData::getOutputSegmentIndex() const {
336 LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
337 return segment
->outputSeg
->index
;
340 uint32_t GlobalSymbol::getGlobalIndex() const {
341 if (auto *f
= dyn_cast
<DefinedGlobal
>(this))
342 return f
->global
->getAssignedIndex();
343 assert(globalIndex
!= INVALID_INDEX
);
347 void GlobalSymbol::setGlobalIndex(uint32_t index
) {
348 LLVM_DEBUG(dbgs() << "setGlobalIndex " << name
<< " -> " << index
<< "\n");
349 assert(globalIndex
== INVALID_INDEX
);
353 bool GlobalSymbol::hasGlobalIndex() const {
354 if (auto *f
= dyn_cast
<DefinedGlobal
>(this))
355 return f
->global
->hasAssignedIndex();
356 return globalIndex
!= INVALID_INDEX
;
359 DefinedGlobal::DefinedGlobal(StringRef name
, uint32_t flags
, InputFile
*file
,
361 : GlobalSymbol(name
, DefinedGlobalKind
, flags
, file
,
362 global
? &global
->getType() : nullptr),
365 uint32_t TagSymbol::getTagIndex() const {
366 if (auto *f
= dyn_cast
<DefinedTag
>(this))
367 return f
->tag
->getAssignedIndex();
368 assert(tagIndex
!= INVALID_INDEX
);
372 void TagSymbol::setTagIndex(uint32_t index
) {
373 LLVM_DEBUG(dbgs() << "setTagIndex " << name
<< " -> " << index
<< "\n");
374 assert(tagIndex
== INVALID_INDEX
);
378 bool TagSymbol::hasTagIndex() const {
379 if (auto *f
= dyn_cast
<DefinedTag
>(this))
380 return f
->tag
->hasAssignedIndex();
381 return tagIndex
!= INVALID_INDEX
;
384 DefinedTag::DefinedTag(StringRef name
, uint32_t flags
, InputFile
*file
,
386 : TagSymbol(name
, DefinedTagKind
, flags
, file
,
387 tag
? &tag
->signature
: nullptr),
390 void TableSymbol::setLimits(const WasmLimits
&limits
) {
391 if (auto *t
= dyn_cast
<DefinedTable
>(this))
392 t
->table
->setLimits(limits
);
393 auto *newType
= make
<WasmTableType
>(*tableType
);
394 newType
->Limits
= limits
;
398 uint32_t TableSymbol::getTableNumber() const {
399 if (const auto *t
= dyn_cast
<DefinedTable
>(this))
400 return t
->table
->getAssignedIndex();
401 assert(tableNumber
!= INVALID_INDEX
);
405 void TableSymbol::setTableNumber(uint32_t number
) {
406 if (const auto *t
= dyn_cast
<DefinedTable
>(this))
407 return t
->table
->assignIndex(number
);
408 LLVM_DEBUG(dbgs() << "setTableNumber " << name
<< " -> " << number
<< "\n");
409 assert(tableNumber
== INVALID_INDEX
);
410 tableNumber
= number
;
413 bool TableSymbol::hasTableNumber() const {
414 if (const auto *t
= dyn_cast
<DefinedTable
>(this))
415 return t
->table
->hasAssignedIndex();
416 return tableNumber
!= INVALID_INDEX
;
419 DefinedTable::DefinedTable(StringRef name
, uint32_t flags
, InputFile
*file
,
421 : TableSymbol(name
, DefinedTableKind
, flags
, file
,
422 table
? &table
->getType() : nullptr),
425 const OutputSectionSymbol
*SectionSymbol::getOutputSectionSymbol() const {
426 assert(section
->outputSec
&& section
->outputSec
->sectionSym
);
427 return section
->outputSec
->sectionSym
;
430 void LazySymbol::extract() {
433 symtab
->addFile(file
, name
);
437 void LazySymbol::setWeak() {
438 flags
|= (flags
& ~WASM_SYMBOL_BINDING_MASK
) | WASM_SYMBOL_BINDING_WEAK
;
441 void printTraceSymbolUndefined(StringRef name
, const InputFile
* file
) {
442 message(toString(file
) + ": reference to " + name
);
445 // Print out a log message for --trace-symbol.
446 void printTraceSymbol(Symbol
*sym
) {
447 // Undefined symbols are traced via printTraceSymbolUndefined
448 if (sym
->isUndefined())
453 s
= ": lazy definition of ";
455 s
= ": definition of ";
457 message(toString(sym
->getFile()) + s
+ sym
->getName());
460 const char *defaultModule
= "env";
461 const char *functionTableName
= "__indirect_function_table";
462 const char *memoryName
= "memory";