brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.0 KiB · f204044 Raw
441 lines · cpp
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-exception6//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) {30  return 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.36  if (name == "__main_argc_argv")37    return "main";38  if (wasm::ctx.arg.demangle)39    return demangle(name);40  return name.str();41}42 43std::string toString(wasm::Symbol::Kind kind) {44  switch (kind) {45  case wasm::Symbol::DefinedFunctionKind:46    return "DefinedFunction";47  case wasm::Symbol::DefinedDataKind:48    return "DefinedData";49  case wasm::Symbol::DefinedGlobalKind:50    return "DefinedGlobal";51  case wasm::Symbol::DefinedTableKind:52    return "DefinedTable";53  case wasm::Symbol::DefinedTagKind:54    return "DefinedTag";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:66    return "LazyKind";67  case wasm::Symbol::SectionKind:68    return "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";75  }76  llvm_unreachable("invalid symbol kind");77}78 79namespace wasm {80 81WasmSymbolType 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<TagSymbol>(this))89    return WASM_SYMBOL_TYPE_TAG;90  if (isa<TableSymbol>(this))91    return WASM_SYMBOL_TYPE_TABLE;92  if (isa<SectionSymbol>(this) || isa<OutputSectionSymbol>(this))93    return WASM_SYMBOL_TYPE_SECTION;94  llvm_unreachable("invalid symbol kind");95}96 97const WasmSignature *Symbol::getSignature() const {98  if (auto* f = dyn_cast<FunctionSymbol>(this))99    return f->signature;100  if (auto *t = dyn_cast<TagSymbol>(this))101    return t->signature;102  if (auto *l = dyn_cast<LazySymbol>(this))103    return l->signature;104  return nullptr;105}106 107InputChunk *Symbol::getChunk() const {108  if (auto *f = dyn_cast<DefinedFunction>(this))109    return f->function;110  if (auto *f = dyn_cast<UndefinedFunction>(this))111    if (f->stubFunction)112      return f->stubFunction->function;113  if (auto *d = dyn_cast<DefinedData>(this))114    return d->segment;115  return nullptr;116}117 118bool Symbol::isDiscarded() const {119  if (InputChunk *c = getChunk())120    return c->discarded;121  return false;122}123 124bool Symbol::isLive() const {125  if (auto *g = dyn_cast<DefinedGlobal>(this))126    return g->global->live;127  if (auto *t = dyn_cast<DefinedTag>(this))128    return t->tag->live;129  if (auto *t = dyn_cast<DefinedTable>(this))130    return t->table->live;131  if (InputChunk *c = getChunk())132    return c->live;133  return referenced;134}135 136void Symbol::markLive() {137  assert(!isDiscarded());138  referenced = true;139  if (file != nullptr && isDefined())140    file->markLive();141  if (auto *g = dyn_cast<DefinedGlobal>(this))142    g->global->live = true;143  if (auto *t = dyn_cast<DefinedTag>(this))144    t->tag->live = true;145  if (auto *t = dyn_cast<DefinedTable>(this))146    t->table->live = true;147  if (InputChunk *c = getChunk()) {148    // Usually, a whole chunk is marked as live or dead, but in mergeable149    // (splittable) sections, each piece of data has independent liveness bit.150    // So we explicitly tell it which offset is in use.151    if (auto *d = dyn_cast<DefinedData>(this)) {152      if (auto *ms = dyn_cast<MergeInputChunk>(c)) {153        ms->getSectionPiece(d->value)->live = true;154      }155    }156    c->live = true;157  }158}159 160uint32_t Symbol::getOutputSymbolIndex() const {161  assert(outputSymbolIndex != INVALID_INDEX || !isLive());162  return outputSymbolIndex;163}164 165void Symbol::setOutputSymbolIndex(uint32_t index) {166  LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name << " -> " << index167                    << "\n");168  assert(outputSymbolIndex == INVALID_INDEX);169  outputSymbolIndex = index;170}171 172void Symbol::setGOTIndex(uint32_t index) {173  LLVM_DEBUG(dbgs() << "setGOTIndex " << name << " -> " << index << "\n");174  assert(gotIndex == INVALID_INDEX);175  gotIndex = index;176}177 178bool Symbol::isWeak() const {179  return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;180}181 182bool Symbol::isLocal() const {183  return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;184}185 186bool Symbol::isHidden() const {187  return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;188}189 190bool Symbol::isTLS() const { return flags & WASM_SYMBOL_TLS; }191 192void Symbol::setHidden(bool isHidden) {193  LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n");194  flags &= ~WASM_SYMBOL_VISIBILITY_MASK;195  if (isHidden)196    flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;197  else198    flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;199}200 201bool Symbol::isImported() const {202  return isShared() ||203         (isUndefined() && (importName.has_value() || forceImport));204}205 206bool Symbol::isExported() const {207  if (!isDefined() || isShared() || isLocal())208    return false;209 210  // Shared libraries must export all weakly defined symbols211  // in case they contain the version that will be chosen by212  // the dynamic linker.213  if (ctx.arg.shared && isLive() && isWeak() && !isHidden())214    return true;215 216  if (ctx.arg.exportAll || (ctx.arg.exportDynamic && !isHidden()))217    return true;218 219  return isExportedExplicit();220}221 222bool Symbol::isExportedExplicit() const {223  return forceExport || flags & WASM_SYMBOL_EXPORTED;224}225 226bool Symbol::isNoStrip() const {227  return flags & WASM_SYMBOL_NO_STRIP;228}229 230uint32_t FunctionSymbol::getFunctionIndex() const {231  if (const auto *u = dyn_cast<UndefinedFunction>(this))232    if (u->stubFunction)233      return u->stubFunction->getFunctionIndex();234  if (functionIndex != INVALID_INDEX)235    return functionIndex;236  auto *f = cast<DefinedFunction>(this);237  return f->function->getFunctionIndex();238}239 240void FunctionSymbol::setFunctionIndex(uint32_t index) {241  LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n");242  assert(functionIndex == INVALID_INDEX);243  functionIndex = index;244}245 246bool FunctionSymbol::hasFunctionIndex() const {247  if (auto *f = dyn_cast<DefinedFunction>(this))248    return f->function->hasFunctionIndex();249  return functionIndex != INVALID_INDEX;250}251 252uint32_t FunctionSymbol::getTableIndex() const {253  if (auto *f = dyn_cast<DefinedFunction>(this))254    return f->function->getTableIndex();255  assert(tableIndex != INVALID_INDEX);256  return tableIndex;257}258 259bool FunctionSymbol::hasTableIndex() const {260  if (auto *f = dyn_cast<DefinedFunction>(this))261    return f->function->hasTableIndex();262  return tableIndex != INVALID_INDEX;263}264 265void FunctionSymbol::setTableIndex(uint32_t index) {266  // For imports, we set the table index here on the Symbol; for defined267  // functions we set the index on the InputFunction so that we don't export268  // the same thing twice (keeps the table size down).269  if (auto *f = dyn_cast<DefinedFunction>(this)) {270    f->function->setTableIndex(index);271    return;272  }273  LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n");274  assert(tableIndex == INVALID_INDEX);275  tableIndex = index;276}277 278DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f,279                                 InputFunction *function)280    : FunctionSymbol(name, DefinedFunctionKind, flags, f,281                     function ? &function->signature : nullptr),282      function(function) {}283 284uint32_t DefinedFunction::getExportedFunctionIndex() const {285  return function->getFunctionIndex();286}287 288uint64_t DefinedData::getVA(bool absolute) const {289  LLVM_DEBUG(dbgs() << "getVA: " << getName() << "\n");290  // TLS symbols (by default) are relative to the start of the TLS output291  // segment (__tls_base).292  if (isTLS() && !absolute)293    return getOutputSegmentOffset();294  if (segment)295    return segment->getVA(value);296  return value;297}298 299void DefinedData::setVA(uint64_t value_) {300  LLVM_DEBUG(dbgs() << "setVA " << name << " -> " << value_ << "\n");301  assert(!segment);302  value = value_;303}304 305uint64_t DefinedData::getOutputSegmentOffset() const {306  LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");307  return segment->getChunkOffset(value);308}309 310uint64_t DefinedData::getOutputSegmentIndex() const {311  LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");312  return segment->outputSeg->index;313}314 315uint32_t GlobalSymbol::getGlobalIndex() const {316  if (auto *f = dyn_cast<DefinedGlobal>(this))317    return f->global->getAssignedIndex();318  assert(globalIndex != INVALID_INDEX);319  return globalIndex;320}321 322void GlobalSymbol::setGlobalIndex(uint32_t index) {323  LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n");324  assert(globalIndex == INVALID_INDEX);325  globalIndex = index;326}327 328bool GlobalSymbol::hasGlobalIndex() const {329  if (auto *f = dyn_cast<DefinedGlobal>(this))330    return f->global->hasAssignedIndex();331  return globalIndex != INVALID_INDEX;332}333 334DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,335                             InputGlobal *global)336    : GlobalSymbol(name, DefinedGlobalKind, flags, file,337                   global ? &global->getType() : nullptr),338      global(global) {}339 340uint32_t TagSymbol::getTagIndex() const {341  if (auto *f = dyn_cast<DefinedTag>(this))342    return f->tag->getAssignedIndex();343  assert(tagIndex != INVALID_INDEX);344  return tagIndex;345}346 347void TagSymbol::setTagIndex(uint32_t index) {348  LLVM_DEBUG(dbgs() << "setTagIndex " << name << " -> " << index << "\n");349  assert(tagIndex == INVALID_INDEX);350  tagIndex = index;351}352 353bool TagSymbol::hasTagIndex() const {354  if (auto *f = dyn_cast<DefinedTag>(this))355    return f->tag->hasAssignedIndex();356  return tagIndex != INVALID_INDEX;357}358 359DefinedTag::DefinedTag(StringRef name, uint32_t flags, InputFile *file,360                       InputTag *tag)361    : TagSymbol(name, DefinedTagKind, flags, file,362                tag ? &tag->signature : nullptr),363      tag(tag) {}364 365void TableSymbol::setLimits(const WasmLimits &limits) {366  if (auto *t = dyn_cast<DefinedTable>(this))367    t->table->setLimits(limits);368  auto *newType = make<WasmTableType>(*tableType);369  newType->Limits = limits;370  tableType = newType;371}372 373uint32_t TableSymbol::getTableNumber() const {374  if (const auto *t = dyn_cast<DefinedTable>(this))375    return t->table->getAssignedIndex();376  assert(tableNumber != INVALID_INDEX);377  return tableNumber;378}379 380void TableSymbol::setTableNumber(uint32_t number) {381  if (const auto *t = dyn_cast<DefinedTable>(this))382    return t->table->assignIndex(number);383  LLVM_DEBUG(dbgs() << "setTableNumber " << name << " -> " << number << "\n");384  assert(tableNumber == INVALID_INDEX);385  tableNumber = number;386}387 388bool TableSymbol::hasTableNumber() const {389  if (const auto *t = dyn_cast<DefinedTable>(this))390    return t->table->hasAssignedIndex();391  return tableNumber != INVALID_INDEX;392}393 394DefinedTable::DefinedTable(StringRef name, uint32_t flags, InputFile *file,395                           InputTable *table)396    : TableSymbol(name, DefinedTableKind, flags, file,397                  table ? &table->getType() : nullptr),398      table(table) {}399 400const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const {401  assert(section->outputSec && section->outputSec->sectionSym);402  return section->outputSec->sectionSym;403}404 405void LazySymbol::extract() {406  if (file->lazy) {407    file->lazy = false;408    symtab->addFile(file, name);409  }410}411 412void LazySymbol::setWeak() {413  flags |= (flags & ~WASM_SYMBOL_BINDING_MASK) | WASM_SYMBOL_BINDING_WEAK;414}415 416void printTraceSymbolUndefined(StringRef name, const InputFile* file) {417  message(toString(file) + ": reference to " + name);418}419 420// Print out a log message for --trace-symbol.421void printTraceSymbol(Symbol *sym) {422  // Undefined symbols are traced via printTraceSymbolUndefined423  if (sym->isUndefined())424    return;425 426  std::string s;427  if (sym->isLazy())428    s = ": lazy definition of ";429  else430    s = ": definition of ";431 432  message(toString(sym->getFile()) + s + sym->getName());433}434 435const char *defaultModule = "env";436const char *functionTableName = "__indirect_function_table";437const char *memoryName = "memory";438 439} // namespace wasm440} // namespace lld441