173
|
1 //===- SyntheticSections.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_SYNTHETIC_SECTIONS_H
|
|
10 #define LLD_MACHO_SYNTHETIC_SECTIONS_H
|
|
11
|
207
|
12 #include "Config.h"
|
173
|
13 #include "ExportTrie.h"
|
|
14 #include "InputSection.h"
|
|
15 #include "OutputSection.h"
|
207
|
16 #include "OutputSegment.h"
|
173
|
17 #include "Target.h"
|
|
18
|
207
|
19 #include "llvm/ADT/Hashing.h"
|
173
|
20 #include "llvm/ADT/SetVector.h"
|
207
|
21 #include "llvm/Support/MathExtras.h"
|
173
|
22 #include "llvm/Support/raw_ostream.h"
|
|
23
|
207
|
24 namespace llvm {
|
|
25 class DWARFUnit;
|
|
26 } // namespace llvm
|
|
27
|
173
|
28 namespace lld {
|
|
29 namespace macho {
|
|
30
|
207
|
31 class Defined;
|
173
|
32 class DylibSymbol;
|
|
33 class LoadCommand;
|
207
|
34 class ObjFile;
|
|
35 class UnwindInfoSection;
|
173
|
36
|
|
37 class SyntheticSection : public OutputSection {
|
|
38 public:
|
|
39 SyntheticSection(const char *segname, const char *name);
|
|
40 virtual ~SyntheticSection() = default;
|
|
41
|
|
42 static bool classof(const OutputSection *sec) {
|
|
43 return sec->kind() == SyntheticKind;
|
|
44 }
|
207
|
45
|
|
46 const StringRef segname;
|
|
47 // This fake InputSection makes it easier for us to write code that applies
|
|
48 // generically to both user inputs and synthetics.
|
|
49 InputSection *isec;
|
|
50 };
|
|
51
|
|
52 // All sections in __LINKEDIT should inherit from this.
|
|
53 class LinkEditSection : public SyntheticSection {
|
|
54 public:
|
|
55 LinkEditSection(const char *segname, const char *name)
|
|
56 : SyntheticSection(segname, name) {
|
|
57 align = target->wordSize;
|
|
58 }
|
|
59
|
|
60 virtual void finalizeContents() {}
|
|
61
|
|
62 // Sections in __LINKEDIT are special: their offsets are recorded in the
|
|
63 // load commands like LC_DYLD_INFO_ONLY and LC_SYMTAB, instead of in section
|
|
64 // headers.
|
|
65 bool isHidden() const override final { return true; }
|
|
66
|
|
67 virtual uint64_t getRawSize() const = 0;
|
|
68
|
|
69 // codesign (or more specifically libstuff) checks that each section in
|
|
70 // __LINKEDIT ends where the next one starts -- no gaps are permitted. We
|
|
71 // therefore align every section's start and end points to WordSize.
|
|
72 //
|
|
73 // NOTE: This assumes that the extra bytes required for alignment can be
|
|
74 // zero-valued bytes.
|
|
75 uint64_t getSize() const override final {
|
|
76 return llvm::alignTo(getRawSize(), align);
|
|
77 }
|
173
|
78 };
|
|
79
|
|
80 // The header of the Mach-O file, which must have a file offset of zero.
|
|
81 class MachHeaderSection : public SyntheticSection {
|
|
82 public:
|
|
83 MachHeaderSection();
|
|
84 bool isHidden() const override { return true; }
|
207
|
85 uint64_t getSize() const override;
|
173
|
86 void writeTo(uint8_t *buf) const override;
|
|
87
|
207
|
88 void addLoadCommand(LoadCommand *);
|
|
89
|
|
90 protected:
|
173
|
91 std::vector<LoadCommand *> loadCommands;
|
|
92 uint32_t sizeOfCmds = 0;
|
|
93 };
|
|
94
|
|
95 // A hidden section that exists solely for the purpose of creating the
|
|
96 // __PAGEZERO segment, which is used to catch null pointer dereferences.
|
|
97 class PageZeroSection : public SyntheticSection {
|
|
98 public:
|
|
99 PageZeroSection();
|
|
100 bool isHidden() const override { return true; }
|
207
|
101 uint64_t getSize() const override { return target->pageZeroSize; }
|
173
|
102 uint64_t getFileSize() const override { return 0; }
|
|
103 void writeTo(uint8_t *buf) const override {}
|
|
104 };
|
|
105
|
207
|
106 // This is the base class for the GOT and TLVPointer sections, which are nearly
|
|
107 // functionally identical -- they will both be populated by dyld with addresses
|
|
108 // to non-lazily-loaded dylib symbols. The main difference is that the
|
|
109 // TLVPointerSection stores references to thread-local variables.
|
|
110 class NonLazyPointerSectionBase : public SyntheticSection {
|
173
|
111 public:
|
207
|
112 NonLazyPointerSectionBase(const char *segname, const char *name);
|
173
|
113
|
207
|
114 const llvm::SetVector<const Symbol *> &getEntries() const { return entries; }
|
173
|
115
|
|
116 bool isNeeded() const override { return !entries.empty(); }
|
|
117
|
207
|
118 uint64_t getSize() const override {
|
|
119 return entries.size() * target->wordSize;
|
|
120 }
|
173
|
121
|
207
|
122 void writeTo(uint8_t *buf) const override;
|
|
123
|
|
124 void addEntry(Symbol *sym);
|
|
125
|
|
126 uint64_t getVA(uint32_t gotIndex) const {
|
|
127 return addr + gotIndex * target->wordSize;
|
173
|
128 }
|
|
129
|
207
|
130 private:
|
|
131 llvm::SetVector<const Symbol *> entries;
|
|
132 };
|
|
133
|
|
134 class GotSection : public NonLazyPointerSectionBase {
|
|
135 public:
|
|
136 GotSection()
|
|
137 : NonLazyPointerSectionBase(segment_names::dataConst,
|
|
138 section_names::got) {
|
|
139 // TODO: section_64::reserved1 should be an index into the indirect symbol
|
|
140 // table, which we do not currently emit
|
|
141 }
|
|
142 };
|
|
143
|
|
144 class TlvPointerSection : public NonLazyPointerSectionBase {
|
|
145 public:
|
|
146 TlvPointerSection()
|
|
147 : NonLazyPointerSectionBase(segment_names::data,
|
|
148 section_names::threadPtrs) {}
|
|
149 };
|
|
150
|
|
151 struct Location {
|
|
152 const InputSection *isec;
|
|
153 uint64_t offset;
|
|
154
|
|
155 Location(const InputSection *isec, uint64_t offset)
|
|
156 : isec(isec), offset(offset) {}
|
|
157 uint64_t getVA() const { return isec->getVA() + offset; }
|
|
158 };
|
|
159
|
|
160 // Stores rebase opcodes, which tell dyld where absolute addresses have been
|
|
161 // encoded in the binary. If the binary is not loaded at its preferred address,
|
|
162 // dyld has to rebase these addresses by adding an offset to them.
|
|
163 class RebaseSection : public LinkEditSection {
|
|
164 public:
|
|
165 RebaseSection();
|
|
166 void finalizeContents() override;
|
|
167 uint64_t getRawSize() const override { return contents.size(); }
|
|
168 bool isNeeded() const override { return !locations.empty(); }
|
|
169 void writeTo(uint8_t *buf) const override;
|
|
170
|
|
171 void addEntry(const InputSection *isec, uint64_t offset) {
|
|
172 if (config->isPic)
|
|
173 locations.push_back({isec, offset});
|
|
174 }
|
173
|
175
|
|
176 private:
|
207
|
177 std::vector<Location> locations;
|
|
178 SmallVector<char, 128> contents;
|
|
179 };
|
|
180
|
|
181 struct BindingEntry {
|
|
182 const DylibSymbol *dysym;
|
|
183 int64_t addend;
|
|
184 Location target;
|
|
185 BindingEntry(const DylibSymbol *dysym, int64_t addend, Location target)
|
|
186 : dysym(dysym), addend(addend), target(std::move(target)) {}
|
173
|
187 };
|
|
188
|
|
189 // Stores bind opcodes for telling dyld which symbols to load non-lazily.
|
207
|
190 class BindingSection : public LinkEditSection {
|
173
|
191 public:
|
|
192 BindingSection();
|
207
|
193 void finalizeContents() override;
|
|
194 uint64_t getRawSize() const override { return contents.size(); }
|
|
195 bool isNeeded() const override { return !bindings.empty(); }
|
173
|
196 void writeTo(uint8_t *buf) const override;
|
|
197
|
207
|
198 void addEntry(const DylibSymbol *dysym, const InputSection *isec,
|
|
199 uint64_t offset, int64_t addend = 0) {
|
|
200 bindings.emplace_back(dysym, addend, Location(isec, offset));
|
|
201 }
|
|
202
|
|
203 private:
|
|
204 std::vector<BindingEntry> bindings;
|
|
205 SmallVector<char, 128> contents;
|
|
206 };
|
|
207
|
|
208 struct WeakBindingEntry {
|
|
209 const Symbol *symbol;
|
|
210 int64_t addend;
|
|
211 Location target;
|
|
212 WeakBindingEntry(const Symbol *symbol, int64_t addend, Location target)
|
|
213 : symbol(symbol), addend(addend), target(std::move(target)) {}
|
|
214 };
|
|
215
|
|
216 // Stores bind opcodes for telling dyld which weak symbols need coalescing.
|
|
217 // There are two types of entries in this section:
|
|
218 //
|
|
219 // 1) Non-weak definitions: This is a symbol definition that weak symbols in
|
|
220 // other dylibs should coalesce to.
|
|
221 //
|
|
222 // 2) Weak bindings: These tell dyld that a given symbol reference should
|
|
223 // coalesce to a non-weak definition if one is found. Note that unlike the
|
|
224 // entries in the BindingSection, the bindings here only refer to these
|
|
225 // symbols by name, but do not specify which dylib to load them from.
|
|
226 class WeakBindingSection : public LinkEditSection {
|
|
227 public:
|
|
228 WeakBindingSection();
|
|
229 void finalizeContents() override;
|
|
230 uint64_t getRawSize() const override { return contents.size(); }
|
|
231 bool isNeeded() const override {
|
|
232 return !bindings.empty() || !definitions.empty();
|
|
233 }
|
|
234
|
|
235 void writeTo(uint8_t *buf) const override;
|
|
236
|
|
237 void addEntry(const Symbol *symbol, const InputSection *isec, uint64_t offset,
|
|
238 int64_t addend = 0) {
|
|
239 bindings.emplace_back(symbol, addend, Location(isec, offset));
|
|
240 }
|
|
241
|
|
242 bool hasEntry() const { return !bindings.empty(); }
|
|
243
|
|
244 void addNonWeakDefinition(const Defined *defined) {
|
|
245 definitions.emplace_back(defined);
|
|
246 }
|
|
247
|
|
248 bool hasNonWeakDefinition() const { return !definitions.empty(); }
|
|
249
|
|
250 private:
|
|
251 std::vector<WeakBindingEntry> bindings;
|
|
252 std::vector<const Defined *> definitions;
|
173
|
253 SmallVector<char, 128> contents;
|
|
254 };
|
|
255
|
|
256 // The following sections implement lazy symbol binding -- very similar to the
|
|
257 // PLT mechanism in ELF.
|
|
258 //
|
207
|
259 // ELF's .plt section is broken up into two sections in Mach-O: StubsSection
|
|
260 // and StubHelperSection. Calls to functions in dylibs will end up calling into
|
173
|
261 // StubsSection, which contains indirect jumps to addresses stored in the
|
|
262 // LazyPointerSection (the counterpart to ELF's .plt.got).
|
|
263 //
|
207
|
264 // We will first describe how non-weak symbols are handled.
|
|
265 //
|
|
266 // At program start, the LazyPointerSection contains addresses that point into
|
|
267 // one of the entry points in the middle of the StubHelperSection. The code in
|
173
|
268 // StubHelperSection will push on the stack an offset into the
|
|
269 // LazyBindingSection. The push is followed by a jump to the beginning of the
|
|
270 // StubHelperSection (similar to PLT0), which then calls into dyld_stub_binder.
|
|
271 // dyld_stub_binder is a non-lazily-bound symbol, so this call looks it up in
|
|
272 // the GOT.
|
|
273 //
|
|
274 // The stub binder will look up the bind opcodes in the LazyBindingSection at
|
207
|
275 // the given offset. The bind opcodes will tell the binder to update the
|
|
276 // address in the LazyPointerSection to point to the symbol, so that subsequent
|
|
277 // calls don't have to redo the symbol resolution. The binder will then jump to
|
|
278 // the resolved symbol.
|
|
279 //
|
|
280 // With weak symbols, the situation is slightly different. Since there is no
|
|
281 // "weak lazy" lookup, function calls to weak symbols are always non-lazily
|
|
282 // bound. We emit both regular non-lazy bindings as well as weak bindings, in
|
|
283 // order that the weak bindings may overwrite the non-lazy bindings if an
|
|
284 // appropriate symbol is found at runtime. However, the bound addresses will
|
|
285 // still be written (non-lazily) into the LazyPointerSection.
|
173
|
286
|
|
287 class StubsSection : public SyntheticSection {
|
|
288 public:
|
|
289 StubsSection();
|
207
|
290 uint64_t getSize() const override;
|
173
|
291 bool isNeeded() const override { return !entries.empty(); }
|
207
|
292 void finalize() override;
|
173
|
293 void writeTo(uint8_t *buf) const override;
|
207
|
294 const llvm::SetVector<Symbol *> &getEntries() const { return entries; }
|
|
295 // Returns whether the symbol was added. Note that every stubs entry will
|
|
296 // have a corresponding entry in the LazyPointerSection.
|
|
297 bool addEntry(Symbol *);
|
|
298 uint64_t getVA(uint32_t stubsIndex) const {
|
|
299 // ConcatOutputSection::finalize() can seek the address of a
|
|
300 // stub before its address is assigned. Before __stubs is
|
|
301 // finalized, return a contrived out-of-range address.
|
|
302 return isFinal ? addr + stubsIndex * target->stubSize
|
|
303 : TargetInfo::outOfRangeVA;
|
|
304 }
|
173
|
305
|
207
|
306 bool isFinal = false; // is address assigned?
|
173
|
307
|
|
308 private:
|
207
|
309 llvm::SetVector<Symbol *> entries;
|
173
|
310 };
|
|
311
|
|
312 class StubHelperSection : public SyntheticSection {
|
|
313 public:
|
|
314 StubHelperSection();
|
207
|
315 uint64_t getSize() const override;
|
173
|
316 bool isNeeded() const override;
|
|
317 void writeTo(uint8_t *buf) const override;
|
|
318
|
|
319 void setup();
|
|
320
|
|
321 DylibSymbol *stubBinder = nullptr;
|
207
|
322 Defined *dyldPrivate = nullptr;
|
173
|
323 };
|
|
324
|
|
325 // This section contains space for just a single word, and will be used by dyld
|
|
326 // to cache an address to the image loader it uses. Note that unlike the other
|
|
327 // synthetic sections, which are OutputSections, the ImageLoaderCacheSection is
|
|
328 // an InputSection that gets merged into the __data OutputSection.
|
|
329 class ImageLoaderCacheSection : public InputSection {
|
|
330 public:
|
|
331 ImageLoaderCacheSection();
|
207
|
332 uint64_t getSize() const override { return target->wordSize; }
|
173
|
333 };
|
|
334
|
207
|
335 // Note that this section may also be targeted by non-lazy bindings. In
|
|
336 // particular, this happens when branch relocations target weak symbols.
|
173
|
337 class LazyPointerSection : public SyntheticSection {
|
|
338 public:
|
|
339 LazyPointerSection();
|
207
|
340 uint64_t getSize() const override;
|
173
|
341 bool isNeeded() const override;
|
|
342 void writeTo(uint8_t *buf) const override;
|
|
343 };
|
|
344
|
207
|
345 class LazyBindingSection : public LinkEditSection {
|
173
|
346 public:
|
|
347 LazyBindingSection();
|
207
|
348 void finalizeContents() override;
|
|
349 uint64_t getRawSize() const override { return contents.size(); }
|
|
350 bool isNeeded() const override { return !entries.empty(); }
|
173
|
351 void writeTo(uint8_t *buf) const override;
|
207
|
352 // Note that every entry here will by referenced by a corresponding entry in
|
|
353 // the StubHelperSection.
|
|
354 void addEntry(DylibSymbol *dysym);
|
|
355 const llvm::SetVector<DylibSymbol *> &getEntries() const { return entries; }
|
173
|
356
|
|
357 private:
|
207
|
358 uint32_t encode(const DylibSymbol &);
|
|
359
|
|
360 llvm::SetVector<DylibSymbol *> entries;
|
173
|
361 SmallVector<char, 128> contents;
|
|
362 llvm::raw_svector_ostream os{contents};
|
|
363 };
|
|
364
|
|
365 // Stores a trie that describes the set of exported symbols.
|
207
|
366 class ExportSection : public LinkEditSection {
|
173
|
367 public:
|
|
368 ExportSection();
|
207
|
369 void finalizeContents() override;
|
|
370 uint64_t getRawSize() const override { return size; }
|
173
|
371 void writeTo(uint8_t *buf) const override;
|
|
372
|
207
|
373 bool hasWeakSymbol = false;
|
|
374
|
173
|
375 private:
|
|
376 TrieBuilder trieBuilder;
|
|
377 size_t size = 0;
|
|
378 };
|
|
379
|
207
|
380 class FunctionStartsSection : public LinkEditSection {
|
|
381 public:
|
|
382 FunctionStartsSection();
|
|
383 void finalizeContents() override;
|
|
384 uint64_t getRawSize() const override { return contents.size(); }
|
|
385 void writeTo(uint8_t *buf) const override;
|
|
386
|
|
387 private:
|
|
388 SmallVector<char, 128> contents;
|
|
389 };
|
|
390
|
173
|
391 // Stores the strings referenced by the symbol table.
|
207
|
392 class StringTableSection : public LinkEditSection {
|
173
|
393 public:
|
|
394 StringTableSection();
|
|
395 // Returns the start offset of the added string.
|
|
396 uint32_t addString(StringRef);
|
207
|
397 uint64_t getRawSize() const override { return size; }
|
173
|
398 void writeTo(uint8_t *buf) const override;
|
|
399
|
207
|
400 static constexpr size_t emptyStringIndex = 1;
|
|
401
|
173
|
402 private:
|
207
|
403 // ld64 emits string tables which start with a space and a zero byte. We
|
|
404 // match its behavior here since some tools depend on it.
|
|
405 // Consequently, the empty string will be at index 1, not zero.
|
|
406 std::vector<StringRef> strings{" "};
|
|
407 size_t size = 2;
|
173
|
408 };
|
|
409
|
|
410 struct SymtabEntry {
|
|
411 Symbol *sym;
|
|
412 size_t strx;
|
|
413 };
|
|
414
|
207
|
415 struct StabsEntry {
|
|
416 uint8_t type = 0;
|
|
417 uint32_t strx = StringTableSection::emptyStringIndex;
|
|
418 uint8_t sect = 0;
|
|
419 uint16_t desc = 0;
|
|
420 uint64_t value = 0;
|
|
421
|
|
422 StabsEntry() = default;
|
|
423 explicit StabsEntry(uint8_t type) : type(type) {}
|
|
424 };
|
|
425
|
|
426 // Symbols of the same type must be laid out contiguously: we choose to emit
|
|
427 // all local symbols first, then external symbols, and finally undefined
|
|
428 // symbols. For each symbol type, the LC_DYSYMTAB load command will record the
|
|
429 // range (start index and total number) of those symbols in the symbol table.
|
|
430 class SymtabSection : public LinkEditSection {
|
173
|
431 public:
|
207
|
432 void finalizeContents() override;
|
|
433 uint32_t getNumSymbols() const;
|
|
434 uint32_t getNumLocalSymbols() const {
|
|
435 return stabs.size() + localSymbols.size();
|
|
436 }
|
|
437 uint32_t getNumExternalSymbols() const { return externalSymbols.size(); }
|
|
438 uint32_t getNumUndefinedSymbols() const { return undefinedSymbols.size(); }
|
|
439
|
|
440 private:
|
|
441 void emitBeginSourceStab(llvm::DWARFUnit *compileUnit);
|
|
442 void emitEndSourceStab();
|
|
443 void emitObjectFileStab(ObjFile *);
|
|
444 void emitEndFunStab(Defined *);
|
|
445 void emitStabs();
|
|
446
|
|
447 protected:
|
173
|
448 SymtabSection(StringTableSection &);
|
207
|
449
|
|
450 StringTableSection &stringTableSection;
|
|
451 // STABS symbols are always local symbols, but we represent them with special
|
|
452 // entries because they may use fields like n_sect and n_desc differently.
|
|
453 std::vector<StabsEntry> stabs;
|
|
454 std::vector<SymtabEntry> localSymbols;
|
|
455 std::vector<SymtabEntry> externalSymbols;
|
|
456 std::vector<SymtabEntry> undefinedSymbols;
|
|
457 };
|
|
458
|
|
459 template <class LP> SymtabSection *makeSymtabSection(StringTableSection &);
|
|
460
|
|
461 // The indirect symbol table is a list of 32-bit integers that serve as indices
|
|
462 // into the (actual) symbol table. The indirect symbol table is a
|
|
463 // concatenation of several sub-arrays of indices, each sub-array belonging to
|
|
464 // a separate section. The starting offset of each sub-array is stored in the
|
|
465 // reserved1 header field of the respective section.
|
|
466 //
|
|
467 // These sub-arrays provide symbol information for sections that store
|
|
468 // contiguous sequences of symbol references. These references can be pointers
|
|
469 // (e.g. those in the GOT and TLVP sections) or assembly sequences (e.g.
|
|
470 // function stubs).
|
|
471 class IndirectSymtabSection : public LinkEditSection {
|
|
472 public:
|
|
473 IndirectSymtabSection();
|
|
474 void finalizeContents() override;
|
|
475 uint32_t getNumSymbols() const;
|
|
476 uint64_t getRawSize() const override {
|
|
477 return getNumSymbols() * sizeof(uint32_t);
|
|
478 }
|
|
479 bool isNeeded() const override;
|
|
480 void writeTo(uint8_t *buf) const override;
|
|
481 };
|
|
482
|
|
483 // The code signature comes at the very end of the linked output file.
|
|
484 class CodeSignatureSection : public LinkEditSection {
|
|
485 public:
|
|
486 static constexpr uint8_t blockSizeShift = 12;
|
|
487 static constexpr size_t blockSize = (1 << blockSizeShift); // 4 KiB
|
|
488 static constexpr size_t hashSize = 256 / 8;
|
|
489 static constexpr size_t blobHeadersSize = llvm::alignTo<8>(
|
|
490 sizeof(llvm::MachO::CS_SuperBlob) + sizeof(llvm::MachO::CS_BlobIndex));
|
|
491 static constexpr uint32_t fixedHeadersSize =
|
|
492 blobHeadersSize + sizeof(llvm::MachO::CS_CodeDirectory);
|
|
493
|
|
494 uint32_t fileNamePad = 0;
|
|
495 uint32_t allHeadersSize = 0;
|
|
496 StringRef fileName;
|
|
497
|
|
498 CodeSignatureSection();
|
|
499 uint64_t getRawSize() const override;
|
|
500 bool isNeeded() const override { return true; }
|
|
501 void writeTo(uint8_t *buf) const override;
|
|
502 uint32_t getBlockCount() const;
|
|
503 void writeHashes(uint8_t *buf) const;
|
|
504 };
|
|
505
|
|
506 class BitcodeBundleSection : public SyntheticSection {
|
|
507 public:
|
|
508 BitcodeBundleSection();
|
|
509 uint64_t getSize() const override { return xarSize; }
|
|
510 void finalize() override;
|
173
|
511 void writeTo(uint8_t *buf) const override;
|
|
512
|
|
513 private:
|
207
|
514 llvm::SmallString<261> xarPath;
|
|
515 uint64_t xarSize;
|
173
|
516 };
|
|
517
|
|
518 struct InStruct {
|
207
|
519 MachHeaderSection *header = nullptr;
|
|
520 RebaseSection *rebase = nullptr;
|
|
521 BindingSection *binding = nullptr;
|
|
522 WeakBindingSection *weakBinding = nullptr;
|
|
523 LazyBindingSection *lazyBinding = nullptr;
|
|
524 ExportSection *exports = nullptr;
|
173
|
525 GotSection *got = nullptr;
|
207
|
526 TlvPointerSection *tlvPointers = nullptr;
|
173
|
527 LazyPointerSection *lazyPointers = nullptr;
|
|
528 StubsSection *stubs = nullptr;
|
|
529 StubHelperSection *stubHelper = nullptr;
|
|
530 ImageLoaderCacheSection *imageLoaderCache = nullptr;
|
207
|
531 UnwindInfoSection *unwindInfo = nullptr;
|
173
|
532 };
|
|
533
|
|
534 extern InStruct in;
|
207
|
535 extern std::vector<SyntheticSection *> syntheticSections;
|
|
536
|
|
537 void createSyntheticSymbols();
|
173
|
538
|
|
539 } // namespace macho
|
|
540 } // namespace lld
|
|
541
|
|
542 #endif
|