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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLD_MACHO_SYMBOLS_H 10 #define LLD_MACHO_SYMBOLS_H 11 12 #include "InputSection.h" 13 #include "Target.h" 14 #include "lld/Common/ErrorHandler.h" 15 #include "lld/Common/Strings.h" 16 #include "llvm/Object/Archive.h" 17 18 namespace lld { 19 namespace macho { 20 21 class InputSection; 22 class DylibFile; 23 class ArchiveFile; 24 25 struct StringRefZ { 26 StringRefZ(const char *s) : data(s), size(-1) {} 27 StringRefZ(StringRef s) : data(s.data()), size(s.size()) {} 28 29 const char *data; 30 const uint32_t size; 31 }; 32 33 class Symbol { 34 public: 35 enum Kind { 36 DefinedKind, 37 UndefinedKind, 38 DylibKind, 39 LazyKind, 40 }; 41 42 Kind kind() const { return static_cast<Kind>(symbolKind); } 43 44 StringRef getName() const { return {name.data, name.size}; } 45 46 uint64_t getVA() const; 47 48 uint64_t getFileOffset() const; 49 50 uint32_t gotIndex = UINT32_MAX; 51 52 protected: 53 Symbol(Kind k, StringRefZ name) : symbolKind(k), name(name) {} 54 55 Kind symbolKind; 56 StringRefZ name; 57 }; 58 59 class Defined : public Symbol { 60 public: 61 Defined(StringRefZ name, InputSection *isec, uint32_t value) 62 : Symbol(DefinedKind, name), isec(isec), value(value) {} 63 64 InputSection *isec; 65 uint32_t value; 66 67 static bool classof(const Symbol *s) { return s->kind() == DefinedKind; } 68 }; 69 70 class Undefined : public Symbol { 71 public: 72 Undefined(StringRefZ name) : Symbol(UndefinedKind, name) {} 73 74 static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; } 75 }; 76 77 class DylibSymbol : public Symbol { 78 public: 79 DylibSymbol(DylibFile *file, StringRefZ name) 80 : Symbol(DylibKind, name), file(file) {} 81 82 static bool classof(const Symbol *s) { return s->kind() == DylibKind; } 83 84 DylibFile *file; 85 uint32_t stubsIndex = UINT32_MAX; 86 uint32_t lazyBindOffset = UINT32_MAX; 87 }; 88 89 class LazySymbol : public Symbol { 90 public: 91 LazySymbol(ArchiveFile *file, const llvm::object::Archive::Symbol &sym) 92 : Symbol(LazyKind, sym.getName()), file(file), sym(sym) {} 93 94 static bool classof(const Symbol *s) { return s->kind() == LazyKind; } 95 96 void fetchArchiveMember(); 97 98 private: 99 ArchiveFile *file; 100 const llvm::object::Archive::Symbol sym; 101 }; 102 103 inline uint64_t Symbol::getVA() const { 104 if (auto *d = dyn_cast<Defined>(this)) 105 return d->isec->getVA() + d->value; 106 return 0; 107 } 108 109 inline uint64_t Symbol::getFileOffset() const { 110 if (auto *d = dyn_cast<Defined>(this)) 111 return d->isec->getFileOffset() + d->value; 112 llvm_unreachable("attempt to get an offset from an undefined symbol"); 113 } 114 115 union SymbolUnion { 116 alignas(Defined) char a[sizeof(Defined)]; 117 alignas(Undefined) char b[sizeof(Undefined)]; 118 alignas(DylibSymbol) char c[sizeof(DylibSymbol)]; 119 alignas(LazySymbol) char d[sizeof(LazySymbol)]; 120 }; 121 122 template <typename T, typename... ArgT> 123 void replaceSymbol(Symbol *s, ArgT &&... arg) { 124 static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small"); 125 static_assert(alignof(T) <= alignof(SymbolUnion), 126 "SymbolUnion not aligned enough"); 127 assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr && 128 "Not a Symbol"); 129 130 new (s) T(std::forward<ArgT>(arg)...); 131 } 132 133 } // namespace macho 134 135 std::string toString(const macho::Symbol &); 136 } // namespace lld 137 138 #endif 139