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
12#include "Config.h"
13#include "ExportTrie.h"
14#include "InputSection.h"
15#include "OutputSection.h"
16#include "OutputSegment.h"
17#include "Target.h"
18#include "Writer.h"
19
20#include "llvm/ADT/DenseMap.h"
21#include "llvm/ADT/Hashing.h"
22#include "llvm/ADT/Optional.h"
23#include "llvm/ADT/SetVector.h"
24#include "llvm/MC/StringTableBuilder.h"
25#include "llvm/Support/MathExtras.h"
26#include "llvm/Support/raw_ostream.h"
27
28#include <unordered_map>
29
30namespace llvm {
31class DWARFUnit;
32} // namespace llvm
33
34namespace lld::macho {
35
36class Defined;
37class DylibSymbol;
38class LoadCommand;
39class ObjFile;
40class UnwindInfoSection;
41
42class SyntheticSection : public OutputSection {
43public:
44 SyntheticSection(const char *segname, const char *name);
45 virtual ~SyntheticSection() = default;
46
47 static bool classof(const OutputSection *sec) {
48 return sec->kind() == SyntheticKind;
49 }
50
51 StringRef segname;
52 // This fake InputSection makes it easier for us to write code that applies
53 // generically to both user inputs and synthetics.
54 InputSection *isec;
55};
56
57// All sections in __LINKEDIT should inherit from this.
58class LinkEditSection : public SyntheticSection {
59public:
60 LinkEditSection(const char *segname, const char *name)
61 : SyntheticSection(segname, name) {
62 align = target->wordSize;
63 }
64
65 // Implementations of this method can assume that the regular (non-__LINKEDIT)
66 // sections already have their addresses assigned.
67 virtual void finalizeContents() {}
68
69 // Sections in __LINKEDIT are special: their offsets are recorded in the
70 // load commands like LC_DYLD_INFO_ONLY and LC_SYMTAB, instead of in section
71 // headers.
72 bool isHidden() const final { return true; }
73
74 virtual uint64_t getRawSize() const = 0;
75
76 // codesign (or more specifically libstuff) checks that each section in
77 // __LINKEDIT ends where the next one starts -- no gaps are permitted. We
78 // therefore align every section's start and end points to WordSize.
79 //
80 // NOTE: This assumes that the extra bytes required for alignment can be
81 // zero-valued bytes.
82 uint64_t getSize() const final { return llvm::alignTo(getRawSize(), align); }
83};
84
85// The header of the Mach-O file, which must have a file offset of zero.
86class MachHeaderSection final : public SyntheticSection {
87public:
88 MachHeaderSection();
89 bool isHidden() const override { return true; }
90 uint64_t getSize() const override;
91 void writeTo(uint8_t *buf) const override;
92
93 void addLoadCommand(LoadCommand *);
94
95protected:
96 std::vector<LoadCommand *> loadCommands;
97 uint32_t sizeOfCmds = 0;
98};
99
100// A hidden section that exists solely for the purpose of creating the
101// __PAGEZERO segment, which is used to catch null pointer dereferences.
102class PageZeroSection final : public SyntheticSection {
103public:
104 PageZeroSection();
105 bool isHidden() const override { return true; }
106 bool isNeeded() const override { return target->pageZeroSize != 0; }
107 uint64_t getSize() const override { return target->pageZeroSize; }
108 uint64_t getFileSize() const override { return 0; }
109 void writeTo(uint8_t *buf) const override {}
110};
111
112// This is the base class for the GOT and TLVPointer sections, which are nearly
113// functionally identical -- they will both be populated by dyld with addresses
114// to non-lazily-loaded dylib symbols. The main difference is that the
115// TLVPointerSection stores references to thread-local variables.
116class NonLazyPointerSectionBase : public SyntheticSection {
117public:
118 NonLazyPointerSectionBase(const char *segname, const char *name);
119 const llvm::SetVector<const Symbol *> &getEntries() const { return entries; }
120 bool isNeeded() const override { return !entries.empty(); }
121 uint64_t getSize() const override {
122 return entries.size() * target->wordSize;
123 }
124 void writeTo(uint8_t *buf) const override;
125 void addEntry(Symbol *sym);
126 uint64_t getVA(uint32_t gotIndex) const {
127 return addr + gotIndex * target->wordSize;
128 }
129
130private:
131 llvm::SetVector<const Symbol *> entries;
132};
133
134class GotSection final : public NonLazyPointerSectionBase {
135public:
136 GotSection();
137};
138
139class TlvPointerSection final : public NonLazyPointerSectionBase {
140public:
141 TlvPointerSection();
142};
143
144struct Location {
145 const InputSection *isec;
146 uint64_t offset;
147
148 Location(const InputSection *isec, uint64_t offset)
149 : isec(isec), offset(offset) {}
150 uint64_t getVA() const { return isec->getVA(offset); }
151};
152
153// Stores rebase opcodes, which tell dyld where absolute addresses have been
154// encoded in the binary. If the binary is not loaded at its preferred address,
155// dyld has to rebase these addresses by adding an offset to them.
156class RebaseSection final : public LinkEditSection {
157public:
158 RebaseSection();
159 void finalizeContents() override;
160 uint64_t getRawSize() const override { return contents.size(); }
161 bool isNeeded() const override { return !locations.empty(); }
162 void writeTo(uint8_t *buf) const override;
163
164 void addEntry(const InputSection *isec, uint64_t offset) {
165 if (config->isPic)
166 locations.push_back({isec, offset});
167 }
168
169private:
170 std::vector<Location> locations;
171 SmallVector<char, 128> contents;
172};
173
174struct BindingEntry {
175 int64_t addend;
176 Location target;
177 BindingEntry(int64_t addend, Location target)
178 : addend(addend), target(std::move(target)) {}
179};
180
181template <class Sym>
182using BindingsMap = llvm::DenseMap<Sym, std::vector<BindingEntry>>;
183
184// Stores bind opcodes for telling dyld which symbols to load non-lazily.
185class BindingSection final : public LinkEditSection {
186public:
187 BindingSection();
188 void finalizeContents() override;
189 uint64_t getRawSize() const override { return contents.size(); }
190 bool isNeeded() const override { return !bindingsMap.empty(); }
191 void writeTo(uint8_t *buf) const override;
192
193 void addEntry(const Symbol *dysym, const InputSection *isec, uint64_t offset,
194 int64_t addend = 0) {
195 bindingsMap[dysym].emplace_back(addend, Location(isec, offset));
196 }
197
198private:
199 BindingsMap<const Symbol *> bindingsMap;
200 SmallVector<char, 128> contents;
201};
202
203// Stores bind opcodes for telling dyld which weak symbols need coalescing.
204// There are two types of entries in this section:
205//
206// 1) Non-weak definitions: This is a symbol definition that weak symbols in
207// other dylibs should coalesce to.
208//
209// 2) Weak bindings: These tell dyld that a given symbol reference should
210// coalesce to a non-weak definition if one is found. Note that unlike the
211// entries in the BindingSection, the bindings here only refer to these
212// symbols by name, but do not specify which dylib to load them from.
213class WeakBindingSection final : public LinkEditSection {
214public:
215 WeakBindingSection();
216 void finalizeContents() override;
217 uint64_t getRawSize() const override { return contents.size(); }
218 bool isNeeded() const override {
219 return !bindingsMap.empty() || !definitions.empty();
220 }
221
222 void writeTo(uint8_t *buf) const override;
223
224 void addEntry(const Symbol *symbol, const InputSection *isec, uint64_t offset,
225 int64_t addend = 0) {
226 bindingsMap[symbol].emplace_back(addend, Location(isec, offset));
227 }
228
229 bool hasEntry() const { return !bindingsMap.empty(); }
230
231 void addNonWeakDefinition(const Defined *defined) {
232 definitions.emplace_back(defined);
233 }
234
235 bool hasNonWeakDefinition() const { return !definitions.empty(); }
236
237private:
238 BindingsMap<const Symbol *> bindingsMap;
239 std::vector<const Defined *> definitions;
240 SmallVector<char, 128> contents;
241};
242
243// The following sections implement lazy symbol binding -- very similar to the
244// PLT mechanism in ELF.
245//
246// ELF's .plt section is broken up into two sections in Mach-O: StubsSection
247// and StubHelperSection. Calls to functions in dylibs will end up calling into
248// StubsSection, which contains indirect jumps to addresses stored in the
249// LazyPointerSection (the counterpart to ELF's .plt.got).
250//
251// We will first describe how non-weak symbols are handled.
252//
253// At program start, the LazyPointerSection contains addresses that point into
254// one of the entry points in the middle of the StubHelperSection. The code in
255// StubHelperSection will push on the stack an offset into the
256// LazyBindingSection. The push is followed by a jump to the beginning of the
257// StubHelperSection (similar to PLT0), which then calls into dyld_stub_binder.
258// dyld_stub_binder is a non-lazily-bound symbol, so this call looks it up in
259// the GOT.
260//
261// The stub binder will look up the bind opcodes in the LazyBindingSection at
262// the given offset. The bind opcodes will tell the binder to update the
263// address in the LazyPointerSection to point to the symbol, so that subsequent
264// calls don't have to redo the symbol resolution. The binder will then jump to
265// the resolved symbol.
266//
267// With weak symbols, the situation is slightly different. Since there is no
268// "weak lazy" lookup, function calls to weak symbols are always non-lazily
269// bound. We emit both regular non-lazy bindings as well as weak bindings, in
270// order that the weak bindings may overwrite the non-lazy bindings if an
271// appropriate symbol is found at runtime. However, the bound addresses will
272// still be written (non-lazily) into the LazyPointerSection.
273
274class StubsSection final : public SyntheticSection {
275public:
276 StubsSection();
277 uint64_t getSize() const override;
278 bool isNeeded() const override { return !entries.empty(); }
279 void finalize() override;
280 void writeTo(uint8_t *buf) const override;
281 const llvm::SetVector<Symbol *> &getEntries() const { return entries; }
282 // Returns whether the symbol was added. Note that every stubs entry will
283 // have a corresponding entry in the LazyPointerSection.
284 bool addEntry(Symbol *);
285 uint64_t getVA(uint32_t stubsIndex) const {
286 assert(isFinal || target->usesThunks());
287 // ConcatOutputSection::finalize() can seek the address of a
288 // stub before its address is assigned. Before __stubs is
289 // finalized, return a contrived out-of-range address.
290 return isFinal ? addr + stubsIndex * target->stubSize
291 : TargetInfo::outOfRangeVA;
292 }
293
294 bool isFinal = false; // is address assigned?
295
296private:
297 llvm::SetVector<Symbol *> entries;
298};
299
300class StubHelperSection final : public SyntheticSection {
301public:
302 StubHelperSection();
303 uint64_t getSize() const override;
304 bool isNeeded() const override;
305 void writeTo(uint8_t *buf) const override;
306
307 void setup();
308
309 DylibSymbol *stubBinder = nullptr;
310 Defined *dyldPrivate = nullptr;
311};
312
313// Objective-C stubs are hoisted objc_msgSend calls per selector called in the
314// program. Apple Clang produces undefined symbols to each stub, such as
315// '_objc_msgSend$foo', which are then synthesized by the linker. The stubs
316// load the particular selector 'foo' from __objc_selrefs, setting it to the
317// first argument of the objc_msgSend call, and then jumps to objc_msgSend. The
318// actual stub contents are mirrored from ld64.
319class ObjCStubsSection final : public SyntheticSection {
320public:
321 ObjCStubsSection();
322 void addEntry(Symbol *sym);
323 uint64_t getSize() const override;
324 bool isNeeded() const override { return !symbols.empty(); }
325 void finalize() override { isec->isFinal = true; }
326 void writeTo(uint8_t *buf) const override;
327 void setup();
328
329 static constexpr llvm::StringLiteral symbolPrefix = "_objc_msgSend$";
330
331private:
332 std::vector<Defined *> symbols;
333 std::vector<uint32_t> offsets;
334 int objcMsgSendGotIndex = 0;
335};
336
337// Note that this section may also be targeted by non-lazy bindings. In
338// particular, this happens when branch relocations target weak symbols.
339class LazyPointerSection final : public SyntheticSection {
340public:
341 LazyPointerSection();
342 uint64_t getSize() const override;
343 bool isNeeded() const override;
344 void writeTo(uint8_t *buf) const override;
345};
346
347class LazyBindingSection final : public LinkEditSection {
348public:
349 LazyBindingSection();
350 void finalizeContents() override;
351 uint64_t getRawSize() const override { return contents.size(); }
352 bool isNeeded() const override { return !entries.empty(); }
353 void writeTo(uint8_t *buf) const override;
354 // Note that every entry here will by referenced by a corresponding entry in
355 // the StubHelperSection.
356 void addEntry(Symbol *dysym);
357 const llvm::SetVector<Symbol *> &getEntries() const { return entries; }
358
359private:
360 uint32_t encode(const Symbol &);
361
362 llvm::SetVector<Symbol *> entries;
363 SmallVector<char, 128> contents;
364 llvm::raw_svector_ostream os{contents};
365};
366
367// Stores a trie that describes the set of exported symbols.
368class ExportSection final : public LinkEditSection {
369public:
370 ExportSection();
371 void finalizeContents() override;
372 uint64_t getRawSize() const override { return size; }
373 bool isNeeded() const override { return size; }
374 void writeTo(uint8_t *buf) const override;
375
376 bool hasWeakSymbol = false;
377
378private:
379 TrieBuilder trieBuilder;
380 size_t size = 0;
381};
382
383// Stores 'data in code' entries that describe the locations of
384// data regions inside code sections.
385class DataInCodeSection final : public LinkEditSection {
386public:
387 DataInCodeSection();
388 void finalizeContents() override;
389 uint64_t getRawSize() const override {
390 return sizeof(llvm::MachO::data_in_code_entry) * entries.size();
391 }
392 void writeTo(uint8_t *buf) const override;
393
394private:
395 std::vector<llvm::MachO::data_in_code_entry> entries;
396};
397
398// Stores ULEB128 delta encoded addresses of functions.
399class FunctionStartsSection final : public LinkEditSection {
400public:
401 FunctionStartsSection();
402 void finalizeContents() override;
403 uint64_t getRawSize() const override { return contents.size(); }
404 void writeTo(uint8_t *buf) const override;
405
406private:
407 SmallVector<char, 128> contents;
408};
409
410// Stores the strings referenced by the symbol table.
411class StringTableSection final : public LinkEditSection {
412public:
413 StringTableSection();
414 // Returns the start offset of the added string.
415 uint32_t addString(StringRef);
416 uint64_t getRawSize() const override { return size; }
417 void writeTo(uint8_t *buf) const override;
418
419 static constexpr size_t emptyStringIndex = 1;
420
421private:
422 // ld64 emits string tables which start with a space and a zero byte. We
423 // match its behavior here since some tools depend on it.
424 // Consequently, the empty string will be at index 1, not zero.
425 std::vector<StringRef> strings{" "};
426 size_t size = 2;
427};
428
429struct SymtabEntry {
430 Symbol *sym;
431 size_t strx;
432};
433
434struct StabsEntry {
435 uint8_t type = 0;
436 uint32_t strx = StringTableSection::emptyStringIndex;
437 uint8_t sect = 0;
438 uint16_t desc = 0;
439 uint64_t value = 0;
440
441 StabsEntry() = default;
442 explicit StabsEntry(uint8_t type) : type(type) {}
443};
444
445// Symbols of the same type must be laid out contiguously: we choose to emit
446// all local symbols first, then external symbols, and finally undefined
447// symbols. For each symbol type, the LC_DYSYMTAB load command will record the
448// range (start index and total number) of those symbols in the symbol table.
449class SymtabSection : public LinkEditSection {
450public:
451 void finalizeContents() override;
452 uint32_t getNumSymbols() const;
453 uint32_t getNumLocalSymbols() const {
454 return stabs.size() + localSymbols.size();
455 }
456 uint32_t getNumExternalSymbols() const { return externalSymbols.size(); }
457 uint32_t getNumUndefinedSymbols() const { return undefinedSymbols.size(); }
458
459private:
460 void emitBeginSourceStab(StringRef);
461 void emitEndSourceStab();
462 void emitObjectFileStab(ObjFile *);
463 void emitEndFunStab(Defined *);
464 void emitStabs();
465
466protected:
467 SymtabSection(StringTableSection &);
468
469 StringTableSection &stringTableSection;
470 // STABS symbols are always local symbols, but we represent them with special
471 // entries because they may use fields like n_sect and n_desc differently.
472 std::vector<StabsEntry> stabs;
473 std::vector<SymtabEntry> localSymbols;
474 std::vector<SymtabEntry> externalSymbols;
475 std::vector<SymtabEntry> undefinedSymbols;
476};
477
478template <class LP> SymtabSection *makeSymtabSection(StringTableSection &);
479
480// The indirect symbol table is a list of 32-bit integers that serve as indices
481// into the (actual) symbol table. The indirect symbol table is a
482// concatenation of several sub-arrays of indices, each sub-array belonging to
483// a separate section. The starting offset of each sub-array is stored in the
484// reserved1 header field of the respective section.
485//
486// These sub-arrays provide symbol information for sections that store
487// contiguous sequences of symbol references. These references can be pointers
488// (e.g. those in the GOT and TLVP sections) or assembly sequences (e.g.
489// function stubs).
490class IndirectSymtabSection final : public LinkEditSection {
491public:
492 IndirectSymtabSection();
493 void finalizeContents() override;
494 uint32_t getNumSymbols() const;
495 uint64_t getRawSize() const override {
496 return getNumSymbols() * sizeof(uint32_t);
497 }
498 bool isNeeded() const override;
499 void writeTo(uint8_t *buf) const override;
500};
501
502// The code signature comes at the very end of the linked output file.
503class CodeSignatureSection final : public LinkEditSection {
504public:
505 // NOTE: These values are duplicated in llvm-objcopy's MachO/Object.h file
506 // and any changes here, should be repeated there.
507 static constexpr uint8_t blockSizeShift = 12;
508 static constexpr size_t blockSize = (1 << blockSizeShift); // 4 KiB
509 static constexpr size_t hashSize = 256 / 8;
510 static constexpr size_t blobHeadersSize = llvm::alignTo<8>(
511 sizeof(llvm::MachO::CS_SuperBlob) + sizeof(llvm::MachO::CS_BlobIndex));
512 static constexpr uint32_t fixedHeadersSize =
513 blobHeadersSize + sizeof(llvm::MachO::CS_CodeDirectory);
514
515 uint32_t fileNamePad = 0;
516 uint32_t allHeadersSize = 0;
517 StringRef fileName;
518
519 CodeSignatureSection();
520 uint64_t getRawSize() const override;
521 bool isNeeded() const override { return true; }
522 void writeTo(uint8_t *buf) const override;
523 uint32_t getBlockCount() const;
524 void writeHashes(uint8_t *buf) const;
525};
526
527class BitcodeBundleSection final : public SyntheticSection {
528public:
529 BitcodeBundleSection();
530 uint64_t getSize() const override { return xarSize; }
531 void finalize() override;
532 void writeTo(uint8_t *buf) const override;
533
534private:
535 llvm::SmallString<261> xarPath;
536 uint64_t xarSize;
537};
538
539class CStringSection : public SyntheticSection {
540public:
541 CStringSection(const char *name);
542 void addInput(CStringInputSection *);
543 uint64_t getSize() const override { return size; }
544 virtual void finalizeContents();
545 bool isNeeded() const override { return !inputs.empty(); }
546 void writeTo(uint8_t *buf) const override;
547
548 std::vector<CStringInputSection *> inputs;
549
550private:
551 uint64_t size;
552};
553
554class DeduplicatedCStringSection final : public CStringSection {
555public:
556 DeduplicatedCStringSection(const char *name) : CStringSection(name){};
557 uint64_t getSize() const override { return size; }
558 void finalizeContents() override;
559 void writeTo(uint8_t *buf) const override;
560
561 struct StringOffset {
562 uint8_t trailingZeros;
563 uint64_t outSecOff = UINT64_MAX;
564
565 explicit StringOffset(uint8_t zeros) : trailingZeros(zeros) {}
566 };
567
568 StringOffset getStringOffset(StringRef str) const;
569
570private:
571 llvm::DenseMap<llvm::CachedHashStringRef, StringOffset> stringOffsetMap;
572 size_t size = 0;
573};
574
575/*
576 * This section contains deduplicated literal values. The 16-byte values are
577 * laid out first, followed by the 8- and then the 4-byte ones.
578 */
579class WordLiteralSection final : public SyntheticSection {
580public:
581 using UInt128 = std::pair<uint64_t, uint64_t>;
582 // I don't think the standard guarantees the size of a pair, so let's make
583 // sure it's exact -- that way we can construct it via `mmap`.
584 static_assert(sizeof(UInt128) == 16, "");
585
586 WordLiteralSection();
587 void addInput(WordLiteralInputSection *);
588 void finalizeContents();
589 void writeTo(uint8_t *buf) const override;
590
591 uint64_t getSize() const override {
592 return literal16Map.size() * 16 + literal8Map.size() * 8 +
593 literal4Map.size() * 4;
594 }
595
596 bool isNeeded() const override {
597 return !literal16Map.empty() || !literal4Map.empty() ||
598 !literal8Map.empty();
599 }
600
601 uint64_t getLiteral16Offset(uintptr_t buf) const {
602 return literal16Map.at(*reinterpret_cast<const UInt128 *>(buf)) * 16;
603 }
604
605 uint64_t getLiteral8Offset(uintptr_t buf) const {
606 return literal16Map.size() * 16 +
607 literal8Map.at(*reinterpret_cast<const uint64_t *>(buf)) * 8;
608 }
609
610 uint64_t getLiteral4Offset(uintptr_t buf) const {
611 return literal16Map.size() * 16 + literal8Map.size() * 8 +
612 literal4Map.at(*reinterpret_cast<const uint32_t *>(buf)) * 4;
613 }
614
615private:
616 std::vector<WordLiteralInputSection *> inputs;
617
618 template <class T> struct Hasher {
619 llvm::hash_code operator()(T v) const { return llvm::hash_value(v); }
620 };
621 // We're using unordered_map instead of DenseMap here because we need to
622 // support all possible integer values -- there are no suitable tombstone
623 // values for DenseMap.
624 std::unordered_map<UInt128, uint64_t, Hasher<UInt128>> literal16Map;
625 std::unordered_map<uint64_t, uint64_t> literal8Map;
626 std::unordered_map<uint32_t, uint64_t> literal4Map;
627};
628
629class ObjCImageInfoSection final : public SyntheticSection {
630public:
631 ObjCImageInfoSection();
632 bool isNeeded() const override { return !files.empty(); }
633 uint64_t getSize() const override { return 8; }
634 void addFile(const InputFile *file) {
635 assert(!file->objCImageInfo.empty());
636 files.push_back(file);
637 }
638 void finalizeContents();
639 void writeTo(uint8_t *buf) const override;
640
641private:
642 struct ImageInfo {
643 uint8_t swiftVersion = 0;
644 bool hasCategoryClassProperties = false;
645 } info;
646 static ImageInfo parseImageInfo(const InputFile *);
647 std::vector<const InputFile *> files; // files with image info
648};
649
650struct InStruct {
651 const uint8_t *bufferStart = nullptr;
652 MachHeaderSection *header = nullptr;
653 CStringSection *cStringSection = nullptr;
654 DeduplicatedCStringSection *objcMethnameSection = nullptr;
655 WordLiteralSection *wordLiteralSection = nullptr;
656 RebaseSection *rebase = nullptr;
657 BindingSection *binding = nullptr;
658 WeakBindingSection *weakBinding = nullptr;
659 LazyBindingSection *lazyBinding = nullptr;
660 ExportSection *exports = nullptr;
661 GotSection *got = nullptr;
662 TlvPointerSection *tlvPointers = nullptr;
663 LazyPointerSection *lazyPointers = nullptr;
664 StubsSection *stubs = nullptr;
665 StubHelperSection *stubHelper = nullptr;
666 ObjCStubsSection *objcStubs = nullptr;
667 ConcatInputSection *objcSelrefs = nullptr;
668 UnwindInfoSection *unwindInfo = nullptr;
669 ObjCImageInfoSection *objCImageInfo = nullptr;
670 ConcatInputSection *imageLoaderCache = nullptr;
671};
672
673extern InStruct in;
674extern std::vector<SyntheticSection *> syntheticSections;
675
676void createSyntheticSymbols();
677
678} // namespace lld::macho
679
680#endif
681

source code of lld/MachO/SyntheticSections.h