| //===- Symbols.cpp --------------------------------------------------------===// | 
 | // | 
 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
 | // See https://llvm.org/LICENSE.txt for license information. | 
 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "Symbols.h" | 
 | #include "Config.h" | 
 | #include "InputChunks.h" | 
 | #include "InputElement.h" | 
 | #include "InputFiles.h" | 
 | #include "OutputSections.h" | 
 | #include "OutputSegment.h" | 
 | #include "SymbolTable.h" | 
 | #include "lld/Common/ErrorHandler.h" | 
 | #include "lld/Common/Memory.h" | 
 | #include "llvm/Demangle/Demangle.h" | 
 |  | 
 | #define DEBUG_TYPE "lld" | 
 |  | 
 | using namespace llvm; | 
 | using namespace llvm::object; | 
 | using namespace llvm::wasm; | 
 | using namespace lld::wasm; | 
 |  | 
 | namespace lld { | 
 | std::string toString(const wasm::Symbol &sym) { | 
 |   return maybeDemangleSymbol(sym.getName()); | 
 | } | 
 |  | 
 | std::string maybeDemangleSymbol(StringRef name) { | 
 |   // WebAssembly requires caller and callee signatures to match, so we mangle | 
 |   // `main` in the case where we need to pass it arguments. | 
 |   if (name == "__main_argc_argv") | 
 |     return "main"; | 
 |   if (wasm::ctx.arg.demangle) | 
 |     return demangle(name); | 
 |   return name.str(); | 
 | } | 
 |  | 
 | std::string toString(wasm::Symbol::Kind kind) { | 
 |   switch (kind) { | 
 |   case wasm::Symbol::DefinedFunctionKind: | 
 |     return "DefinedFunction"; | 
 |   case wasm::Symbol::DefinedDataKind: | 
 |     return "DefinedData"; | 
 |   case wasm::Symbol::DefinedGlobalKind: | 
 |     return "DefinedGlobal"; | 
 |   case wasm::Symbol::DefinedTableKind: | 
 |     return "DefinedTable"; | 
 |   case wasm::Symbol::DefinedTagKind: | 
 |     return "DefinedTag"; | 
 |   case wasm::Symbol::UndefinedFunctionKind: | 
 |     return "UndefinedFunction"; | 
 |   case wasm::Symbol::UndefinedDataKind: | 
 |     return "UndefinedData"; | 
 |   case wasm::Symbol::UndefinedGlobalKind: | 
 |     return "UndefinedGlobal"; | 
 |   case wasm::Symbol::UndefinedTableKind: | 
 |     return "UndefinedTable"; | 
 |   case wasm::Symbol::UndefinedTagKind: | 
 |     return "UndefinedTag"; | 
 |   case wasm::Symbol::LazyKind: | 
 |     return "LazyKind"; | 
 |   case wasm::Symbol::SectionKind: | 
 |     return "SectionKind"; | 
 |   case wasm::Symbol::OutputSectionKind: | 
 |     return "OutputSectionKind"; | 
 |   case wasm::Symbol::SharedFunctionKind: | 
 |     return "SharedFunctionKind"; | 
 |   case wasm::Symbol::SharedDataKind: | 
 |     return "SharedDataKind"; | 
 |   } | 
 |   llvm_unreachable("invalid symbol kind"); | 
 | } | 
 |  | 
 | namespace wasm { | 
 |  | 
 | WasmSymbolType Symbol::getWasmType() const { | 
 |   if (isa<FunctionSymbol>(this)) | 
 |     return WASM_SYMBOL_TYPE_FUNCTION; | 
 |   if (isa<DataSymbol>(this)) | 
 |     return WASM_SYMBOL_TYPE_DATA; | 
 |   if (isa<GlobalSymbol>(this)) | 
 |     return WASM_SYMBOL_TYPE_GLOBAL; | 
 |   if (isa<TagSymbol>(this)) | 
 |     return WASM_SYMBOL_TYPE_TAG; | 
 |   if (isa<TableSymbol>(this)) | 
 |     return WASM_SYMBOL_TYPE_TABLE; | 
 |   if (isa<SectionSymbol>(this) || isa<OutputSectionSymbol>(this)) | 
 |     return WASM_SYMBOL_TYPE_SECTION; | 
 |   llvm_unreachable("invalid symbol kind"); | 
 | } | 
 |  | 
 | const WasmSignature *Symbol::getSignature() const { | 
 |   if (auto* f = dyn_cast<FunctionSymbol>(this)) | 
 |     return f->signature; | 
 |   if (auto *t = dyn_cast<TagSymbol>(this)) | 
 |     return t->signature; | 
 |   if (auto *l = dyn_cast<LazySymbol>(this)) | 
 |     return l->signature; | 
 |   return nullptr; | 
 | } | 
 |  | 
 | InputChunk *Symbol::getChunk() const { | 
 |   if (auto *f = dyn_cast<DefinedFunction>(this)) | 
 |     return f->function; | 
 |   if (auto *f = dyn_cast<UndefinedFunction>(this)) | 
 |     if (f->stubFunction) | 
 |       return f->stubFunction->function; | 
 |   if (auto *d = dyn_cast<DefinedData>(this)) | 
 |     return d->segment; | 
 |   return nullptr; | 
 | } | 
 |  | 
 | bool Symbol::isDiscarded() const { | 
 |   if (InputChunk *c = getChunk()) | 
 |     return c->discarded; | 
 |   return false; | 
 | } | 
 |  | 
 | bool Symbol::isLive() const { | 
 |   if (auto *g = dyn_cast<DefinedGlobal>(this)) | 
 |     return g->global->live; | 
 |   if (auto *t = dyn_cast<DefinedTag>(this)) | 
 |     return t->tag->live; | 
 |   if (auto *t = dyn_cast<DefinedTable>(this)) | 
 |     return t->table->live; | 
 |   if (InputChunk *c = getChunk()) | 
 |     return c->live; | 
 |   return referenced; | 
 | } | 
 |  | 
 | void Symbol::markLive() { | 
 |   assert(!isDiscarded()); | 
 |   referenced = true; | 
 |   if (file != nullptr && isDefined()) | 
 |     file->markLive(); | 
 |   if (auto *g = dyn_cast<DefinedGlobal>(this)) | 
 |     g->global->live = true; | 
 |   if (auto *t = dyn_cast<DefinedTag>(this)) | 
 |     t->tag->live = true; | 
 |   if (auto *t = dyn_cast<DefinedTable>(this)) | 
 |     t->table->live = true; | 
 |   if (InputChunk *c = getChunk()) { | 
 |     // Usually, a whole chunk is marked as live or dead, but in mergeable | 
 |     // (splittable) sections, each piece of data has independent liveness bit. | 
 |     // So we explicitly tell it which offset is in use. | 
 |     if (auto *d = dyn_cast<DefinedData>(this)) { | 
 |       if (auto *ms = dyn_cast<MergeInputChunk>(c)) { | 
 |         ms->getSectionPiece(d->value)->live = true; | 
 |       } | 
 |     } | 
 |     c->live = true; | 
 |   } | 
 | } | 
 |  | 
 | uint32_t Symbol::getOutputSymbolIndex() const { | 
 |   assert(outputSymbolIndex != INVALID_INDEX); | 
 |   return outputSymbolIndex; | 
 | } | 
 |  | 
 | void Symbol::setOutputSymbolIndex(uint32_t index) { | 
 |   LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name << " -> " << index | 
 |                     << "\n"); | 
 |   assert(outputSymbolIndex == INVALID_INDEX); | 
 |   outputSymbolIndex = index; | 
 | } | 
 |  | 
 | void Symbol::setGOTIndex(uint32_t index) { | 
 |   LLVM_DEBUG(dbgs() << "setGOTIndex " << name << " -> " << index << "\n"); | 
 |   assert(gotIndex == INVALID_INDEX); | 
 |   gotIndex = index; | 
 | } | 
 |  | 
 | bool Symbol::isWeak() const { | 
 |   return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK; | 
 | } | 
 |  | 
 | bool Symbol::isLocal() const { | 
 |   return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL; | 
 | } | 
 |  | 
 | bool Symbol::isHidden() const { | 
 |   return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN; | 
 | } | 
 |  | 
 | bool Symbol::isTLS() const { return flags & WASM_SYMBOL_TLS; } | 
 |  | 
 | void Symbol::setHidden(bool isHidden) { | 
 |   LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n"); | 
 |   flags &= ~WASM_SYMBOL_VISIBILITY_MASK; | 
 |   if (isHidden) | 
 |     flags |= WASM_SYMBOL_VISIBILITY_HIDDEN; | 
 |   else | 
 |     flags |= WASM_SYMBOL_VISIBILITY_DEFAULT; | 
 | } | 
 |  | 
 | bool Symbol::isImported() const { | 
 |   return isShared() || | 
 |          (isUndefined() && (importName.has_value() || forceImport)); | 
 | } | 
 |  | 
 | bool Symbol::isExported() const { | 
 |   if (!isDefined() || isShared() || isLocal()) | 
 |     return false; | 
 |  | 
 |   // Shared libraries must export all weakly defined symbols | 
 |   // in case they contain the version that will be chosen by | 
 |   // the dynamic linker. | 
 |   if (ctx.arg.shared && isLive() && isWeak() && !isHidden()) | 
 |     return true; | 
 |  | 
 |   if (ctx.arg.exportAll || (ctx.arg.exportDynamic && !isHidden())) | 
 |     return true; | 
 |  | 
 |   return isExportedExplicit(); | 
 | } | 
 |  | 
 | bool Symbol::isExportedExplicit() const { | 
 |   return forceExport || flags & WASM_SYMBOL_EXPORTED; | 
 | } | 
 |  | 
 | bool Symbol::isNoStrip() const { | 
 |   return flags & WASM_SYMBOL_NO_STRIP; | 
 | } | 
 |  | 
 | uint32_t FunctionSymbol::getFunctionIndex() const { | 
 |   if (const auto *u = dyn_cast<UndefinedFunction>(this)) | 
 |     if (u->stubFunction) | 
 |       return u->stubFunction->getFunctionIndex(); | 
 |   if (functionIndex != INVALID_INDEX) | 
 |     return functionIndex; | 
 |   auto *f = cast<DefinedFunction>(this); | 
 |   return f->function->getFunctionIndex(); | 
 | } | 
 |  | 
 | void FunctionSymbol::setFunctionIndex(uint32_t index) { | 
 |   LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n"); | 
 |   assert(functionIndex == INVALID_INDEX); | 
 |   functionIndex = index; | 
 | } | 
 |  | 
 | bool FunctionSymbol::hasFunctionIndex() const { | 
 |   if (auto *f = dyn_cast<DefinedFunction>(this)) | 
 |     return f->function->hasFunctionIndex(); | 
 |   return functionIndex != INVALID_INDEX; | 
 | } | 
 |  | 
 | uint32_t FunctionSymbol::getTableIndex() const { | 
 |   if (auto *f = dyn_cast<DefinedFunction>(this)) | 
 |     return f->function->getTableIndex(); | 
 |   assert(tableIndex != INVALID_INDEX); | 
 |   return tableIndex; | 
 | } | 
 |  | 
 | bool FunctionSymbol::hasTableIndex() const { | 
 |   if (auto *f = dyn_cast<DefinedFunction>(this)) | 
 |     return f->function->hasTableIndex(); | 
 |   return tableIndex != INVALID_INDEX; | 
 | } | 
 |  | 
 | void FunctionSymbol::setTableIndex(uint32_t index) { | 
 |   // For imports, we set the table index here on the Symbol; for defined | 
 |   // functions we set the index on the InputFunction so that we don't export | 
 |   // the same thing twice (keeps the table size down). | 
 |   if (auto *f = dyn_cast<DefinedFunction>(this)) { | 
 |     f->function->setTableIndex(index); | 
 |     return; | 
 |   } | 
 |   LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n"); | 
 |   assert(tableIndex == INVALID_INDEX); | 
 |   tableIndex = index; | 
 | } | 
 |  | 
 | DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f, | 
 |                                  InputFunction *function) | 
 |     : FunctionSymbol(name, DefinedFunctionKind, flags, f, | 
 |                      function ? &function->signature : nullptr), | 
 |       function(function) {} | 
 |  | 
 | uint32_t DefinedFunction::getExportedFunctionIndex() const { | 
 |   return function->getFunctionIndex(); | 
 | } | 
 |  | 
 | uint64_t DefinedData::getVA(bool absolute) const { | 
 |   LLVM_DEBUG(dbgs() << "getVA: " << getName() << "\n"); | 
 |   // TLS symbols (by default) are relative to the start of the TLS output | 
 |   // segment (__tls_base). | 
 |   if (isTLS() && !absolute) | 
 |     return getOutputSegmentOffset(); | 
 |   if (segment) | 
 |     return segment->getVA(value); | 
 |   return value; | 
 | } | 
 |  | 
 | void DefinedData::setVA(uint64_t value_) { | 
 |   LLVM_DEBUG(dbgs() << "setVA " << name << " -> " << value_ << "\n"); | 
 |   assert(!segment); | 
 |   value = value_; | 
 | } | 
 |  | 
 | uint64_t DefinedData::getOutputSegmentOffset() const { | 
 |   LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n"); | 
 |   return segment->getChunkOffset(value); | 
 | } | 
 |  | 
 | uint64_t DefinedData::getOutputSegmentIndex() const { | 
 |   LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n"); | 
 |   return segment->outputSeg->index; | 
 | } | 
 |  | 
 | uint32_t GlobalSymbol::getGlobalIndex() const { | 
 |   if (auto *f = dyn_cast<DefinedGlobal>(this)) | 
 |     return f->global->getAssignedIndex(); | 
 |   assert(globalIndex != INVALID_INDEX); | 
 |   return globalIndex; | 
 | } | 
 |  | 
 | void GlobalSymbol::setGlobalIndex(uint32_t index) { | 
 |   LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n"); | 
 |   assert(globalIndex == INVALID_INDEX); | 
 |   globalIndex = index; | 
 | } | 
 |  | 
 | bool GlobalSymbol::hasGlobalIndex() const { | 
 |   if (auto *f = dyn_cast<DefinedGlobal>(this)) | 
 |     return f->global->hasAssignedIndex(); | 
 |   return globalIndex != INVALID_INDEX; | 
 | } | 
 |  | 
 | DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file, | 
 |                              InputGlobal *global) | 
 |     : GlobalSymbol(name, DefinedGlobalKind, flags, file, | 
 |                    global ? &global->getType() : nullptr), | 
 |       global(global) {} | 
 |  | 
 | uint32_t TagSymbol::getTagIndex() const { | 
 |   if (auto *f = dyn_cast<DefinedTag>(this)) | 
 |     return f->tag->getAssignedIndex(); | 
 |   assert(tagIndex != INVALID_INDEX); | 
 |   return tagIndex; | 
 | } | 
 |  | 
 | void TagSymbol::setTagIndex(uint32_t index) { | 
 |   LLVM_DEBUG(dbgs() << "setTagIndex " << name << " -> " << index << "\n"); | 
 |   assert(tagIndex == INVALID_INDEX); | 
 |   tagIndex = index; | 
 | } | 
 |  | 
 | bool TagSymbol::hasTagIndex() const { | 
 |   if (auto *f = dyn_cast<DefinedTag>(this)) | 
 |     return f->tag->hasAssignedIndex(); | 
 |   return tagIndex != INVALID_INDEX; | 
 | } | 
 |  | 
 | DefinedTag::DefinedTag(StringRef name, uint32_t flags, InputFile *file, | 
 |                        InputTag *tag) | 
 |     : TagSymbol(name, DefinedTagKind, flags, file, | 
 |                 tag ? &tag->signature : nullptr), | 
 |       tag(tag) {} | 
 |  | 
 | void TableSymbol::setLimits(const WasmLimits &limits) { | 
 |   if (auto *t = dyn_cast<DefinedTable>(this)) | 
 |     t->table->setLimits(limits); | 
 |   auto *newType = make<WasmTableType>(*tableType); | 
 |   newType->Limits = limits; | 
 |   tableType = newType; | 
 | } | 
 |  | 
 | uint32_t TableSymbol::getTableNumber() const { | 
 |   if (const auto *t = dyn_cast<DefinedTable>(this)) | 
 |     return t->table->getAssignedIndex(); | 
 |   assert(tableNumber != INVALID_INDEX); | 
 |   return tableNumber; | 
 | } | 
 |  | 
 | void TableSymbol::setTableNumber(uint32_t number) { | 
 |   if (const auto *t = dyn_cast<DefinedTable>(this)) | 
 |     return t->table->assignIndex(number); | 
 |   LLVM_DEBUG(dbgs() << "setTableNumber " << name << " -> " << number << "\n"); | 
 |   assert(tableNumber == INVALID_INDEX); | 
 |   tableNumber = number; | 
 | } | 
 |  | 
 | bool TableSymbol::hasTableNumber() const { | 
 |   if (const auto *t = dyn_cast<DefinedTable>(this)) | 
 |     return t->table->hasAssignedIndex(); | 
 |   return tableNumber != INVALID_INDEX; | 
 | } | 
 |  | 
 | DefinedTable::DefinedTable(StringRef name, uint32_t flags, InputFile *file, | 
 |                            InputTable *table) | 
 |     : TableSymbol(name, DefinedTableKind, flags, file, | 
 |                   table ? &table->getType() : nullptr), | 
 |       table(table) {} | 
 |  | 
 | const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const { | 
 |   assert(section->outputSec && section->outputSec->sectionSym); | 
 |   return section->outputSec->sectionSym; | 
 | } | 
 |  | 
 | void LazySymbol::extract() { | 
 |   if (file->lazy) { | 
 |     file->lazy = false; | 
 |     symtab->addFile(file, name); | 
 |   } | 
 | } | 
 |  | 
 | void LazySymbol::setWeak() { | 
 |   flags |= (flags & ~WASM_SYMBOL_BINDING_MASK) | WASM_SYMBOL_BINDING_WEAK; | 
 | } | 
 |  | 
 | void printTraceSymbolUndefined(StringRef name, const InputFile* file) { | 
 |   message(toString(file) + ": reference to " + name); | 
 | } | 
 |  | 
 | // Print out a log message for --trace-symbol. | 
 | void printTraceSymbol(Symbol *sym) { | 
 |   // Undefined symbols are traced via printTraceSymbolUndefined | 
 |   if (sym->isUndefined()) | 
 |     return; | 
 |  | 
 |   std::string s; | 
 |   if (sym->isLazy()) | 
 |     s = ": lazy definition of "; | 
 |   else | 
 |     s = ": definition of "; | 
 |  | 
 |   message(toString(sym->getFile()) + s + sym->getName()); | 
 | } | 
 |  | 
 | const char *defaultModule = "env"; | 
 | const char *functionTableName = "__indirect_function_table"; | 
 | const char *memoryName = "memory"; | 
 |  | 
 | } // namespace wasm | 
 | } // namespace lld |