brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.7 KiB · 9f077dd Raw
548 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_COFF_SYMBOLS_H10#define LLD_COFF_SYMBOLS_H11 12#include "Chunks.h"13#include "Config.h"14#include "lld/Common/LLVM.h"15#include "lld/Common/Memory.h"16#include "llvm/ADT/ArrayRef.h"17#include "llvm/Object/Archive.h"18#include "llvm/Object/COFF.h"19#include <atomic>20#include <memory>21#include <vector>22 23namespace lld {24 25namespace coff {26 27using llvm::object::Archive;28using llvm::object::COFFSymbolRef;29using llvm::object::coff_import_header;30using llvm::object::coff_symbol_generic;31 32class ArchiveFile;33class COFFLinkerContext;34class InputFile;35class ObjFile;36class Symbol;37class SymbolTable;38 39const COFFSyncStream &operator<<(const COFFSyncStream &,40                                 const llvm::object::Archive::Symbol *);41 42// The base class for real symbol classes.43class Symbol {44public:45  enum Kind {46    // The order of these is significant. We start with the regular defined47    // symbols as those are the most prevalent and the zero tag is the cheapest48    // to set. Among the defined kinds, the lower the kind is preferred over49    // the higher kind when testing whether one symbol should take precedence50    // over another.51    DefinedRegularKind = 0,52    DefinedCommonKind,53    DefinedLocalImportKind,54    DefinedImportThunkKind,55    DefinedImportDataKind,56    DefinedAbsoluteKind,57    DefinedSyntheticKind,58 59    UndefinedKind,60    LazyArchiveKind,61    LazyObjectKind,62    LazyDLLSymbolKind,63 64    LastDefinedCOFFKind = DefinedCommonKind,65    LastDefinedKind = DefinedSyntheticKind,66  };67 68  Kind kind() const { return static_cast<Kind>(symbolKind); }69 70  // Returns the symbol name.71  StringRef getName() {72    // COFF symbol names are read lazily for a performance reason.73    // Non-external symbol names are never used by the linker except for logging74    // or debugging. Their internal references are resolved not by name but by75    // symbol index. And because they are not external, no one can refer them by76    // name. Object files contain lots of non-external symbols, and creating77    // StringRefs for them (which involves lots of strlen() on the string table)78    // is a waste of time.79    if (nameData == nullptr)80      computeName();81    return StringRef(nameData, nameSize);82  }83 84  void replaceKeepingName(Symbol *other, size_t size);85 86  // Returns the file from which this symbol was created.87  InputFile *getFile();88 89  // Indicates that this symbol will be included in the final image. Only valid90  // after calling markLive.91  bool isLive() const;92 93  bool isLazy() const {94    return symbolKind == LazyArchiveKind || symbolKind == LazyObjectKind ||95           symbolKind == LazyDLLSymbolKind;96  }97 98  // Get the Defined symbol associated with this symbol, either itself or its99  // weak alias.100  Defined *getDefined();101 102private:103  void computeName();104 105protected:106  friend SymbolTable;107  explicit Symbol(Kind k, StringRef n = "")108      : symbolKind(k), isExternal(true), isCOMDAT(false),109        writtenToSymtab(false), isUsedInRegularObj(false),110        pendingArchiveLoad(false), isGCRoot(false), isRuntimePseudoReloc(false),111        deferUndefined(false), canInline(true), isWeak(false), isAntiDep(false),112        nameSize(n.size()), nameData(n.empty() ? nullptr : n.data()) {113    assert((!n.empty() || k <= LastDefinedCOFFKind) &&114           "If the name is empty, the Symbol must be a DefinedCOFF.");115  }116 117  unsigned symbolKind : 8;118  unsigned isExternal : 1;119 120public:121  // This bit is used by the \c DefinedRegular subclass.122  unsigned isCOMDAT : 1;123 124  // This bit is used by Writer::createSymbolAndStringTable() to prevent125  // symbols from being written to the symbol table more than once.126  unsigned writtenToSymtab : 1;127 128  // True if this symbol was referenced by a regular (non-bitcode) object.129  unsigned isUsedInRegularObj : 1;130 131  // True if we've seen both a lazy and an undefined symbol with this symbol132  // name, which means that we have enqueued an archive member load and should133  // not load any more archive members to resolve the same symbol.134  unsigned pendingArchiveLoad : 1;135 136  /// True if we've already added this symbol to the list of GC roots.137  unsigned isGCRoot : 1;138 139  unsigned isRuntimePseudoReloc : 1;140 141  // True if we want to allow this symbol to be undefined in the early142  // undefined check pass in SymbolTable::reportUnresolvable(), as it143  // might be fixed up later.144  unsigned deferUndefined : 1;145 146  // False if LTO shouldn't inline whatever this symbol points to. If a symbol147  // is overwritten after LTO, LTO shouldn't inline the symbol because it148  // doesn't know the final contents of the symbol.149  unsigned canInline : 1;150 151  // True if the symbol is weak. This is only tracked for bitcode/LTO symbols.152  // This information isn't written to the output; rather, it's used for153  // managing weak symbol overrides.154  unsigned isWeak : 1;155 156  // True if the symbol is an anti-dependency.157  unsigned isAntiDep : 1;158 159protected:160  // Symbol name length. Assume symbol lengths fit in a 32-bit integer.161  uint32_t nameSize;162 163  const char *nameData;164};165 166// The base class for any defined symbols, including absolute symbols,167// etc.168class Defined : public Symbol {169public:170  Defined(Kind k, StringRef n) : Symbol(k, n) {}171 172  static bool classof(const Symbol *s) { return s->kind() <= LastDefinedKind; }173 174  // Returns the RVA (relative virtual address) of this symbol. The175  // writer sets and uses RVAs.176  uint64_t getRVA();177 178  // Returns the chunk containing this symbol. Absolute symbols and __ImageBase179  // do not have chunks, so this may return null.180  Chunk *getChunk();181};182 183// Symbols defined via a COFF object file or bitcode file.  For COFF files, this184// stores a coff_symbol_generic*, and names of internal symbols are lazily185// loaded through that. For bitcode files, Sym is nullptr and the name is stored186// as a decomposed StringRef.187class DefinedCOFF : public Defined {188  friend Symbol;189 190public:191  DefinedCOFF(Kind k, InputFile *f, StringRef n, const coff_symbol_generic *s)192      : Defined(k, n), file(f), sym(s) {}193 194  static bool classof(const Symbol *s) {195    return s->kind() <= LastDefinedCOFFKind;196  }197 198  InputFile *getFile() { return file; }199 200  COFFSymbolRef getCOFFSymbol();201 202  InputFile *file;203 204protected:205  const coff_symbol_generic *sym;206};207 208// Regular defined symbols read from object file symbol tables.209class DefinedRegular : public DefinedCOFF {210public:211  DefinedRegular(InputFile *f, StringRef n, bool isCOMDAT,212                 bool isExternal = false,213                 const coff_symbol_generic *s = nullptr,214                 SectionChunk *c = nullptr, bool isWeak = false)215      : DefinedCOFF(DefinedRegularKind, f, n, s), data(c ? &c->repl : nullptr) {216    this->isExternal = isExternal;217    this->isCOMDAT = isCOMDAT;218    this->isWeak = isWeak;219  }220 221  static bool classof(const Symbol *s) {222    return s->kind() == DefinedRegularKind;223  }224 225  uint64_t getRVA() const { return (*data)->getRVA() + sym->Value; }226  SectionChunk *getChunk() const { return *data; }227  uint32_t getValue() const { return sym->Value; }228 229  SectionChunk **data;230};231 232class DefinedCommon : public DefinedCOFF {233public:234  DefinedCommon(InputFile *f, StringRef n, uint64_t size,235                const coff_symbol_generic *s = nullptr,236                CommonChunk *c = nullptr)237      : DefinedCOFF(DefinedCommonKind, f, n, s), data(c), size(size) {238    this->isExternal = true;239    if (c)240      c->live = true;241  }242 243  static bool classof(const Symbol *s) {244    return s->kind() == DefinedCommonKind;245  }246 247  uint64_t getRVA() { return data->getRVA(); }248  CommonChunk *getChunk() { return data; }249 250private:251  friend SymbolTable;252  uint64_t getSize() const { return size; }253  CommonChunk *data;254  uint64_t size;255};256 257// Absolute symbols.258class DefinedAbsolute : public Defined {259public:260  DefinedAbsolute(const COFFLinkerContext &c, StringRef n, COFFSymbolRef s)261      : Defined(DefinedAbsoluteKind, n), va(s.getValue()), ctx(c) {262    isExternal = s.isExternal();263  }264 265  DefinedAbsolute(const COFFLinkerContext &c, StringRef n, uint64_t v)266      : Defined(DefinedAbsoluteKind, n), va(v), ctx(c) {}267 268  static bool classof(const Symbol *s) {269    return s->kind() == DefinedAbsoluteKind;270  }271 272  uint64_t getRVA();273  void setVA(uint64_t v) { va = v; }274  uint64_t getVA() const { return va; }275 276private:277  uint64_t va;278  const COFFLinkerContext &ctx;279};280 281// This symbol is used for linker-synthesized symbols like __ImageBase and282// __safe_se_handler_table.283class DefinedSynthetic : public Defined {284public:285  explicit DefinedSynthetic(StringRef name, Chunk *c, uint32_t offset = 0)286      : Defined(DefinedSyntheticKind, name), c(c), offset(offset) {}287 288  static bool classof(const Symbol *s) {289    return s->kind() == DefinedSyntheticKind;290  }291 292  // A null chunk indicates that this is __ImageBase. Otherwise, this is some293  // other synthesized chunk, like SEHTableChunk.294  uint32_t getRVA() { return c ? c->getRVA() + offset : 0; }295  Chunk *getChunk() { return c; }296 297private:298  Chunk *c;299  uint32_t offset;300};301 302// This class represents a symbol defined in an archive file. It is303// created from an archive file header, and it knows how to load an304// object file from an archive to replace itself with a defined305// symbol. If the resolver finds both Undefined and LazyArchive for306// the same name, it will ask the LazyArchive to load a file.307class LazyArchive : public Symbol {308public:309  LazyArchive(ArchiveFile *f, const Archive::Symbol s)310      : Symbol(LazyArchiveKind, s.getName()), file(f), sym(s) {}311 312  static bool classof(const Symbol *s) { return s->kind() == LazyArchiveKind; }313 314  MemoryBufferRef getMemberBuffer();315 316  ArchiveFile *file;317  const Archive::Symbol sym;318};319 320class LazyObject : public Symbol {321public:322  LazyObject(InputFile *f, StringRef n) : Symbol(LazyObjectKind, n), file(f) {}323  static bool classof(const Symbol *s) { return s->kind() == LazyObjectKind; }324  InputFile *file;325};326 327// MinGW only.328class LazyDLLSymbol : public Symbol {329public:330  LazyDLLSymbol(DLLFile *f, DLLFile::Symbol *s, StringRef n)331      : Symbol(LazyDLLSymbolKind, n), file(f), sym(s) {}332  static bool classof(const Symbol *s) {333    return s->kind() == LazyDLLSymbolKind;334  }335 336  DLLFile *file;337  DLLFile::Symbol *sym;338};339 340// Undefined symbols.341class Undefined : public Symbol {342public:343  explicit Undefined(StringRef n) : Symbol(UndefinedKind, n) {}344 345  static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; }346 347  // An undefined symbol can have a fallback symbol which gives an348  // undefined symbol a second chance if it would remain undefined.349  // If it remains undefined, it'll be replaced with whatever the350  // Alias pointer points to.351  Symbol *weakAlias = nullptr;352 353  // If this symbol is external weak, try to resolve it to a defined354  // symbol by searching the chain of fallback symbols. Returns the symbol if355  // successful, otherwise returns null.356  Symbol *getWeakAlias();357  Defined *getDefinedWeakAlias() {358    return dyn_cast_or_null<Defined>(getWeakAlias());359  }360 361  void setWeakAlias(Symbol *sym, bool antiDep = false) {362    weakAlias = sym;363    isAntiDep = antiDep;364  }365 366  bool isECAlias(MachineTypes machine) const {367    return weakAlias && isAntiDep && isArm64EC(machine);368  }369 370  // If this symbol is external weak, replace this object with aliased symbol.371  bool resolveWeakAlias();372};373 374// Windows-specific classes.375 376// This class represents a symbol imported from a DLL. This has two377// names for internal use and external use. The former is used for378// name resolution, and the latter is used for the import descriptor379// table in an output. The former has "__imp_" prefix.380class DefinedImportData : public Defined {381public:382  DefinedImportData(StringRef n, ImportFile *file, Chunk *&location)383      : Defined(DefinedImportDataKind, n), file(file), location(location) {}384 385  static bool classof(const Symbol *s) {386    return s->kind() == DefinedImportDataKind;387  }388 389  uint64_t getRVA() { return getChunk()->getRVA(); }390  Chunk *getChunk() { return location; }391  void setLocation(Chunk *addressTable) { location = addressTable; }392 393  StringRef getDLLName() { return file->dllName; }394  StringRef getExternalName() { return file->externalName; }395  uint16_t getOrdinal() { return file->hdr->OrdinalHint; }396 397  ImportFile *file;398  Chunk *&location;399 400  // This is a pointer to the synthetic symbol associated with the load thunk401  // for this symbol that will be called if the DLL is delay-loaded. This is402  // needed for Control Flow Guard because if this DefinedImportData symbol is a403  // valid call target, the corresponding load thunk must also be marked as a404  // valid call target.405  DefinedSynthetic *loadThunkSym = nullptr;406};407 408// This class represents a symbol for a jump table entry which jumps409// to a function in a DLL. Linker are supposed to create such symbols410// without "__imp_" prefix for all function symbols exported from411// DLLs, so that you can call DLL functions as regular functions with412// a regular name. A function pointer is given as a DefinedImportData.413class DefinedImportThunk : public Defined {414public:415  DefinedImportThunk(COFFLinkerContext &ctx, StringRef name,416                     DefinedImportData *s, ImportThunkChunk *chunk);417 418  static bool classof(const Symbol *s) {419    return s->kind() == DefinedImportThunkKind;420  }421 422  uint64_t getRVA() { return data->getRVA(); }423  ImportThunkChunk *getChunk() const { return data; }424 425  DefinedImportData *wrappedSym;426 427private:428  ImportThunkChunk *data;429};430 431// If you have a symbol "foo" in your object file, a symbol name432// "__imp_foo" becomes automatically available as a pointer to "foo".433// This class is for such automatically-created symbols.434// Yes, this is an odd feature. We didn't intend to implement that.435// This is here just for compatibility with MSVC.436class DefinedLocalImport : public Defined {437public:438  DefinedLocalImport(COFFLinkerContext &ctx, StringRef n, Defined *s)439      : Defined(DefinedLocalImportKind, n),440        data(make<LocalImportChunk>(ctx, s)) {}441 442  static bool classof(const Symbol *s) {443    return s->kind() == DefinedLocalImportKind;444  }445 446  uint64_t getRVA() { return data->getRVA(); }447  Chunk *getChunk() { return data; }448 449private:450  LocalImportChunk *data;451};452 453inline uint64_t Defined::getRVA() {454  switch (kind()) {455  case DefinedAbsoluteKind:456    return cast<DefinedAbsolute>(this)->getRVA();457  case DefinedSyntheticKind:458    return cast<DefinedSynthetic>(this)->getRVA();459  case DefinedImportDataKind:460    return cast<DefinedImportData>(this)->getRVA();461  case DefinedImportThunkKind:462    return cast<DefinedImportThunk>(this)->getRVA();463  case DefinedLocalImportKind:464    return cast<DefinedLocalImport>(this)->getRVA();465  case DefinedCommonKind:466    return cast<DefinedCommon>(this)->getRVA();467  case DefinedRegularKind:468    return cast<DefinedRegular>(this)->getRVA();469  case LazyArchiveKind:470  case LazyObjectKind:471  case LazyDLLSymbolKind:472  case UndefinedKind:473    llvm_unreachable("Cannot get the address for an undefined symbol.");474  }475  llvm_unreachable("unknown symbol kind");476}477 478inline Chunk *Defined::getChunk() {479  switch (kind()) {480  case DefinedRegularKind:481    return cast<DefinedRegular>(this)->getChunk();482  case DefinedAbsoluteKind:483    return nullptr;484  case DefinedSyntheticKind:485    return cast<DefinedSynthetic>(this)->getChunk();486  case DefinedImportDataKind:487    return cast<DefinedImportData>(this)->getChunk();488  case DefinedImportThunkKind:489    return cast<DefinedImportThunk>(this)->getChunk();490  case DefinedLocalImportKind:491    return cast<DefinedLocalImport>(this)->getChunk();492  case DefinedCommonKind:493    return cast<DefinedCommon>(this)->getChunk();494  case LazyArchiveKind:495  case LazyObjectKind:496  case LazyDLLSymbolKind:497  case UndefinedKind:498    llvm_unreachable("Cannot get the chunk of an undefined symbol.");499  }500  llvm_unreachable("unknown symbol kind");501}502 503// A buffer class that is large enough to hold any Symbol-derived504// object. We allocate memory using this class and instantiate a symbol505// using the placement new.506union SymbolUnion {507  alignas(DefinedRegular) char a[sizeof(DefinedRegular)];508  alignas(DefinedCommon) char b[sizeof(DefinedCommon)];509  alignas(DefinedAbsolute) char c[sizeof(DefinedAbsolute)];510  alignas(DefinedSynthetic) char d[sizeof(DefinedSynthetic)];511  alignas(LazyArchive) char e[sizeof(LazyArchive)];512  alignas(Undefined) char f[sizeof(Undefined)];513  alignas(DefinedImportData) char g[sizeof(DefinedImportData)];514  alignas(DefinedImportThunk) char h[sizeof(DefinedImportThunk)];515  alignas(DefinedLocalImport) char i[sizeof(DefinedLocalImport)];516  alignas(LazyObject) char j[sizeof(LazyObject)];517  alignas(LazyDLLSymbol) char k[sizeof(LazyDLLSymbol)];518};519 520template <typename T, typename... ArgT>521void replaceSymbol(Symbol *s, ArgT &&... arg) {522  static_assert(std::is_trivially_destructible<T>(),523                "Symbol types must be trivially destructible");524  static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small");525  static_assert(alignof(T) <= alignof(SymbolUnion),526                "SymbolUnion not aligned enough");527  assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&528         "Not a Symbol");529  bool canInline = s->canInline;530  bool isUsedInRegularObj = s->isUsedInRegularObj;531  new (s) T(std::forward<ArgT>(arg)...);532  s->canInline = canInline;533  s->isUsedInRegularObj = isUsedInRegularObj;534}535} // namespace coff536 537std::string toString(const coff::COFFLinkerContext &ctx, coff::Symbol &b);538std::string toCOFFString(const coff::COFFLinkerContext &ctx,539                         const llvm::object::Archive::Symbol &b);540 541// Returns a symbol name for an error message.542std::string maybeDemangleSymbol(const coff::COFFLinkerContext &ctx,543                                StringRef symName);544 545} // namespace lld546 547#endif548