Mercurial > hg > CbC > CbC_llvm
comparison lld/MachO/Symbols.h @ 207:2e18cbf3894f
LLVM12
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 08 Jun 2021 06:07:14 +0900 |
parents | 0572611fdcc8 |
children | 5f17cb93ff66 |
comparison
equal
deleted
inserted
replaced
173:0572611fdcc8 | 207:2e18cbf3894f |
---|---|
7 //===----------------------------------------------------------------------===// | 7 //===----------------------------------------------------------------------===// |
8 | 8 |
9 #ifndef LLD_MACHO_SYMBOLS_H | 9 #ifndef LLD_MACHO_SYMBOLS_H |
10 #define LLD_MACHO_SYMBOLS_H | 10 #define LLD_MACHO_SYMBOLS_H |
11 | 11 |
12 #include "InputFiles.h" | |
12 #include "InputSection.h" | 13 #include "InputSection.h" |
13 #include "Target.h" | 14 #include "Target.h" |
15 #include "lld/Common/ErrorHandler.h" | |
14 #include "lld/Common/Strings.h" | 16 #include "lld/Common/Strings.h" |
15 #include "llvm/Object/Archive.h" | 17 #include "llvm/Object/Archive.h" |
18 #include "llvm/Support/MathExtras.h" | |
16 | 19 |
17 namespace lld { | 20 namespace lld { |
18 namespace macho { | 21 namespace macho { |
19 | 22 |
20 class InputSection; | 23 class InputSection; |
21 class DylibFile; | 24 class MachHeaderSection; |
22 class ArchiveFile; | |
23 | 25 |
24 struct StringRefZ { | 26 struct StringRefZ { |
25 StringRefZ(const char *s) : data(s), size(-1) {} | 27 StringRefZ(const char *s) : data(s), size(-1) {} |
26 StringRefZ(StringRef s) : data(s.data()), size(s.size()) {} | 28 StringRefZ(StringRef s) : data(s.data()), size(s.size()) {} |
27 | 29 |
32 class Symbol { | 34 class Symbol { |
33 public: | 35 public: |
34 enum Kind { | 36 enum Kind { |
35 DefinedKind, | 37 DefinedKind, |
36 UndefinedKind, | 38 UndefinedKind, |
39 CommonKind, | |
37 DylibKind, | 40 DylibKind, |
38 LazyKind, | 41 LazyKind, |
39 }; | 42 }; |
40 | 43 |
41 Kind kind() const { return static_cast<Kind>(symbolKind); } | 44 virtual ~Symbol() {} |
42 | 45 |
43 StringRef getName() const { return {name.data, name.size}; } | 46 Kind kind() const { return symbolKind; } |
44 | 47 |
45 uint64_t getVA() const; | 48 StringRef getName() const { |
49 if (nameSize == (uint32_t)-1) | |
50 nameSize = strlen(nameData); | |
51 return {nameData, nameSize}; | |
52 } | |
53 | |
54 bool isLive() const; | |
55 | |
56 virtual uint64_t getVA() const { return 0; } | |
57 | |
58 virtual uint64_t getFileOffset() const { | |
59 llvm_unreachable("attempt to get an offset from a non-defined symbol"); | |
60 } | |
61 | |
62 virtual bool isWeakDef() const { llvm_unreachable("cannot be weak def"); } | |
63 | |
64 // Only undefined or dylib symbols can be weak references. A weak reference | |
65 // need not be satisfied at runtime, e.g. due to the symbol not being | |
66 // available on a given target platform. | |
67 virtual bool isWeakRef() const { llvm_unreachable("cannot be a weak ref"); } | |
68 | |
69 virtual bool isTlv() const { llvm_unreachable("cannot be TLV"); } | |
70 | |
71 // Whether this symbol is in the GOT or TLVPointer sections. | |
72 bool isInGot() const { return gotIndex != UINT32_MAX; } | |
73 | |
74 // Whether this symbol is in the StubsSection. | |
75 bool isInStubs() const { return stubsIndex != UINT32_MAX; } | |
76 | |
77 uint64_t getStubVA() const; | |
78 uint64_t getGotVA() const; | |
79 uint64_t getTlvVA() const; | |
80 uint64_t resolveBranchVA() const { | |
81 assert(isa<Defined>(this) || isa<DylibSymbol>(this)); | |
82 return isInStubs() ? getStubVA() : getVA(); | |
83 } | |
84 uint64_t resolveGotVA() const { return isInGot() ? getGotVA() : getVA(); } | |
85 uint64_t resolveTlvVA() const { return isInGot() ? getTlvVA() : getVA(); } | |
86 | |
87 // The index of this symbol in the GOT or the TLVPointer section, depending | |
88 // on whether it is a thread-local. A given symbol cannot be referenced by | |
89 // both these sections at once. | |
90 uint32_t gotIndex = UINT32_MAX; | |
91 | |
92 uint32_t stubsIndex = UINT32_MAX; | |
93 | |
94 uint32_t symtabIndex = UINT32_MAX; | |
95 | |
96 InputFile *getFile() const { return file; } | |
46 | 97 |
47 protected: | 98 protected: |
48 Symbol(Kind k, StringRefZ name) : symbolKind(k), name(name) {} | 99 Symbol(Kind k, StringRefZ name, InputFile *file) |
100 : symbolKind(k), nameData(name.data), nameSize(name.size), file(file), | |
101 isUsedInRegularObj(!file || isa<ObjFile>(file)), | |
102 used(!config->deadStrip) {} | |
49 | 103 |
50 Kind symbolKind; | 104 Kind symbolKind; |
51 StringRefZ name; | 105 const char *nameData; |
106 mutable uint32_t nameSize; | |
107 InputFile *file; | |
108 | |
109 public: | |
110 // True if this symbol was referenced by a regular (non-bitcode) object. | |
111 bool isUsedInRegularObj : 1; | |
112 | |
113 // True if an undefined or dylib symbol is used from a live section. | |
114 bool used : 1; | |
52 }; | 115 }; |
53 | 116 |
54 class Defined : public Symbol { | 117 class Defined : public Symbol { |
55 public: | 118 public: |
56 Defined(StringRefZ name, InputSection *isec, uint32_t value) | 119 Defined(StringRefZ name, InputFile *file, InputSection *isec, uint64_t value, |
57 : Symbol(DefinedKind, name), isec(isec), value(value) {} | 120 uint64_t size, bool isWeakDef, bool isExternal, bool isPrivateExtern, |
121 bool isThumb, bool isReferencedDynamically, bool noDeadStrip) | |
122 : Symbol(DefinedKind, name, file), isec(isec), value(value), size(size), | |
123 overridesWeakDef(false), privateExtern(isPrivateExtern), | |
124 includeInSymtab(true), thumb(isThumb), | |
125 referencedDynamically(isReferencedDynamically), | |
126 noDeadStrip(noDeadStrip), weakDef(isWeakDef), external(isExternal) { | |
127 if (isec) | |
128 isec->numRefs++; | |
129 } | |
130 | |
131 bool isWeakDef() const override { return weakDef; } | |
132 bool isExternalWeakDef() const { | |
133 return isWeakDef() && isExternal() && !privateExtern; | |
134 } | |
135 bool isTlv() const override { | |
136 return !isAbsolute() && isThreadLocalVariables(isec->flags); | |
137 } | |
138 | |
139 bool isExternal() const { return external; } | |
140 bool isAbsolute() const { return isec == nullptr; } | |
141 | |
142 uint64_t getVA() const override; | |
143 uint64_t getFileOffset() const override; | |
144 | |
145 static bool classof(const Symbol *s) { return s->kind() == DefinedKind; } | |
58 | 146 |
59 InputSection *isec; | 147 InputSection *isec; |
60 uint32_t value; | 148 // Contains the offset from the containing subsection. Note that this is |
61 | 149 // different from nlist::n_value, which is the absolute address of the symbol. |
62 static bool classof(const Symbol *s) { return s->kind() == DefinedKind; } | 150 uint64_t value; |
63 }; | 151 // size is only calculated for regular (non-bitcode) symbols. |
152 uint64_t size; | |
153 | |
154 bool overridesWeakDef : 1; | |
155 // Whether this symbol should appear in the output binary's export trie. | |
156 bool privateExtern : 1; | |
157 // Whether this symbol should appear in the output symbol table. | |
158 bool includeInSymtab : 1; | |
159 // Only relevant when compiling for Thumb-supporting arm32 archs. | |
160 bool thumb : 1; | |
161 // Symbols marked referencedDynamically won't be removed from the output's | |
162 // symbol table by tools like strip. In theory, this could be set on arbitrary | |
163 // symbols in input object files. In practice, it's used solely for the | |
164 // synthetic __mh_execute_header symbol. | |
165 // This is information for the static linker, and it's also written to the | |
166 // output file's symbol table for tools running later (such as `strip`). | |
167 bool referencedDynamically : 1; | |
168 // Set on symbols that should not be removed by dead code stripping. | |
169 // Set for example on `__attribute__((used))` globals, or on some Objective-C | |
170 // metadata. This is information only for the static linker and not written | |
171 // to the output. | |
172 bool noDeadStrip : 1; | |
173 | |
174 private: | |
175 const bool weakDef : 1; | |
176 const bool external : 1; | |
177 }; | |
178 | |
179 // This enum does double-duty: as a symbol property, it indicates whether & how | |
180 // a dylib symbol is referenced. As a DylibFile property, it indicates the kind | |
181 // of referenced symbols contained within the file. If there are both weak | |
182 // and strong references to the same file, we will count the file as | |
183 // strongly-referenced. | |
184 enum class RefState : uint8_t { Unreferenced = 0, Weak = 1, Strong = 2 }; | |
64 | 185 |
65 class Undefined : public Symbol { | 186 class Undefined : public Symbol { |
66 public: | 187 public: |
67 Undefined(StringRefZ name) : Symbol(UndefinedKind, name) {} | 188 Undefined(StringRefZ name, InputFile *file, RefState refState) |
189 : Symbol(UndefinedKind, name, file), refState(refState) { | |
190 assert(refState != RefState::Unreferenced); | |
191 } | |
192 | |
193 bool isWeakRef() const override { return refState == RefState::Weak; } | |
68 | 194 |
69 static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; } | 195 static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; } |
196 | |
197 RefState refState : 2; | |
198 }; | |
199 | |
200 // On Unix, it is traditionally allowed to write variable definitions without | |
201 // initialization expressions (such as "int foo;") to header files. These are | |
202 // called tentative definitions. | |
203 // | |
204 // Using tentative definitions is usually considered a bad practice; you should | |
205 // write only declarations (such as "extern int foo;") to header files. | |
206 // Nevertheless, the linker and the compiler have to do something to support | |
207 // bad code by allowing duplicate definitions for this particular case. | |
208 // | |
209 // The compiler creates common symbols when it sees tentative definitions. | |
210 // (You can suppress this behavior and let the compiler create a regular | |
211 // defined symbol by passing -fno-common. -fno-common is the default in clang | |
212 // as of LLVM 11.0.) When linking the final binary, if there are remaining | |
213 // common symbols after name resolution is complete, the linker converts them | |
214 // to regular defined symbols in a __common section. | |
215 class CommonSymbol : public Symbol { | |
216 public: | |
217 CommonSymbol(StringRefZ name, InputFile *file, uint64_t size, uint32_t align, | |
218 bool isPrivateExtern) | |
219 : Symbol(CommonKind, name, file), size(size), | |
220 align(align != 1 ? align : llvm::PowerOf2Ceil(size)), | |
221 privateExtern(isPrivateExtern) { | |
222 // TODO: cap maximum alignment | |
223 } | |
224 | |
225 static bool classof(const Symbol *s) { return s->kind() == CommonKind; } | |
226 | |
227 const uint64_t size; | |
228 const uint32_t align; | |
229 const bool privateExtern; | |
70 }; | 230 }; |
71 | 231 |
72 class DylibSymbol : public Symbol { | 232 class DylibSymbol : public Symbol { |
73 public: | 233 public: |
74 DylibSymbol(DylibFile *file, StringRefZ name) | 234 DylibSymbol(DylibFile *file, StringRefZ name, bool isWeakDef, |
75 : Symbol(DylibKind, name), file(file) {} | 235 RefState refState, bool isTlv) |
236 : Symbol(DylibKind, name, file), refState(refState), weakDef(isWeakDef), | |
237 tlv(isTlv) { | |
238 if (file && refState > RefState::Unreferenced) | |
239 file->numReferencedSymbols++; | |
240 } | |
241 | |
242 uint64_t getVA() const override; | |
243 bool isWeakDef() const override { return weakDef; } | |
244 bool isWeakRef() const override { return refState == RefState::Weak; } | |
245 bool isReferenced() const { return refState != RefState::Unreferenced; } | |
246 bool isTlv() const override { return tlv; } | |
247 bool isDynamicLookup() const { return file == nullptr; } | |
248 bool hasStubsHelper() const { return stubsHelperIndex != UINT32_MAX; } | |
249 | |
250 DylibFile *getFile() const { | |
251 assert(!isDynamicLookup()); | |
252 return cast<DylibFile>(file); | |
253 } | |
76 | 254 |
77 static bool classof(const Symbol *s) { return s->kind() == DylibKind; } | 255 static bool classof(const Symbol *s) { return s->kind() == DylibKind; } |
78 | 256 |
79 DylibFile *file; | 257 uint32_t stubsHelperIndex = UINT32_MAX; |
80 uint32_t gotIndex = UINT32_MAX; | |
81 uint32_t stubsIndex = UINT32_MAX; | |
82 uint32_t lazyBindOffset = UINT32_MAX; | 258 uint32_t lazyBindOffset = UINT32_MAX; |
259 | |
260 RefState getRefState() const { return refState; } | |
261 | |
262 void reference(RefState newState) { | |
263 assert(newState > RefState::Unreferenced); | |
264 if (refState == RefState::Unreferenced && file) | |
265 getFile()->numReferencedSymbols++; | |
266 refState = std::max(refState, newState); | |
267 } | |
268 | |
269 void unreference() { | |
270 // dynamic_lookup symbols have no file. | |
271 if (refState > RefState::Unreferenced && file) { | |
272 assert(getFile()->numReferencedSymbols > 0); | |
273 getFile()->numReferencedSymbols--; | |
274 } | |
275 } | |
276 | |
277 private: | |
278 RefState refState : 2; | |
279 const bool weakDef : 1; | |
280 const bool tlv : 1; | |
83 }; | 281 }; |
84 | 282 |
85 class LazySymbol : public Symbol { | 283 class LazySymbol : public Symbol { |
86 public: | 284 public: |
87 LazySymbol(ArchiveFile *file, const llvm::object::Archive::Symbol &sym) | 285 LazySymbol(ArchiveFile *file, const llvm::object::Archive::Symbol &sym) |
88 : Symbol(LazyKind, sym.getName()), file(file), sym(sym) {} | 286 : Symbol(LazyKind, sym.getName(), file), sym(sym) {} |
287 | |
288 ArchiveFile *getFile() const { return cast<ArchiveFile>(file); } | |
289 void fetchArchiveMember(); | |
89 | 290 |
90 static bool classof(const Symbol *s) { return s->kind() == LazyKind; } | 291 static bool classof(const Symbol *s) { return s->kind() == LazyKind; } |
91 | 292 |
92 void fetchArchiveMember(); | |
93 | |
94 private: | 293 private: |
95 ArchiveFile *file; | |
96 const llvm::object::Archive::Symbol sym; | 294 const llvm::object::Archive::Symbol sym; |
97 }; | 295 }; |
98 | |
99 inline uint64_t Symbol::getVA() const { | |
100 if (auto *d = dyn_cast<Defined>(this)) | |
101 return d->isec->getVA() + d->value; | |
102 return 0; | |
103 } | |
104 | 296 |
105 union SymbolUnion { | 297 union SymbolUnion { |
106 alignas(Defined) char a[sizeof(Defined)]; | 298 alignas(Defined) char a[sizeof(Defined)]; |
107 alignas(Undefined) char b[sizeof(Undefined)]; | 299 alignas(Undefined) char b[sizeof(Undefined)]; |
108 alignas(DylibSymbol) char c[sizeof(DylibSymbol)]; | 300 alignas(CommonSymbol) char c[sizeof(CommonSymbol)]; |
109 alignas(LazySymbol) char d[sizeof(LazySymbol)]; | 301 alignas(DylibSymbol) char d[sizeof(DylibSymbol)]; |
302 alignas(LazySymbol) char e[sizeof(LazySymbol)]; | |
110 }; | 303 }; |
111 | 304 |
112 template <typename T, typename... ArgT> | 305 template <typename T, typename... ArgT> |
113 void replaceSymbol(Symbol *s, ArgT &&... arg) { | 306 T *replaceSymbol(Symbol *s, ArgT &&...arg) { |
114 static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small"); | 307 static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small"); |
115 static_assert(alignof(T) <= alignof(SymbolUnion), | 308 static_assert(alignof(T) <= alignof(SymbolUnion), |
116 "SymbolUnion not aligned enough"); | 309 "SymbolUnion not aligned enough"); |
117 assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr && | 310 assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr && |
118 "Not a Symbol"); | 311 "Not a Symbol"); |
119 | 312 |
120 new (s) T(std::forward<ArgT>(arg)...); | 313 bool isUsedInRegularObj = s->isUsedInRegularObj; |
314 T *sym = new (s) T(std::forward<ArgT>(arg)...); | |
315 sym->isUsedInRegularObj |= isUsedInRegularObj; | |
316 return sym; | |
121 } | 317 } |
122 | 318 |
123 } // namespace macho | 319 } // namespace macho |
124 | 320 |
125 std::string toString(const macho::Symbol &); | 321 std::string toString(const macho::Symbol &); |
322 std::string toMachOString(const llvm::object::Archive::Symbol &); | |
323 | |
126 } // namespace lld | 324 } // namespace lld |
127 | 325 |
128 #endif | 326 #endif |