brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.9 KiB · 55ee219 Raw
604 lines · c
1//===- Symbols.h ------------------------------------------------*- C++ -*-===//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#ifndef LLD_WASM_SYMBOLS_H10#define LLD_WASM_SYMBOLS_H11 12#include "Config.h"13#include "lld/Common/LLVM.h"14#include "llvm/Object/Archive.h"15#include "llvm/Object/Wasm.h"16#include <optional>17 18namespace lld {19namespace wasm {20 21// Shared string constants22 23// The default module name to use for symbol imports.24extern const char *defaultModule;25 26// The name under which to import or export the wasm table.27extern const char *functionTableName;28 29// The name under which to import or export the wasm memory.30extern const char *memoryName;31 32using llvm::wasm::WasmSymbolType;33 34class InputFile;35class InputChunk;36class InputSegment;37class InputFunction;38class InputGlobal;39class InputTag;40class InputSection;41class InputTable;42class OutputSection;43 44#define INVALID_INDEX UINT32_MAX45 46// The base class for real symbol classes.47class Symbol {48public:49  enum Kind : uint8_t {50    DefinedFunctionKind,51    DefinedDataKind,52    DefinedGlobalKind,53    DefinedTagKind,54    DefinedTableKind,55    SectionKind,56    OutputSectionKind,57    UndefinedFunctionKind,58    UndefinedDataKind,59    UndefinedGlobalKind,60    UndefinedTableKind,61    UndefinedTagKind,62    LazyKind,63    SharedFunctionKind,64    SharedDataKind,65  };66 67  Kind kind() const { return symbolKind; }68 69  bool isDefined() const { return !isLazy() && !isUndefined(); }70 71  bool isUndefined() const {72    return symbolKind == UndefinedFunctionKind ||73           symbolKind == UndefinedDataKind ||74           symbolKind == UndefinedGlobalKind ||75           symbolKind == UndefinedTableKind || symbolKind == UndefinedTagKind;76  }77 78  bool isLazy() const { return symbolKind == LazyKind; }79  bool isShared() const {80    return symbolKind == SharedFunctionKind || symbolKind == SharedDataKind;81  }82 83  bool isLocal() const;84  bool isWeak() const;85  bool isHidden() const;86  bool isTLS() const;87 88  // Returns true if this symbol exists in a discarded (due to COMDAT) section89  bool isDiscarded() const;90 91  // True if this is an undefined weak symbol. This only works once92  // all input files have been added.93  bool isUndefWeak() const {94    // See comment on lazy symbols for details.95    return isWeak() && (isUndefined() || isLazy());96  }97 98  // Returns the symbol name.99  StringRef getName() const { return name; }100 101  // Returns the file from which this symbol was created.102  InputFile *getFile() const { return file; }103 104  InputChunk *getChunk() const;105 106  // Indicates that the section or import for this symbol will be included in107  // the final image.108  bool isLive() const;109 110  // Marks the symbol's InputChunk as Live, so that it will be included in the111  // final image.112  void markLive();113 114  void setHidden(bool isHidden);115 116  // Get/set the index in the output symbol table.  This is only used for117  // relocatable output.118  uint32_t getOutputSymbolIndex() const;119  void setOutputSymbolIndex(uint32_t index);120 121  WasmSymbolType getWasmType() const;122  bool isImported() const;123  bool isExported() const;124  bool isExportedExplicit() const;125 126  // Indicates that the symbol is used in an __attribute__((used)) directive127  // or similar.128  bool isNoStrip() const;129 130  const WasmSignature* getSignature() const;131 132  uint32_t getGOTIndex() const {133    assert(gotIndex != INVALID_INDEX);134    return gotIndex;135  }136 137  void setGOTIndex(uint32_t index);138  bool hasGOTIndex() const { return gotIndex != INVALID_INDEX; }139 140protected:141  Symbol(StringRef name, Kind k, uint32_t flags, InputFile *f)142      : name(name), file(f), symbolKind(k), referenced(!ctx.arg.gcSections),143        requiresGOT(false), isUsedInRegularObj(false), forceExport(false),144        forceImport(false), canInline(false), traced(false), isStub(false),145        flags(flags) {}146 147  StringRef name;148  InputFile *file;149  uint32_t outputSymbolIndex = INVALID_INDEX;150  uint32_t gotIndex = INVALID_INDEX;151  Kind symbolKind;152 153public:154  bool referenced : 1;155 156  // True for data symbols that needs a dummy GOT entry.  Used for static157  // linking of GOT accesses.158  bool requiresGOT : 1;159 160  // True if the symbol was used for linking and thus need to be added to the161  // output file's symbol table. This is true for all symbols except for162  // unreferenced DSO symbols, lazy (archive) symbols, and bitcode symbols that163  // are unreferenced except by other bitcode objects.164  bool isUsedInRegularObj : 1;165 166  // True if this symbol is explicitly marked for export (i.e. via the167  // -e/--export command line flag)168  bool forceExport : 1;169 170  bool forceImport : 1;171 172  // False if LTO shouldn't inline whatever this symbol points to. If a symbol173  // is overwritten after LTO, LTO shouldn't inline the symbol because it174  // doesn't know the final contents of the symbol.175  bool canInline : 1;176 177  // True if this symbol is specified by --trace-symbol option.178  bool traced : 1;179 180  // True if this symbol is a linker-synthesized stub function (traps when181  // called) and should otherwise be treated as missing/undefined.  See182  // SymbolTable::replaceWithUndefined.183  // These stubs never appear in the table and any table index relocations184  // against them will produce address 0 (The table index representing185  // the null function pointer).186  bool isStub : 1;187 188  uint32_t flags;189 190  std::optional<StringRef> importName;191  std::optional<StringRef> importModule;192};193 194class FunctionSymbol : public Symbol {195public:196  static bool classof(const Symbol *s) {197    return s->kind() == DefinedFunctionKind ||198           s->kind() == SharedFunctionKind ||199           s->kind() == UndefinedFunctionKind;200  }201 202  // Get/set the table index203  void setTableIndex(uint32_t index);204  uint32_t getTableIndex() const;205  bool hasTableIndex() const;206 207  // Get/set the function index208  uint32_t getFunctionIndex() const;209  void setFunctionIndex(uint32_t index);210  bool hasFunctionIndex() const;211 212  const WasmSignature *signature;213 214protected:215  FunctionSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,216                 const WasmSignature *sig)217      : Symbol(name, k, flags, f), signature(sig) {}218 219  uint32_t tableIndex = INVALID_INDEX;220  uint32_t functionIndex = INVALID_INDEX;221};222 223class DefinedFunction : public FunctionSymbol {224public:225  DefinedFunction(StringRef name, uint32_t flags, InputFile *f,226                  InputFunction *function);227 228  static bool classof(const Symbol *s) {229    return s->kind() == DefinedFunctionKind;230  }231 232  // Get the function index to be used when exporting.  This only applies to233  // defined functions and can be differ from the regular function index for234  // weakly defined functions (that are imported and used via one index but235  // defined and exported via another).236  uint32_t getExportedFunctionIndex() const;237 238  InputFunction *function;239};240 241class UndefinedFunction : public FunctionSymbol {242public:243  UndefinedFunction(StringRef name, std::optional<StringRef> importName,244                    std::optional<StringRef> importModule, uint32_t flags,245                    InputFile *file = nullptr,246                    const WasmSignature *type = nullptr,247                    bool isCalledDirectly = true)248      : FunctionSymbol(name, UndefinedFunctionKind, flags, file, type),249        isCalledDirectly(isCalledDirectly) {250    this->importName = importName;251    this->importModule = importModule;252  }253 254  static bool classof(const Symbol *s) {255    return s->kind() == UndefinedFunctionKind;256  }257 258  DefinedFunction *stubFunction = nullptr;259  bool isCalledDirectly;260};261 262// Section symbols for output sections are different from those for input263// section.  These are generated by the linker and point the OutputSection264// rather than an InputSection.265class OutputSectionSymbol : public Symbol {266public:267  OutputSectionSymbol(const OutputSection *s)268      : Symbol("", OutputSectionKind, llvm::wasm::WASM_SYMBOL_BINDING_LOCAL,269               nullptr),270        section(s) {}271 272  static bool classof(const Symbol *s) {273    return s->kind() == OutputSectionKind;274  }275 276  const OutputSection *section;277};278 279class SectionSymbol : public Symbol {280public:281  SectionSymbol(uint32_t flags, const InputChunk *s, InputFile *f = nullptr)282      : Symbol("", SectionKind, flags, f), section(s) {}283 284  static bool classof(const Symbol *s) { return s->kind() == SectionKind; }285 286  const OutputSectionSymbol *getOutputSectionSymbol() const;287 288  const InputChunk *section;289};290 291class DataSymbol : public Symbol {292public:293  static bool classof(const Symbol *s) {294    return s->kind() == DefinedDataKind || s->kind() == UndefinedDataKind ||295           s->kind() == SharedDataKind;296  }297 298protected:299  DataSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f)300      : Symbol(name, k, flags, f) {}301};302 303class DefinedData : public DataSymbol {304public:305  // Constructor for regular data symbols originating from input files.306  DefinedData(StringRef name, uint32_t flags, InputFile *f, InputChunk *segment,307              uint64_t value, uint64_t size)308      : DataSymbol(name, DefinedDataKind, flags, f), segment(segment),309        value(value), size(size) {}310 311  // Constructor for linker synthetic data symbols.312  DefinedData(StringRef name, uint32_t flags)313      : DataSymbol(name, DefinedDataKind, flags, nullptr) {}314 315  static bool classof(const Symbol *s) { return s->kind() == DefinedDataKind; }316 317  // Returns the output virtual address of a defined data symbol.318  // For TLS symbols, by default (unless absolute is set), this returns an319  // address relative the `__tls_base`.320  uint64_t getVA(bool absolute = false) const;321  void setVA(uint64_t va);322 323  // Returns the offset of a defined data symbol within its OutputSegment.324  uint64_t getOutputSegmentOffset() const;325  uint64_t getOutputSegmentIndex() const;326  uint64_t getSize() const { return size; }327 328  InputChunk *segment = nullptr;329  uint64_t value = 0;330 331protected:332  uint64_t size = 0;333};334 335class SharedData : public DataSymbol {336public:337  SharedData(StringRef name, uint32_t flags, InputFile *f)338      : DataSymbol(name, SharedDataKind, flags, f) {}339};340 341class UndefinedData : public DataSymbol {342public:343  UndefinedData(StringRef name, uint32_t flags, InputFile *file = nullptr)344      : DataSymbol(name, UndefinedDataKind, flags, file) {}345  static bool classof(const Symbol *s) {346    return s->kind() == UndefinedDataKind;347  }348};349 350class GlobalSymbol : public Symbol {351public:352  static bool classof(const Symbol *s) {353    return s->kind() == DefinedGlobalKind || s->kind() == UndefinedGlobalKind;354  }355 356  const WasmGlobalType *getGlobalType() const { return globalType; }357 358  // Get/set the global index359  uint32_t getGlobalIndex() const;360  void setGlobalIndex(uint32_t index);361  bool hasGlobalIndex() const;362 363protected:364  GlobalSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,365               const WasmGlobalType *globalType)366      : Symbol(name, k, flags, f), globalType(globalType) {}367 368  const WasmGlobalType *globalType;369  uint32_t globalIndex = INVALID_INDEX;370};371 372class DefinedGlobal : public GlobalSymbol {373public:374  DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,375                InputGlobal *global);376 377  static bool classof(const Symbol *s) {378    return s->kind() == DefinedGlobalKind;379  }380 381  InputGlobal *global;382};383 384class UndefinedGlobal : public GlobalSymbol {385public:386  UndefinedGlobal(StringRef name, std::optional<StringRef> importName,387                  std::optional<StringRef> importModule, uint32_t flags,388                  InputFile *file = nullptr,389                  const WasmGlobalType *type = nullptr)390      : GlobalSymbol(name, UndefinedGlobalKind, flags, file, type) {391    this->importName = importName;392    this->importModule = importModule;393  }394 395  static bool classof(const Symbol *s) {396    return s->kind() == UndefinedGlobalKind;397  }398};399 400class TableSymbol : public Symbol {401public:402  static bool classof(const Symbol *s) {403    return s->kind() == DefinedTableKind || s->kind() == UndefinedTableKind;404  }405 406  const WasmTableType *getTableType() const { return tableType; }407  void setLimits(const WasmLimits &limits);408 409  // Get/set the table number410  uint32_t getTableNumber() const;411  void setTableNumber(uint32_t number);412  bool hasTableNumber() const;413 414protected:415  TableSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,416              const WasmTableType *type)417      : Symbol(name, k, flags, f), tableType(type) {}418 419  const WasmTableType *tableType;420  uint32_t tableNumber = INVALID_INDEX;421};422 423class DefinedTable : public TableSymbol {424public:425  DefinedTable(StringRef name, uint32_t flags, InputFile *file,426               InputTable *table);427 428  static bool classof(const Symbol *s) { return s->kind() == DefinedTableKind; }429 430  InputTable *table;431};432 433class UndefinedTable : public TableSymbol {434public:435  UndefinedTable(StringRef name, std::optional<StringRef> importName,436                 std::optional<StringRef> importModule, uint32_t flags,437                 InputFile *file, const WasmTableType *type)438      : TableSymbol(name, UndefinedTableKind, flags, file, type) {439    this->importName = importName;440    this->importModule = importModule;441  }442 443  static bool classof(const Symbol *s) {444    return s->kind() == UndefinedTableKind;445  }446};447 448// A tag is a general format to distinguish typed entities. Each tag has an449// attribute and a type. Currently the attribute can only specify that the tag450// is for an exception tag.451//452// In exception handling, tags are used to distinguish different kinds of453// exceptions. For example, they can be used to distinguish different language's454// exceptions, e.g., all C++ exceptions have the same tag and Java exceptions455// would have a distinct tag. Wasm can filter the exceptions it catches based on456// their tag.457//458// A single TagSymbol object represents a single tag. The C++ exception symbol459// is a weak symbol generated in every object file in which exceptions are used,460// and is named '__cpp_exception' for linking.461class TagSymbol : public Symbol {462public:463  static bool classof(const Symbol *s) {464    return s->kind() == DefinedTagKind || s->kind() == UndefinedTagKind;465  }466 467  // Get/set the tag index468  uint32_t getTagIndex() const;469  void setTagIndex(uint32_t index);470  bool hasTagIndex() const;471 472  const WasmSignature *signature;473 474protected:475  TagSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,476            const WasmSignature *sig)477      : Symbol(name, k, flags, f), signature(sig) {}478 479  uint32_t tagIndex = INVALID_INDEX;480};481 482class DefinedTag : public TagSymbol {483public:484  DefinedTag(StringRef name, uint32_t flags, InputFile *file, InputTag *tag);485 486  static bool classof(const Symbol *s) { return s->kind() == DefinedTagKind; }487 488  InputTag *tag;489};490 491class UndefinedTag : public TagSymbol {492public:493  UndefinedTag(StringRef name, std::optional<StringRef> importName,494               std::optional<StringRef> importModule, uint32_t flags,495               InputFile *file = nullptr, const WasmSignature *sig = nullptr)496      : TagSymbol(name, UndefinedTagKind, flags, file, sig) {497    this->importName = importName;498    this->importModule = importModule;499  }500 501  static bool classof(const Symbol *s) { return s->kind() == UndefinedTagKind; }502};503 504class SharedFunctionSymbol : public FunctionSymbol {505public:506  SharedFunctionSymbol(StringRef name, uint32_t flags, InputFile *file,507                       const WasmSignature *sig)508      : FunctionSymbol(name, SharedFunctionKind, flags, file, sig) {}509  static bool classof(const Symbol *s) {510    return s->kind() == SharedFunctionKind;511  }512};513 514// LazySymbol symbols represent symbols in object files between --start-lib and515// --end-lib options. LLD also handles traditional archives as if all the files516// in the archive are surrounded by --start-lib and --end-lib.517//518// A special complication is the handling of weak undefined symbols. They should519// not load a file, but we have to remember we have seen both the weak undefined520// and the lazy. We represent that with a lazy symbol with a weak binding. This521// means that code looking for undefined symbols normally also has to take lazy522// symbols into consideration.523class LazySymbol : public Symbol {524public:525  LazySymbol(StringRef name, uint32_t flags, InputFile *file)526      : Symbol(name, LazyKind, flags, file) {}527 528  static bool classof(const Symbol *s) { return s->kind() == LazyKind; }529  void extract();530  void setWeak();531 532  // Lazy symbols can have a signature because they can replace an533  // UndefinedFunction in which case we need to be able to preserve the534  // signature.535  // TODO(sbc): This repetition of the signature field is inelegant.  Revisit536  // the use of class hierarchy to represent symbol taxonomy.537  const WasmSignature *signature = nullptr;538};539 540// A buffer class that is large enough to hold any Symbol-derived541// object. We allocate memory using this class and instantiate a symbol542// using the placement new.543union SymbolUnion {544  alignas(DefinedFunction) char a[sizeof(DefinedFunction)];545  alignas(DefinedData) char b[sizeof(DefinedData)];546  alignas(DefinedGlobal) char c[sizeof(DefinedGlobal)];547  alignas(DefinedTag) char d[sizeof(DefinedTag)];548  alignas(DefinedTable) char e[sizeof(DefinedTable)];549  alignas(LazySymbol) char f[sizeof(LazySymbol)];550  alignas(UndefinedFunction) char g[sizeof(UndefinedFunction)];551  alignas(UndefinedData) char h[sizeof(UndefinedData)];552  alignas(UndefinedGlobal) char i[sizeof(UndefinedGlobal)];553  alignas(UndefinedTable) char j[sizeof(UndefinedTable)];554  alignas(SectionSymbol) char k[sizeof(SectionSymbol)];555  alignas(SharedFunctionSymbol) char l[sizeof(SharedFunctionSymbol)];556};557 558// It is important to keep the size of SymbolUnion small for performance and559// memory usage reasons. 96 bytes is a soft limit based on the size of560// UndefinedFunction on a 64-bit system.561static_assert(sizeof(SymbolUnion) <= 120, "SymbolUnion too large");562 563void printTraceSymbol(Symbol *sym);564void printTraceSymbolUndefined(StringRef name, const InputFile* file);565 566template <typename T, typename... ArgT>567T *replaceSymbol(Symbol *s, ArgT &&... arg) {568  static_assert(std::is_trivially_destructible<T>(),569                "Symbol types must be trivially destructible");570  static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");571  static_assert(alignof(T) <= alignof(SymbolUnion),572                "SymbolUnion not aligned enough");573  assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&574         "Not a Symbol");575 576  Symbol symCopy = *s;577 578  T *s2 = new (s) T(std::forward<ArgT>(arg)...);579  s2->isUsedInRegularObj = symCopy.isUsedInRegularObj;580  s2->forceExport = symCopy.forceExport;581  s2->forceImport = symCopy.forceImport;582  s2->canInline = symCopy.canInline;583  s2->traced = symCopy.traced;584  s2->referenced = symCopy.referenced;585 586  // Print out a log message if --trace-symbol was specified.587  // This is for debugging.588  if (s2->traced)589    printTraceSymbol(s2);590 591  return s2;592}593 594} // namespace wasm595 596// Returns a symbol name for an error message.597std::string toString(const wasm::Symbol &sym);598std::string toString(wasm::Symbol::Kind kind);599std::string maybeDemangleSymbol(StringRef name);600 601} // namespace lld602 603#endif604