llvm-project
462 строки · 13.9 Кб
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 "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"20
21#define DEBUG_TYPE "lld"22
23using namespace llvm;24using namespace llvm::object;25using namespace llvm::wasm;26using namespace lld::wasm;27
28namespace lld {29std::string toString(const wasm::Symbol &sym) {30return maybeDemangleSymbol(sym.getName());31}
32
33std::string maybeDemangleSymbol(StringRef name) {34// WebAssembly requires caller and callee signatures to match, so we mangle35// `main` in the case where we need to pass it arguments.36if (name == "__main_argc_argv")37return "main";38if (wasm::config->demangle)39return demangle(name);40return name.str();41}
42
43std::string toString(wasm::Symbol::Kind kind) {44switch (kind) {45case wasm::Symbol::DefinedFunctionKind:46return "DefinedFunction";47case wasm::Symbol::DefinedDataKind:48return "DefinedData";49case wasm::Symbol::DefinedGlobalKind:50return "DefinedGlobal";51case wasm::Symbol::DefinedTableKind:52return "DefinedTable";53case wasm::Symbol::DefinedTagKind:54return "DefinedTag";55case wasm::Symbol::UndefinedFunctionKind:56return "UndefinedFunction";57case wasm::Symbol::UndefinedDataKind:58return "UndefinedData";59case wasm::Symbol::UndefinedGlobalKind:60return "UndefinedGlobal";61case wasm::Symbol::UndefinedTableKind:62return "UndefinedTable";63case wasm::Symbol::UndefinedTagKind:64return "UndefinedTag";65case wasm::Symbol::LazyKind:66return "LazyKind";67case wasm::Symbol::SectionKind:68return "SectionKind";69case wasm::Symbol::OutputSectionKind:70return "OutputSectionKind";71}72llvm_unreachable("invalid symbol kind");73}
74
75namespace wasm {76DefinedFunction *WasmSym::callCtors;77DefinedFunction *WasmSym::callDtors;78DefinedFunction *WasmSym::initMemory;79DefinedFunction *WasmSym::applyDataRelocs;80DefinedFunction *WasmSym::applyGlobalRelocs;81DefinedFunction *WasmSym::applyTLSRelocs;82DefinedFunction *WasmSym::applyGlobalTLSRelocs;83DefinedFunction *WasmSym::initTLS;84DefinedFunction *WasmSym::startFunction;85DefinedData *WasmSym::dsoHandle;86DefinedData *WasmSym::dataEnd;87DefinedData *WasmSym::globalBase;88DefinedData *WasmSym::heapBase;89DefinedData *WasmSym::heapEnd;90DefinedData *WasmSym::initMemoryFlag;91GlobalSymbol *WasmSym::stackPointer;92DefinedData *WasmSym::stackLow;93DefinedData *WasmSym::stackHigh;94GlobalSymbol *WasmSym::tlsBase;95GlobalSymbol *WasmSym::tlsSize;96GlobalSymbol *WasmSym::tlsAlign;97UndefinedGlobal *WasmSym::tableBase;98DefinedData *WasmSym::definedTableBase;99UndefinedGlobal *WasmSym::memoryBase;100DefinedData *WasmSym::definedMemoryBase;101TableSymbol *WasmSym::indirectFunctionTable;102
103WasmSymbolType Symbol::getWasmType() const {104if (isa<FunctionSymbol>(this))105return WASM_SYMBOL_TYPE_FUNCTION;106if (isa<DataSymbol>(this))107return WASM_SYMBOL_TYPE_DATA;108if (isa<GlobalSymbol>(this))109return WASM_SYMBOL_TYPE_GLOBAL;110if (isa<TagSymbol>(this))111return WASM_SYMBOL_TYPE_TAG;112if (isa<TableSymbol>(this))113return WASM_SYMBOL_TYPE_TABLE;114if (isa<SectionSymbol>(this) || isa<OutputSectionSymbol>(this))115return WASM_SYMBOL_TYPE_SECTION;116llvm_unreachable("invalid symbol kind");117}
118
119const WasmSignature *Symbol::getSignature() const {120if (auto* f = dyn_cast<FunctionSymbol>(this))121return f->signature;122if (auto *t = dyn_cast<TagSymbol>(this))123return t->signature;124if (auto *l = dyn_cast<LazySymbol>(this))125return l->signature;126return nullptr;127}
128
129InputChunk *Symbol::getChunk() const {130if (auto *f = dyn_cast<DefinedFunction>(this))131return f->function;132if (auto *f = dyn_cast<UndefinedFunction>(this))133if (f->stubFunction)134return f->stubFunction->function;135if (auto *d = dyn_cast<DefinedData>(this))136return d->segment;137return nullptr;138}
139
140bool Symbol::isDiscarded() const {141if (InputChunk *c = getChunk())142return c->discarded;143return false;144}
145
146bool Symbol::isLive() const {147if (auto *g = dyn_cast<DefinedGlobal>(this))148return g->global->live;149if (auto *t = dyn_cast<DefinedTag>(this))150return t->tag->live;151if (auto *t = dyn_cast<DefinedTable>(this))152return t->table->live;153if (InputChunk *c = getChunk())154return c->live;155return referenced;156}
157
158void Symbol::markLive() {159assert(!isDiscarded());160referenced = true;161if (file != nullptr && isDefined())162file->markLive();163if (auto *g = dyn_cast<DefinedGlobal>(this))164g->global->live = true;165if (auto *t = dyn_cast<DefinedTag>(this))166t->tag->live = true;167if (auto *t = dyn_cast<DefinedTable>(this))168t->table->live = true;169if (InputChunk *c = getChunk()) {170// Usually, a whole chunk is marked as live or dead, but in mergeable171// (splittable) sections, each piece of data has independent liveness bit.172// So we explicitly tell it which offset is in use.173if (auto *d = dyn_cast<DefinedData>(this)) {174if (auto *ms = dyn_cast<MergeInputChunk>(c)) {175ms->getSectionPiece(d->value)->live = true;176}177}178c->live = true;179}180}
181
182uint32_t Symbol::getOutputSymbolIndex() const {183assert(outputSymbolIndex != INVALID_INDEX);184return outputSymbolIndex;185}
186
187void Symbol::setOutputSymbolIndex(uint32_t index) {188LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name << " -> " << index189<< "\n");190assert(outputSymbolIndex == INVALID_INDEX);191outputSymbolIndex = index;192}
193
194void Symbol::setGOTIndex(uint32_t index) {195LLVM_DEBUG(dbgs() << "setGOTIndex " << name << " -> " << index << "\n");196assert(gotIndex == INVALID_INDEX);197gotIndex = index;198}
199
200bool Symbol::isWeak() const {201return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;202}
203
204bool Symbol::isLocal() const {205return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;206}
207
208bool Symbol::isHidden() const {209return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;210}
211
212bool Symbol::isTLS() const { return flags & WASM_SYMBOL_TLS; }213
214void Symbol::setHidden(bool isHidden) {215LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n");216flags &= ~WASM_SYMBOL_VISIBILITY_MASK;217if (isHidden)218flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;219else220flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;221}
222
223bool Symbol::isImported() const {224return isUndefined() && (importName.has_value() || forceImport);225}
226
227bool Symbol::isExported() const {228if (!isDefined() || isLocal())229return false;230
231// Shared libraries must export all weakly defined symbols232// in case they contain the version that will be chosen by233// the dynamic linker.234if (config->shared && isLive() && isWeak() && !isHidden())235return true;236
237if (config->exportAll || (config->exportDynamic && !isHidden()))238return true;239
240return isExportedExplicit();241}
242
243bool Symbol::isExportedExplicit() const {244return forceExport || flags & WASM_SYMBOL_EXPORTED;245}
246
247bool Symbol::isNoStrip() const {248return flags & WASM_SYMBOL_NO_STRIP;249}
250
251uint32_t FunctionSymbol::getFunctionIndex() const {252if (const auto *u = dyn_cast<UndefinedFunction>(this))253if (u->stubFunction)254return u->stubFunction->getFunctionIndex();255if (functionIndex != INVALID_INDEX)256return functionIndex;257auto *f = cast<DefinedFunction>(this);258return f->function->getFunctionIndex();259}
260
261void FunctionSymbol::setFunctionIndex(uint32_t index) {262LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n");263assert(functionIndex == INVALID_INDEX);264functionIndex = index;265}
266
267bool FunctionSymbol::hasFunctionIndex() const {268if (auto *f = dyn_cast<DefinedFunction>(this))269return f->function->hasFunctionIndex();270return functionIndex != INVALID_INDEX;271}
272
273uint32_t FunctionSymbol::getTableIndex() const {274if (auto *f = dyn_cast<DefinedFunction>(this))275return f->function->getTableIndex();276assert(tableIndex != INVALID_INDEX);277return tableIndex;278}
279
280bool FunctionSymbol::hasTableIndex() const {281if (auto *f = dyn_cast<DefinedFunction>(this))282return f->function->hasTableIndex();283return tableIndex != INVALID_INDEX;284}
285
286void FunctionSymbol::setTableIndex(uint32_t index) {287// For imports, we set the table index here on the Symbol; for defined288// functions we set the index on the InputFunction so that we don't export289// the same thing twice (keeps the table size down).290if (auto *f = dyn_cast<DefinedFunction>(this)) {291f->function->setTableIndex(index);292return;293}294LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n");295assert(tableIndex == INVALID_INDEX);296tableIndex = index;297}
298
299DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f,300InputFunction *function)301: FunctionSymbol(name, DefinedFunctionKind, flags, f,302function ? &function->signature : nullptr),303function(function) {}304
305uint32_t DefinedFunction::getExportedFunctionIndex() const {306return function->getFunctionIndex();307}
308
309uint64_t DefinedData::getVA() const {310LLVM_DEBUG(dbgs() << "getVA: " << getName() << "\n");311// In the shared memory case, TLS symbols are relative to the start of the TLS312// output segment (__tls_base). When building without shared memory, TLS313// symbols absolute, just like non-TLS.314if (isTLS() && config->sharedMemory)315return getOutputSegmentOffset();316if (segment)317return segment->getVA(value);318return value;319}
320
321void DefinedData::setVA(uint64_t value_) {322LLVM_DEBUG(dbgs() << "setVA " << name << " -> " << value_ << "\n");323assert(!segment);324value = value_;325}
326
327uint64_t DefinedData::getOutputSegmentOffset() const {328LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");329return segment->getChunkOffset(value);330}
331
332uint64_t DefinedData::getOutputSegmentIndex() const {333LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");334return segment->outputSeg->index;335}
336
337uint32_t GlobalSymbol::getGlobalIndex() const {338if (auto *f = dyn_cast<DefinedGlobal>(this))339return f->global->getAssignedIndex();340assert(globalIndex != INVALID_INDEX);341return globalIndex;342}
343
344void GlobalSymbol::setGlobalIndex(uint32_t index) {345LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n");346assert(globalIndex == INVALID_INDEX);347globalIndex = index;348}
349
350bool GlobalSymbol::hasGlobalIndex() const {351if (auto *f = dyn_cast<DefinedGlobal>(this))352return f->global->hasAssignedIndex();353return globalIndex != INVALID_INDEX;354}
355
356DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,357InputGlobal *global)358: GlobalSymbol(name, DefinedGlobalKind, flags, file,359global ? &global->getType() : nullptr),360global(global) {}361
362uint32_t TagSymbol::getTagIndex() const {363if (auto *f = dyn_cast<DefinedTag>(this))364return f->tag->getAssignedIndex();365assert(tagIndex != INVALID_INDEX);366return tagIndex;367}
368
369void TagSymbol::setTagIndex(uint32_t index) {370LLVM_DEBUG(dbgs() << "setTagIndex " << name << " -> " << index << "\n");371assert(tagIndex == INVALID_INDEX);372tagIndex = index;373}
374
375bool TagSymbol::hasTagIndex() const {376if (auto *f = dyn_cast<DefinedTag>(this))377return f->tag->hasAssignedIndex();378return tagIndex != INVALID_INDEX;379}
380
381DefinedTag::DefinedTag(StringRef name, uint32_t flags, InputFile *file,382InputTag *tag)383: TagSymbol(name, DefinedTagKind, flags, file,384tag ? &tag->signature : nullptr),385tag(tag) {}386
387void TableSymbol::setLimits(const WasmLimits &limits) {388if (auto *t = dyn_cast<DefinedTable>(this))389t->table->setLimits(limits);390auto *newType = make<WasmTableType>(*tableType);391newType->Limits = limits;392tableType = newType;393}
394
395uint32_t TableSymbol::getTableNumber() const {396if (const auto *t = dyn_cast<DefinedTable>(this))397return t->table->getAssignedIndex();398assert(tableNumber != INVALID_INDEX);399return tableNumber;400}
401
402void TableSymbol::setTableNumber(uint32_t number) {403if (const auto *t = dyn_cast<DefinedTable>(this))404return t->table->assignIndex(number);405LLVM_DEBUG(dbgs() << "setTableNumber " << name << " -> " << number << "\n");406assert(tableNumber == INVALID_INDEX);407tableNumber = number;408}
409
410bool TableSymbol::hasTableNumber() const {411if (const auto *t = dyn_cast<DefinedTable>(this))412return t->table->hasAssignedIndex();413return tableNumber != INVALID_INDEX;414}
415
416DefinedTable::DefinedTable(StringRef name, uint32_t flags, InputFile *file,417InputTable *table)418: TableSymbol(name, DefinedTableKind, flags, file,419table ? &table->getType() : nullptr),420table(table) {}421
422const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const {423assert(section->outputSec && section->outputSec->sectionSym);424return section->outputSec->sectionSym;425}
426
427void LazySymbol::extract() {428if (file->lazy) {429file->lazy = false;430symtab->addFile(file, name);431}432}
433
434void LazySymbol::setWeak() {435flags |= (flags & ~WASM_SYMBOL_BINDING_MASK) | WASM_SYMBOL_BINDING_WEAK;436}
437
438void printTraceSymbolUndefined(StringRef name, const InputFile* file) {439message(toString(file) + ": reference to " + name);440}
441
442// Print out a log message for --trace-symbol.
443void printTraceSymbol(Symbol *sym) {444// Undefined symbols are traced via printTraceSymbolUndefined445if (sym->isUndefined())446return;447
448std::string s;449if (sym->isLazy())450s = ": lazy definition of ";451else452s = ": definition of ";453
454message(toString(sym->getFile()) + s + sym->getName());455}
456
457const char *defaultModule = "env";458const char *functionTableName = "__indirect_function_table";459const char *memoryName = "memory";460
461} // namespace wasm462} // namespace lld463