1//===- lib/MC/MachObjectWriter.cpp - Mach-O File Writer -------------------===//
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#include "llvm/ADT/DenseMap.h"
10#include "llvm/ADT/Twine.h"
11#include "llvm/BinaryFormat/MachO.h"
12#include "llvm/MC/MCAsmBackend.h"
13#include "llvm/MC/MCAsmInfoDarwin.h"
14#include "llvm/MC/MCAssembler.h"
15#include "llvm/MC/MCContext.h"
16#include "llvm/MC/MCDirectives.h"
17#include "llvm/MC/MCExpr.h"
18#include "llvm/MC/MCFixupKindInfo.h"
19#include "llvm/MC/MCMachObjectWriter.h"
20#include "llvm/MC/MCObjectFileInfo.h"
21#include "llvm/MC/MCObjectWriter.h"
22#include "llvm/MC/MCSection.h"
23#include "llvm/MC/MCSectionMachO.h"
24#include "llvm/MC/MCSymbol.h"
25#include "llvm/MC/MCSymbolMachO.h"
26#include "llvm/MC/MCValue.h"
27#include "llvm/Support/Alignment.h"
28#include "llvm/Support/Casting.h"
29#include "llvm/Support/Debug.h"
30#include "llvm/Support/ErrorHandling.h"
31#include "llvm/Support/MathExtras.h"
32#include "llvm/Support/raw_ostream.h"
33#include <algorithm>
34#include <cassert>
35#include <cstdint>
36#include <string>
37#include <utility>
38#include <vector>
39
40using namespace llvm;
41
42#define DEBUG_TYPE "mc"
43
44void MachObjectWriter::reset() {
45 Relocations.clear();
46 IndirectSymBase.clear();
47 IndirectSymbols.clear();
48 DataRegions.clear();
49 SectionAddress.clear();
50 SectionOrder.clear();
51 StringTable.clear();
52 LocalSymbolData.clear();
53 ExternalSymbolData.clear();
54 UndefinedSymbolData.clear();
55 LOHContainer.reset();
56 VersionInfo.Major = 0;
57 VersionInfo.SDKVersion = VersionTuple();
58 TargetVariantVersionInfo.Major = 0;
59 TargetVariantVersionInfo.SDKVersion = VersionTuple();
60 LinkerOptions.clear();
61 MCObjectWriter::reset();
62}
63
64void MachObjectWriter::setAssembler(MCAssembler *Asm) {
65 MCObjectWriter::setAssembler(Asm);
66 TargetObjectWriter->setAssembler(Asm);
67}
68
69bool MachObjectWriter::doesSymbolRequireExternRelocation(const MCSymbol &S) {
70 // Undefined symbols are always extern.
71 if (S.isUndefined())
72 return true;
73
74 // References to weak definitions require external relocation entries; the
75 // definition may not always be the one in the same object file.
76 if (cast<MCSymbolMachO>(Val: S).isWeakDefinition())
77 return true;
78
79 // Otherwise, we can use an internal relocation.
80 return false;
81}
82
83bool MachObjectWriter::
84MachSymbolData::operator<(const MachSymbolData &RHS) const {
85 return Symbol->getName() < RHS.Symbol->getName();
86}
87
88uint64_t
89MachObjectWriter::getFragmentAddress(const MCAssembler &Asm,
90 const MCFragment *Fragment) const {
91 return getSectionAddress(Sec: Fragment->getParent()) +
92 Asm.getFragmentOffset(F: *Fragment);
93}
94
95uint64_t MachObjectWriter::getSymbolAddress(const MCSymbol &S) const {
96 // If this is a variable, then recursively evaluate now.
97 if (S.isVariable()) {
98 if (const MCConstantExpr *C =
99 dyn_cast<const MCConstantExpr>(Val: S.getVariableValue()))
100 return C->getValue();
101
102 MCValue Target;
103 if (!S.getVariableValue()->evaluateAsRelocatable(Res&: Target, Asm))
104 report_fatal_error(reason: "unable to evaluate offset for variable '" +
105 S.getName() + "'");
106
107 // Verify that any used symbols are defined.
108 if (Target.getAddSym() && Target.getAddSym()->isUndefined())
109 report_fatal_error(reason: "unable to evaluate offset to undefined symbol '" +
110 Target.getAddSym()->getName() + "'");
111 if (Target.getSubSym() && Target.getSubSym()->isUndefined())
112 report_fatal_error(reason: "unable to evaluate offset to undefined symbol '" +
113 Target.getSubSym()->getName() + "'");
114
115 uint64_t Address = Target.getConstant();
116 if (Target.getAddSym())
117 Address += getSymbolAddress(S: *Target.getAddSym());
118 if (Target.getSubSym())
119 Address -= getSymbolAddress(S: *Target.getSubSym());
120 return Address;
121 }
122
123 return getSectionAddress(Sec: S.getFragment()->getParent()) +
124 Asm->getSymbolOffset(S);
125}
126
127uint64_t MachObjectWriter::getPaddingSize(const MCAssembler &Asm,
128 const MCSection *Sec) const {
129 uint64_t EndAddr = getSectionAddress(Sec) + Asm.getSectionAddressSize(Sec: *Sec);
130 unsigned Next = cast<MCSectionMachO>(Val: Sec)->getLayoutOrder() + 1;
131 if (Next >= SectionOrder.size())
132 return 0;
133
134 const MCSection &NextSec = *SectionOrder[Next];
135 if (NextSec.isVirtualSection())
136 return 0;
137 return offsetToAlignment(Value: EndAddr, Alignment: NextSec.getAlign());
138}
139
140static bool isSymbolLinkerVisible(const MCSymbol &Symbol) {
141 // Non-temporary labels should always be visible to the linker.
142 if (!Symbol.isTemporary())
143 return true;
144
145 if (Symbol.isUsedInReloc())
146 return true;
147
148 return false;
149}
150
151const MCSymbol *MachObjectWriter::getAtom(const MCSymbol &S) const {
152 // Linker visible symbols define atoms.
153 if (isSymbolLinkerVisible(Symbol: S))
154 return &S;
155
156 // Absolute and undefined symbols have no defining atom.
157 if (!S.isInSection())
158 return nullptr;
159
160 // Non-linker visible symbols in sections which can't be atomized have no
161 // defining atom.
162 if (!MCAsmInfoDarwin::isSectionAtomizableBySymbols(
163 Section: *S.getFragment()->getParent()))
164 return nullptr;
165
166 // Otherwise, return the atom for the containing fragment.
167 return S.getFragment()->getAtom();
168}
169
170void MachObjectWriter::writeHeader(MachO::HeaderFileType Type,
171 unsigned NumLoadCommands,
172 unsigned LoadCommandsSize,
173 bool SubsectionsViaSymbols) {
174 uint32_t Flags = 0;
175
176 if (SubsectionsViaSymbols)
177 Flags |= MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
178
179 // struct mach_header (28 bytes) or
180 // struct mach_header_64 (32 bytes)
181
182 uint64_t Start = W.OS.tell();
183 (void) Start;
184
185 W.write<uint32_t>(Val: is64Bit() ? MachO::MH_MAGIC_64 : MachO::MH_MAGIC);
186
187 W.write<uint32_t>(Val: TargetObjectWriter->getCPUType());
188
189 uint32_t Cpusubtype = TargetObjectWriter->getCPUSubtype();
190
191 // Promote arm64e subtypes to always be ptrauth-ABI-versioned, at version 0.
192 // We never need to emit unversioned binaries.
193 // And we don't support arbitrary ABI versions (or the kernel flag) yet.
194 if (TargetObjectWriter->getCPUType() == MachO::CPU_TYPE_ARM64 &&
195 Cpusubtype == MachO::CPU_SUBTYPE_ARM64E)
196 Cpusubtype = MachO::CPU_SUBTYPE_ARM64E_WITH_PTRAUTH_VERSION(
197 /*PtrAuthABIVersion=*/0, /*PtrAuthKernelABIVersion=*/false);
198
199 W.write<uint32_t>(Val: Cpusubtype);
200
201 W.write<uint32_t>(Val: Type);
202 W.write<uint32_t>(Val: NumLoadCommands);
203 W.write<uint32_t>(Val: LoadCommandsSize);
204 W.write<uint32_t>(Val: Flags);
205 if (is64Bit())
206 W.write<uint32_t>(Val: 0); // reserved
207
208 assert(W.OS.tell() - Start == (is64Bit() ? sizeof(MachO::mach_header_64)
209 : sizeof(MachO::mach_header)));
210}
211
212void MachObjectWriter::writeWithPadding(StringRef Str, uint64_t Size) {
213 assert(Size >= Str.size());
214 W.OS << Str;
215 W.OS.write_zeros(NumZeros: Size - Str.size());
216}
217
218/// writeSegmentLoadCommand - Write a segment load command.
219///
220/// \param NumSections The number of sections in this segment.
221/// \param SectionDataSize The total size of the sections.
222void MachObjectWriter::writeSegmentLoadCommand(
223 StringRef Name, unsigned NumSections, uint64_t VMAddr, uint64_t VMSize,
224 uint64_t SectionDataStartOffset, uint64_t SectionDataSize, uint32_t MaxProt,
225 uint32_t InitProt) {
226 // struct segment_command (56 bytes) or
227 // struct segment_command_64 (72 bytes)
228
229 uint64_t Start = W.OS.tell();
230 (void) Start;
231
232 unsigned SegmentLoadCommandSize =
233 is64Bit() ? sizeof(MachO::segment_command_64):
234 sizeof(MachO::segment_command);
235 W.write<uint32_t>(Val: is64Bit() ? MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT);
236 W.write<uint32_t>(Val: SegmentLoadCommandSize +
237 NumSections * (is64Bit() ? sizeof(MachO::section_64) :
238 sizeof(MachO::section)));
239
240 writeWithPadding(Str: Name, Size: 16);
241 if (is64Bit()) {
242 W.write<uint64_t>(Val: VMAddr); // vmaddr
243 W.write<uint64_t>(Val: VMSize); // vmsize
244 W.write<uint64_t>(Val: SectionDataStartOffset); // file offset
245 W.write<uint64_t>(Val: SectionDataSize); // file size
246 } else {
247 W.write<uint32_t>(Val: VMAddr); // vmaddr
248 W.write<uint32_t>(Val: VMSize); // vmsize
249 W.write<uint32_t>(Val: SectionDataStartOffset); // file offset
250 W.write<uint32_t>(Val: SectionDataSize); // file size
251 }
252 // maxprot
253 W.write<uint32_t>(Val: MaxProt);
254 // initprot
255 W.write<uint32_t>(Val: InitProt);
256 W.write<uint32_t>(Val: NumSections);
257 W.write<uint32_t>(Val: 0); // flags
258
259 assert(W.OS.tell() - Start == SegmentLoadCommandSize);
260}
261
262void MachObjectWriter::writeSection(const MCAssembler &Asm,
263 const MCSection &Sec, uint64_t VMAddr,
264 uint64_t FileOffset, unsigned Flags,
265 uint64_t RelocationsStart,
266 unsigned NumRelocations) {
267 uint64_t SectionSize = Asm.getSectionAddressSize(Sec);
268 const MCSectionMachO &Section = cast<MCSectionMachO>(Val: Sec);
269
270 // The offset is unused for virtual sections.
271 if (Section.isVirtualSection()) {
272 assert(Asm.getSectionFileSize(Sec) == 0 && "Invalid file size!");
273 FileOffset = 0;
274 }
275
276 // struct section (68 bytes) or
277 // struct section_64 (80 bytes)
278
279 uint64_t Start = W.OS.tell();
280 (void) Start;
281
282 writeWithPadding(Str: Section.getName(), Size: 16);
283 writeWithPadding(Str: Section.getSegmentName(), Size: 16);
284 if (is64Bit()) {
285 W.write<uint64_t>(Val: VMAddr); // address
286 W.write<uint64_t>(Val: SectionSize); // size
287 } else {
288 W.write<uint32_t>(Val: VMAddr); // address
289 W.write<uint32_t>(Val: SectionSize); // size
290 }
291 assert(isUInt<32>(FileOffset) && "Cannot encode offset of section");
292 W.write<uint32_t>(Val: FileOffset);
293
294 W.write<uint32_t>(Val: Log2(A: Section.getAlign()));
295 assert((!NumRelocations || isUInt<32>(RelocationsStart)) &&
296 "Cannot encode offset of relocations");
297 W.write<uint32_t>(Val: NumRelocations ? RelocationsStart : 0);
298 W.write<uint32_t>(Val: NumRelocations);
299 W.write<uint32_t>(Val: Flags);
300 W.write<uint32_t>(Val: IndirectSymBase.lookup(Val: &Sec)); // reserved1
301 W.write<uint32_t>(Val: Section.getStubSize()); // reserved2
302 if (is64Bit())
303 W.write<uint32_t>(Val: 0); // reserved3
304
305 assert(W.OS.tell() - Start ==
306 (is64Bit() ? sizeof(MachO::section_64) : sizeof(MachO::section)));
307}
308
309void MachObjectWriter::writeSymtabLoadCommand(uint32_t SymbolOffset,
310 uint32_t NumSymbols,
311 uint32_t StringTableOffset,
312 uint32_t StringTableSize) {
313 // struct symtab_command (24 bytes)
314
315 uint64_t Start = W.OS.tell();
316 (void) Start;
317
318 W.write<uint32_t>(Val: MachO::LC_SYMTAB);
319 W.write<uint32_t>(Val: sizeof(MachO::symtab_command));
320 W.write<uint32_t>(Val: SymbolOffset);
321 W.write<uint32_t>(Val: NumSymbols);
322 W.write<uint32_t>(Val: StringTableOffset);
323 W.write<uint32_t>(Val: StringTableSize);
324
325 assert(W.OS.tell() - Start == sizeof(MachO::symtab_command));
326}
327
328void MachObjectWriter::writeDysymtabLoadCommand(uint32_t FirstLocalSymbol,
329 uint32_t NumLocalSymbols,
330 uint32_t FirstExternalSymbol,
331 uint32_t NumExternalSymbols,
332 uint32_t FirstUndefinedSymbol,
333 uint32_t NumUndefinedSymbols,
334 uint32_t IndirectSymbolOffset,
335 uint32_t NumIndirectSymbols) {
336 // struct dysymtab_command (80 bytes)
337
338 uint64_t Start = W.OS.tell();
339 (void) Start;
340
341 W.write<uint32_t>(Val: MachO::LC_DYSYMTAB);
342 W.write<uint32_t>(Val: sizeof(MachO::dysymtab_command));
343 W.write<uint32_t>(Val: FirstLocalSymbol);
344 W.write<uint32_t>(Val: NumLocalSymbols);
345 W.write<uint32_t>(Val: FirstExternalSymbol);
346 W.write<uint32_t>(Val: NumExternalSymbols);
347 W.write<uint32_t>(Val: FirstUndefinedSymbol);
348 W.write<uint32_t>(Val: NumUndefinedSymbols);
349 W.write<uint32_t>(Val: 0); // tocoff
350 W.write<uint32_t>(Val: 0); // ntoc
351 W.write<uint32_t>(Val: 0); // modtaboff
352 W.write<uint32_t>(Val: 0); // nmodtab
353 W.write<uint32_t>(Val: 0); // extrefsymoff
354 W.write<uint32_t>(Val: 0); // nextrefsyms
355 W.write<uint32_t>(Val: IndirectSymbolOffset);
356 W.write<uint32_t>(Val: NumIndirectSymbols);
357 W.write<uint32_t>(Val: 0); // extreloff
358 W.write<uint32_t>(Val: 0); // nextrel
359 W.write<uint32_t>(Val: 0); // locreloff
360 W.write<uint32_t>(Val: 0); // nlocrel
361
362 assert(W.OS.tell() - Start == sizeof(MachO::dysymtab_command));
363}
364
365MachObjectWriter::MachSymbolData *
366MachObjectWriter::findSymbolData(const MCSymbol &Sym) {
367 for (auto *SymbolData :
368 {&LocalSymbolData, &ExternalSymbolData, &UndefinedSymbolData})
369 for (MachSymbolData &Entry : *SymbolData)
370 if (Entry.Symbol == &Sym)
371 return &Entry;
372
373 return nullptr;
374}
375
376const MCSymbol &MachObjectWriter::findAliasedSymbol(const MCSymbol &Sym) const {
377 const MCSymbol *S = &Sym;
378 while (S->isVariable()) {
379 const MCExpr *Value = S->getVariableValue();
380 const auto *Ref = dyn_cast<MCSymbolRefExpr>(Val: Value);
381 if (!Ref)
382 return *S;
383 S = &Ref->getSymbol();
384 }
385 return *S;
386}
387
388void MachObjectWriter::writeNlist(MachSymbolData &MSD, const MCAssembler &Asm) {
389 const MCSymbol *Symbol = MSD.Symbol;
390 const auto &Data = cast<MCSymbolMachO>(Val: *Symbol);
391 const MCSymbol *AliasedSymbol = &findAliasedSymbol(Sym: *Symbol);
392 uint8_t SectionIndex = MSD.SectionIndex;
393 uint8_t Type = 0;
394 uint64_t Address = 0;
395 bool IsAlias = Symbol != AliasedSymbol;
396
397 const MCSymbol &OrigSymbol = *Symbol;
398 MachSymbolData *AliaseeInfo;
399 if (IsAlias) {
400 AliaseeInfo = findSymbolData(Sym: *AliasedSymbol);
401 if (AliaseeInfo)
402 SectionIndex = AliaseeInfo->SectionIndex;
403 Symbol = AliasedSymbol;
404 // FIXME: Should this update Data as well?
405 }
406
407 // Set the N_TYPE bits. See <mach-o/nlist.h>.
408 //
409 // FIXME: Are the prebound or indirect fields possible here?
410 if (IsAlias && Symbol->isUndefined())
411 Type = MachO::N_INDR;
412 else if (Symbol->isUndefined())
413 Type = MachO::N_UNDF;
414 else if (Symbol->isAbsolute())
415 Type = MachO::N_ABS;
416 else
417 Type = MachO::N_SECT;
418
419 // FIXME: Set STAB bits.
420
421 if (Data.isPrivateExtern())
422 Type |= MachO::N_PEXT;
423
424 // Set external bit.
425 if (Data.isExternal() || (!IsAlias && Symbol->isUndefined()))
426 Type |= MachO::N_EXT;
427
428 // Compute the symbol address.
429 if (IsAlias && Symbol->isUndefined())
430 Address = AliaseeInfo->StringIndex;
431 else if (Symbol->isDefined())
432 Address = getSymbolAddress(S: OrigSymbol);
433 else if (Symbol->isCommon()) {
434 // Common symbols are encoded with the size in the address
435 // field, and their alignment in the flags.
436 Address = Symbol->getCommonSize();
437 }
438
439 // struct nlist (12 bytes)
440
441 W.write<uint32_t>(Val: MSD.StringIndex);
442 W.OS << char(Type);
443 W.OS << char(SectionIndex);
444
445 // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc'
446 // value.
447 bool EncodeAsAltEntry =
448 IsAlias && cast<MCSymbolMachO>(Val: OrigSymbol).isAltEntry();
449 W.write<uint16_t>(Val: cast<MCSymbolMachO>(Val: Symbol)->getEncodedFlags(EncodeAsAltEntry));
450 if (is64Bit())
451 W.write<uint64_t>(Val: Address);
452 else
453 W.write<uint32_t>(Val: Address);
454}
455
456void MachObjectWriter::writeLinkeditLoadCommand(uint32_t Type,
457 uint32_t DataOffset,
458 uint32_t DataSize) {
459 uint64_t Start = W.OS.tell();
460 (void) Start;
461
462 W.write<uint32_t>(Val: Type);
463 W.write<uint32_t>(Val: sizeof(MachO::linkedit_data_command));
464 W.write<uint32_t>(Val: DataOffset);
465 W.write<uint32_t>(Val: DataSize);
466
467 assert(W.OS.tell() - Start == sizeof(MachO::linkedit_data_command));
468}
469
470static unsigned ComputeLinkerOptionsLoadCommandSize(
471 const std::vector<std::string> &Options, bool is64Bit)
472{
473 unsigned Size = sizeof(MachO::linker_option_command);
474 for (const std::string &Option : Options)
475 Size += Option.size() + 1;
476 return alignTo(Value: Size, Align: is64Bit ? 8 : 4);
477}
478
479void MachObjectWriter::writeLinkerOptionsLoadCommand(
480 const std::vector<std::string> &Options)
481{
482 unsigned Size = ComputeLinkerOptionsLoadCommandSize(Options, is64Bit: is64Bit());
483 uint64_t Start = W.OS.tell();
484 (void) Start;
485
486 W.write<uint32_t>(Val: MachO::LC_LINKER_OPTION);
487 W.write<uint32_t>(Val: Size);
488 W.write<uint32_t>(Val: Options.size());
489 uint64_t BytesWritten = sizeof(MachO::linker_option_command);
490 for (const std::string &Option : Options) {
491 // Write each string, including the null byte.
492 W.OS << Option << '\0';
493 BytesWritten += Option.size() + 1;
494 }
495
496 // Pad to a multiple of the pointer size.
497 W.OS.write_zeros(
498 NumZeros: offsetToAlignment(Value: BytesWritten, Alignment: is64Bit() ? Align(8) : Align(4)));
499
500 assert(W.OS.tell() - Start == Size);
501}
502
503static bool isFixupTargetValid(const MCValue &Target) {
504 // Target is (LHS - RHS + cst).
505 // We don't support the form where LHS is null: -RHS + cst
506 if (!Target.getAddSym() && Target.getSubSym())
507 return false;
508 return true;
509}
510
511void MachObjectWriter::recordRelocation(const MCFragment &F,
512 const MCFixup &Fixup, MCValue Target,
513 uint64_t &FixedValue) {
514 if (!isFixupTargetValid(Target)) {
515 getContext().reportError(L: Fixup.getLoc(),
516 Msg: "unsupported relocation expression");
517 return;
518 }
519
520 TargetObjectWriter->recordRelocation(Writer: this, Asm&: *Asm, Fragment: &F, Fixup, Target,
521 FixedValue);
522}
523
524void MachObjectWriter::bindIndirectSymbols(MCAssembler &Asm) {
525 // This is the point where 'as' creates actual symbols for indirect symbols
526 // (in the following two passes). It would be easier for us to do this sooner
527 // when we see the attribute, but that makes getting the order in the symbol
528 // table much more complicated than it is worth.
529 //
530 // FIXME: Revisit this when the dust settles.
531
532 // Report errors for use of .indirect_symbol not in a symbol pointer section
533 // or stub section.
534 for (IndirectSymbolData &ISD : IndirectSymbols) {
535 const MCSectionMachO &Section = cast<MCSectionMachO>(Val&: *ISD.Section);
536
537 if (Section.getType() != MachO::S_NON_LAZY_SYMBOL_POINTERS &&
538 Section.getType() != MachO::S_LAZY_SYMBOL_POINTERS &&
539 Section.getType() != MachO::S_THREAD_LOCAL_VARIABLE_POINTERS &&
540 Section.getType() != MachO::S_SYMBOL_STUBS) {
541 MCSymbol &Symbol = *ISD.Symbol;
542 report_fatal_error(reason: "indirect symbol '" + Symbol.getName() +
543 "' not in a symbol pointer or stub section");
544 }
545 }
546
547 // Bind non-lazy symbol pointers first.
548 for (auto [IndirectIndex, ISD] : enumerate(First&: IndirectSymbols)) {
549 const auto &Section = cast<MCSectionMachO>(Val&: *ISD.Section);
550
551 if (Section.getType() != MachO::S_NON_LAZY_SYMBOL_POINTERS &&
552 Section.getType() != MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)
553 continue;
554
555 // Initialize the section indirect symbol base, if necessary.
556 IndirectSymBase.insert(KV: std::make_pair(x&: ISD.Section, y&: IndirectIndex));
557
558 Asm.registerSymbol(Symbol: *ISD.Symbol);
559 }
560
561 // Then lazy symbol pointers and symbol stubs.
562 for (auto [IndirectIndex, ISD] : enumerate(First&: IndirectSymbols)) {
563 const auto &Section = cast<MCSectionMachO>(Val&: *ISD.Section);
564
565 if (Section.getType() != MachO::S_LAZY_SYMBOL_POINTERS &&
566 Section.getType() != MachO::S_SYMBOL_STUBS)
567 continue;
568
569 // Initialize the section indirect symbol base, if necessary.
570 IndirectSymBase.insert(KV: std::make_pair(x&: ISD.Section, y&: IndirectIndex));
571
572 // Set the symbol type to undefined lazy, but only on construction.
573 //
574 // FIXME: Do not hardcode.
575 if (Asm.registerSymbol(Symbol: *ISD.Symbol))
576 cast<MCSymbolMachO>(Val: ISD.Symbol)->setReferenceTypeUndefinedLazy(true);
577 }
578}
579
580/// computeSymbolTable - Compute the symbol table data
581void MachObjectWriter::computeSymbolTable(
582 MCAssembler &Asm, std::vector<MachSymbolData> &LocalSymbolData,
583 std::vector<MachSymbolData> &ExternalSymbolData,
584 std::vector<MachSymbolData> &UndefinedSymbolData) {
585 // Build section lookup table.
586 DenseMap<const MCSection*, uint8_t> SectionIndexMap;
587 unsigned Index = 1;
588 for (MCSection &Sec : Asm)
589 SectionIndexMap[&Sec] = Index++;
590 assert(Index <= 256 && "Too many sections!");
591
592 // Build the string table.
593 for (const MCSymbol &Symbol : Asm.symbols()) {
594 if (!cast<MCSymbolMachO>(Val: Symbol).isSymbolLinkerVisible())
595 continue;
596
597 StringTable.add(S: Symbol.getName());
598 }
599 StringTable.finalize();
600
601 // Build the symbol arrays but only for non-local symbols.
602 //
603 // The particular order that we collect and then sort the symbols is chosen to
604 // match 'as'. Even though it doesn't matter for correctness, this is
605 // important for letting us diff .o files.
606 for (const MCSymbol &Symbol : Asm.symbols()) {
607 // Ignore non-linker visible symbols.
608 if (!cast<MCSymbolMachO>(Val: Symbol).isSymbolLinkerVisible())
609 continue;
610
611 if (!Symbol.isExternal() && !Symbol.isUndefined())
612 continue;
613
614 MachSymbolData MSD;
615 MSD.Symbol = &Symbol;
616 MSD.StringIndex = StringTable.getOffset(S: Symbol.getName());
617
618 if (Symbol.isUndefined()) {
619 MSD.SectionIndex = 0;
620 UndefinedSymbolData.push_back(x: MSD);
621 } else if (Symbol.isAbsolute()) {
622 MSD.SectionIndex = 0;
623 ExternalSymbolData.push_back(x: MSD);
624 } else {
625 MSD.SectionIndex = SectionIndexMap.lookup(Val: &Symbol.getSection());
626 assert(MSD.SectionIndex && "Invalid section index!");
627 ExternalSymbolData.push_back(x: MSD);
628 }
629 }
630
631 // Now add the data for local symbols.
632 for (const MCSymbol &Symbol : Asm.symbols()) {
633 // Ignore non-linker visible symbols.
634 if (!cast<MCSymbolMachO>(Val: Symbol).isSymbolLinkerVisible())
635 continue;
636
637 if (Symbol.isExternal() || Symbol.isUndefined())
638 continue;
639
640 MachSymbolData MSD;
641 MSD.Symbol = &Symbol;
642 MSD.StringIndex = StringTable.getOffset(S: Symbol.getName());
643
644 if (Symbol.isAbsolute()) {
645 MSD.SectionIndex = 0;
646 LocalSymbolData.push_back(x: MSD);
647 } else {
648 MSD.SectionIndex = SectionIndexMap.lookup(Val: &Symbol.getSection());
649 assert(MSD.SectionIndex && "Invalid section index!");
650 LocalSymbolData.push_back(x: MSD);
651 }
652 }
653
654 // External and undefined symbols are required to be in lexicographic order.
655 llvm::sort(C&: ExternalSymbolData);
656 llvm::sort(C&: UndefinedSymbolData);
657
658 // Set the symbol indices.
659 Index = 0;
660 for (auto *SymbolData :
661 {&LocalSymbolData, &ExternalSymbolData, &UndefinedSymbolData})
662 for (MachSymbolData &Entry : *SymbolData)
663 Entry.Symbol->setIndex(Index++);
664
665 for (const MCSection &Section : Asm) {
666 for (RelAndSymbol &Rel : Relocations[&Section]) {
667 if (!Rel.Sym)
668 continue;
669
670 // Set the Index and the IsExtern bit.
671 unsigned Index = Rel.Sym->getIndex();
672 assert(isInt<24>(Index));
673 if (W.Endian == llvm::endianness::little)
674 Rel.MRE.r_word1 = (Rel.MRE.r_word1 & (~0U << 24)) | Index | (1 << 27);
675 else
676 Rel.MRE.r_word1 = (Rel.MRE.r_word1 & 0xff) | Index << 8 | (1 << 4);
677 }
678 }
679}
680
681void MachObjectWriter::computeSectionAddresses(const MCAssembler &Asm) {
682 // Assign layout order indices to sections.
683 unsigned i = 0;
684 // Compute the section layout order. Virtual sections must go last.
685 for (MCSection &Sec : Asm) {
686 if (!Sec.isVirtualSection()) {
687 SectionOrder.push_back(Elt: &Sec);
688 cast<MCSectionMachO>(Val&: Sec).setLayoutOrder(i++);
689 }
690 }
691 for (MCSection &Sec : Asm) {
692 if (Sec.isVirtualSection()) {
693 SectionOrder.push_back(Elt: &Sec);
694 cast<MCSectionMachO>(Val&: Sec).setLayoutOrder(i++);
695 }
696 }
697
698 uint64_t StartAddress = 0;
699 for (const MCSection *Sec : SectionOrder) {
700 StartAddress = alignTo(Size: StartAddress, A: Sec->getAlign());
701 SectionAddress[Sec] = StartAddress;
702 StartAddress += Asm.getSectionAddressSize(Sec: *Sec);
703
704 // Explicitly pad the section to match the alignment requirements of the
705 // following one. This is for 'gas' compatibility, it shouldn't
706 /// strictly be necessary.
707 StartAddress += getPaddingSize(Asm, Sec);
708 }
709}
710
711void MachObjectWriter::executePostLayoutBinding() {
712 computeSectionAddresses(Asm: *Asm);
713
714 // Create symbol data for any indirect symbols.
715 bindIndirectSymbols(Asm&: *Asm);
716}
717
718bool MachObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(
719 const MCSymbol &SymA, const MCFragment &FB, bool InSet,
720 bool IsPCRel) const {
721 if (InSet)
722 return true;
723
724 // The effective address is
725 // addr(atom(A)) + offset(A)
726 // - addr(atom(B)) - offset(B)
727 // and the offsets are not relocatable, so the fixup is fully resolved when
728 // addr(atom(A)) - addr(atom(B)) == 0.
729 const MCSymbol &SA = findAliasedSymbol(Sym: SymA);
730 const MCSection &SecA = SA.getSection();
731 const MCSection &SecB = *FB.getParent();
732
733 if (IsPCRel) {
734 // The simple (Darwin, except on x86_64) way of dealing with this was to
735 // assume that any reference to a temporary symbol *must* be a temporary
736 // symbol in the same atom, unless the sections differ. Therefore, any PCrel
737 // relocation to a temporary symbol (in the same section) is fully
738 // resolved. This also works in conjunction with absolutized .set, which
739 // requires the compiler to use .set to absolutize the differences between
740 // symbols which the compiler knows to be assembly time constants, so we
741 // don't need to worry about considering symbol differences fully resolved.
742 //
743 // If the file isn't using sub-sections-via-symbols, we can make the
744 // same assumptions about any symbol that we normally make about
745 // assembler locals.
746
747 bool hasReliableSymbolDifference = isX86_64();
748 if (!hasReliableSymbolDifference) {
749 if (!SA.isInSection() || &SecA != &SecB ||
750 (!SA.isTemporary() && FB.getAtom() != SA.getFragment()->getAtom() &&
751 SubsectionsViaSymbols))
752 return false;
753 return true;
754 }
755 }
756
757 // If they are not in the same section, we can't compute the diff.
758 if (&SecA != &SecB)
759 return false;
760
761 // If the atoms are the same, they are guaranteed to have the same address.
762 return SA.getFragment()->getAtom() == FB.getAtom();
763}
764
765static MachO::LoadCommandType getLCFromMCVM(MCVersionMinType Type) {
766 switch (Type) {
767 case MCVM_OSXVersionMin: return MachO::LC_VERSION_MIN_MACOSX;
768 case MCVM_IOSVersionMin: return MachO::LC_VERSION_MIN_IPHONEOS;
769 case MCVM_TvOSVersionMin: return MachO::LC_VERSION_MIN_TVOS;
770 case MCVM_WatchOSVersionMin: return MachO::LC_VERSION_MIN_WATCHOS;
771 }
772 llvm_unreachable("Invalid mc version min type");
773}
774
775void MachObjectWriter::populateAddrSigSection(MCAssembler &Asm) {
776 MCSection *AddrSigSection =
777 getContext().getObjectFileInfo()->getAddrSigSection();
778 unsigned Log2Size = is64Bit() ? 3 : 2;
779 for (const MCSymbol *S : getAddrsigSyms()) {
780 if (!S->isRegistered())
781 continue;
782 MachO::any_relocation_info MRE;
783 MRE.r_word0 = 0;
784 MRE.r_word1 = (Log2Size << 25) | (MachO::GENERIC_RELOC_VANILLA << 28);
785 addRelocation(RelSymbol: S, Sec: AddrSigSection, MRE);
786 }
787}
788
789uint64_t MachObjectWriter::writeObject() {
790 auto &Asm = *this->Asm;
791 uint64_t StartOffset = W.OS.tell();
792 auto NumBytesWritten = [&] { return W.OS.tell() - StartOffset; };
793
794 populateAddrSigSection(Asm);
795
796 // Compute symbol table information and bind symbol indices.
797 computeSymbolTable(Asm, LocalSymbolData, ExternalSymbolData,
798 UndefinedSymbolData);
799
800 if (!CGProfile.empty()) {
801 MCSection *CGProfileSection = getContext().getMachOSection(
802 Segment: "__LLVM", Section: "__cg_profile", TypeAndAttributes: 0, K: SectionKind::getMetadata());
803 auto &Frag = cast<MCDataFragment>(Val&: *CGProfileSection->begin());
804 Frag.clearContents();
805 raw_svector_ostream OS(Frag.getContentsForAppending());
806 for (const MCObjectWriter::CGProfileEntry &CGPE : CGProfile) {
807 uint32_t FromIndex = CGPE.From->getSymbol().getIndex();
808 uint32_t ToIndex = CGPE.To->getSymbol().getIndex();
809 support::endian::write(os&: OS, value: FromIndex, endian: W.Endian);
810 support::endian::write(os&: OS, value: ToIndex, endian: W.Endian);
811 support::endian::write(os&: OS, value: CGPE.Count, endian: W.Endian);
812 }
813 Frag.doneAppending();
814 }
815
816 unsigned NumSections = Asm.end() - Asm.begin();
817
818 // The section data starts after the header, the segment load command (and
819 // section headers) and the symbol table.
820 unsigned NumLoadCommands = 1;
821 uint64_t LoadCommandsSize = is64Bit() ?
822 sizeof(MachO::segment_command_64) + NumSections * sizeof(MachO::section_64):
823 sizeof(MachO::segment_command) + NumSections * sizeof(MachO::section);
824
825 // Add the deployment target version info load command size, if used.
826 if (VersionInfo.Major != 0) {
827 ++NumLoadCommands;
828 if (VersionInfo.EmitBuildVersion)
829 LoadCommandsSize += sizeof(MachO::build_version_command);
830 else
831 LoadCommandsSize += sizeof(MachO::version_min_command);
832 }
833
834 // Add the target variant version info load command size, if used.
835 if (TargetVariantVersionInfo.Major != 0) {
836 ++NumLoadCommands;
837 assert(TargetVariantVersionInfo.EmitBuildVersion &&
838 "target variant should use build version");
839 LoadCommandsSize += sizeof(MachO::build_version_command);
840 }
841
842 // Add the data-in-code load command size, if used.
843 unsigned NumDataRegions = DataRegions.size();
844 if (NumDataRegions) {
845 ++NumLoadCommands;
846 LoadCommandsSize += sizeof(MachO::linkedit_data_command);
847 }
848
849 // Add the loh load command size, if used.
850 uint64_t LOHRawSize = LOHContainer.getEmitSize(Asm, ObjWriter: *this);
851 uint64_t LOHSize = alignTo(Value: LOHRawSize, Align: is64Bit() ? 8 : 4);
852 if (LOHSize) {
853 ++NumLoadCommands;
854 LoadCommandsSize += sizeof(MachO::linkedit_data_command);
855 }
856
857 // Add the symbol table load command sizes, if used.
858 unsigned NumSymbols = LocalSymbolData.size() + ExternalSymbolData.size() +
859 UndefinedSymbolData.size();
860 if (NumSymbols) {
861 NumLoadCommands += 2;
862 LoadCommandsSize += (sizeof(MachO::symtab_command) +
863 sizeof(MachO::dysymtab_command));
864 }
865
866 // Add the linker option load commands sizes.
867 for (const auto &Option : LinkerOptions) {
868 ++NumLoadCommands;
869 LoadCommandsSize += ComputeLinkerOptionsLoadCommandSize(Options: Option, is64Bit: is64Bit());
870 }
871
872 // Compute the total size of the section data, as well as its file size and vm
873 // size.
874 uint64_t SectionDataStart = (is64Bit() ? sizeof(MachO::mach_header_64) :
875 sizeof(MachO::mach_header)) + LoadCommandsSize;
876 uint64_t SectionDataSize = 0;
877 uint64_t SectionDataFileSize = 0;
878 uint64_t VMSize = 0;
879 for (const MCSection &Sec : Asm) {
880 uint64_t Address = getSectionAddress(Sec: &Sec);
881 uint64_t Size = Asm.getSectionAddressSize(Sec);
882 uint64_t FileSize = Asm.getSectionFileSize(Sec);
883 FileSize += getPaddingSize(Asm, Sec: &Sec);
884
885 VMSize = std::max(a: VMSize, b: Address + Size);
886
887 if (Sec.isVirtualSection())
888 continue;
889
890 SectionDataSize = std::max(a: SectionDataSize, b: Address + Size);
891 SectionDataFileSize = std::max(a: SectionDataFileSize, b: Address + FileSize);
892 }
893
894 // The section data is padded to pointer size bytes.
895 //
896 // FIXME: Is this machine dependent?
897 unsigned SectionDataPadding =
898 offsetToAlignment(Value: SectionDataFileSize, Alignment: is64Bit() ? Align(8) : Align(4));
899 SectionDataFileSize += SectionDataPadding;
900
901 // Write the prolog, starting with the header and load command...
902 writeHeader(Type: MachO::MH_OBJECT, NumLoadCommands, LoadCommandsSize,
903 SubsectionsViaSymbols);
904 uint32_t Prot =
905 MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE;
906 writeSegmentLoadCommand(Name: "", NumSections, VMAddr: 0, VMSize, SectionDataStartOffset: SectionDataStart,
907 SectionDataSize, MaxProt: Prot, InitProt: Prot);
908
909 // ... and then the section headers.
910 uint64_t RelocTableEnd = SectionDataStart + SectionDataFileSize;
911 for (const MCSection &Section : Asm) {
912 const auto &Sec = cast<MCSectionMachO>(Val: Section);
913 std::vector<RelAndSymbol> &Relocs = Relocations[&Sec];
914 unsigned NumRelocs = Relocs.size();
915 uint64_t SectionStart = SectionDataStart + getSectionAddress(Sec: &Sec);
916 unsigned Flags = Sec.getTypeAndAttributes();
917 if (Sec.hasInstructions())
918 Flags |= MachO::S_ATTR_SOME_INSTRUCTIONS;
919 if (!cast<MCSectionMachO>(Val: Sec).isVirtualSection() &&
920 !isUInt<32>(x: SectionStart)) {
921 getContext().reportError(
922 L: SMLoc(), Msg: "cannot encode offset of section; object file too large");
923 return NumBytesWritten();
924 }
925 if (NumRelocs && !isUInt<32>(x: RelocTableEnd)) {
926 getContext().reportError(
927 L: SMLoc(),
928 Msg: "cannot encode offset of relocations; object file too large");
929 return NumBytesWritten();
930 }
931 writeSection(Asm, Sec, VMAddr: getSectionAddress(Sec: &Sec), FileOffset: SectionStart, Flags,
932 RelocationsStart: RelocTableEnd, NumRelocations: NumRelocs);
933 RelocTableEnd += NumRelocs * sizeof(MachO::any_relocation_info);
934 }
935
936 // Write out the deployment target information, if it's available.
937 auto EmitDeploymentTargetVersion =
938 [&](const VersionInfoType &VersionInfo) {
939 auto EncodeVersion = [](VersionTuple V) -> uint32_t {
940 assert(!V.empty() && "empty version");
941 unsigned Update = V.getSubminor().value_or(u: 0);
942 unsigned Minor = V.getMinor().value_or(u: 0);
943 assert(Update < 256 && "unencodable update target version");
944 assert(Minor < 256 && "unencodable minor target version");
945 assert(V.getMajor() < 65536 && "unencodable major target version");
946 return Update | (Minor << 8) | (V.getMajor() << 16);
947 };
948 uint32_t EncodedVersion = EncodeVersion(VersionTuple(
949 VersionInfo.Major, VersionInfo.Minor, VersionInfo.Update));
950 uint32_t SDKVersion = !VersionInfo.SDKVersion.empty()
951 ? EncodeVersion(VersionInfo.SDKVersion)
952 : 0;
953 if (VersionInfo.EmitBuildVersion) {
954 // FIXME: Currently empty tools. Add clang version in the future.
955 W.write<uint32_t>(Val: MachO::LC_BUILD_VERSION);
956 W.write<uint32_t>(Val: sizeof(MachO::build_version_command));
957 W.write<uint32_t>(Val: VersionInfo.TypeOrPlatform.Platform);
958 W.write<uint32_t>(Val: EncodedVersion);
959 W.write<uint32_t>(Val: SDKVersion);
960 W.write<uint32_t>(Val: 0); // Empty tools list.
961 } else {
962 MachO::LoadCommandType LCType =
963 getLCFromMCVM(Type: VersionInfo.TypeOrPlatform.Type);
964 W.write<uint32_t>(Val: LCType);
965 W.write<uint32_t>(Val: sizeof(MachO::version_min_command));
966 W.write<uint32_t>(Val: EncodedVersion);
967 W.write<uint32_t>(Val: SDKVersion);
968 }
969 };
970 if (VersionInfo.Major != 0)
971 EmitDeploymentTargetVersion(VersionInfo);
972 if (TargetVariantVersionInfo.Major != 0)
973 EmitDeploymentTargetVersion(TargetVariantVersionInfo);
974
975 // Write the data-in-code load command, if used.
976 uint64_t DataInCodeTableEnd = RelocTableEnd + NumDataRegions * 8;
977 if (NumDataRegions) {
978 uint64_t DataRegionsOffset = RelocTableEnd;
979 uint64_t DataRegionsSize = NumDataRegions * 8;
980 writeLinkeditLoadCommand(Type: MachO::LC_DATA_IN_CODE, DataOffset: DataRegionsOffset,
981 DataSize: DataRegionsSize);
982 }
983
984 // Write the loh load command, if used.
985 uint64_t LOHTableEnd = DataInCodeTableEnd + LOHSize;
986 if (LOHSize)
987 writeLinkeditLoadCommand(Type: MachO::LC_LINKER_OPTIMIZATION_HINT,
988 DataOffset: DataInCodeTableEnd, DataSize: LOHSize);
989
990 // Write the symbol table load command, if used.
991 if (NumSymbols) {
992 unsigned FirstLocalSymbol = 0;
993 unsigned NumLocalSymbols = LocalSymbolData.size();
994 unsigned FirstExternalSymbol = FirstLocalSymbol + NumLocalSymbols;
995 unsigned NumExternalSymbols = ExternalSymbolData.size();
996 unsigned FirstUndefinedSymbol = FirstExternalSymbol + NumExternalSymbols;
997 unsigned NumUndefinedSymbols = UndefinedSymbolData.size();
998 unsigned NumIndirectSymbols = IndirectSymbols.size();
999 unsigned NumSymTabSymbols =
1000 NumLocalSymbols + NumExternalSymbols + NumUndefinedSymbols;
1001 uint64_t IndirectSymbolSize = NumIndirectSymbols * 4;
1002 uint64_t IndirectSymbolOffset = 0;
1003
1004 // If used, the indirect symbols are written after the section data.
1005 if (NumIndirectSymbols)
1006 IndirectSymbolOffset = LOHTableEnd;
1007
1008 // The symbol table is written after the indirect symbol data.
1009 uint64_t SymbolTableOffset = LOHTableEnd + IndirectSymbolSize;
1010
1011 // The string table is written after symbol table.
1012 uint64_t StringTableOffset =
1013 SymbolTableOffset + NumSymTabSymbols * (is64Bit() ?
1014 sizeof(MachO::nlist_64) :
1015 sizeof(MachO::nlist));
1016 writeSymtabLoadCommand(SymbolOffset: SymbolTableOffset, NumSymbols: NumSymTabSymbols,
1017 StringTableOffset, StringTableSize: StringTable.getSize());
1018
1019 writeDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols,
1020 FirstExternalSymbol, NumExternalSymbols,
1021 FirstUndefinedSymbol, NumUndefinedSymbols,
1022 IndirectSymbolOffset, NumIndirectSymbols);
1023 }
1024
1025 // Write the linker options load commands.
1026 for (const auto &Option : LinkerOptions)
1027 writeLinkerOptionsLoadCommand(Options: Option);
1028
1029 // Write the actual section data.
1030 for (const MCSection &Sec : Asm) {
1031 Asm.writeSectionData(OS&: W.OS, Section: &Sec);
1032
1033 uint64_t Pad = getPaddingSize(Asm, Sec: &Sec);
1034 W.OS.write_zeros(NumZeros: Pad);
1035 }
1036
1037 // Write the extra padding.
1038 W.OS.write_zeros(NumZeros: SectionDataPadding);
1039
1040 // Write the relocation entries.
1041 for (const MCSection &Sec : Asm) {
1042 // Write the section relocation entries, in reverse order to match 'as'
1043 // (approximately, the exact algorithm is more complicated than this).
1044 std::vector<RelAndSymbol> &Relocs = Relocations[&Sec];
1045 for (const RelAndSymbol &Rel : llvm::reverse(C&: Relocs)) {
1046 W.write<uint32_t>(Val: Rel.MRE.r_word0);
1047 W.write<uint32_t>(Val: Rel.MRE.r_word1);
1048 }
1049 }
1050
1051 // Write out the data-in-code region payload, if there is one.
1052 for (DataRegionData Data : DataRegions) {
1053 uint64_t Start = getSymbolAddress(S: *Data.Start);
1054 uint64_t End;
1055 if (Data.End)
1056 End = getSymbolAddress(S: *Data.End);
1057 else
1058 report_fatal_error(reason: "Data region not terminated");
1059
1060 LLVM_DEBUG(dbgs() << "data in code region-- kind: " << Data.Kind
1061 << " start: " << Start << "(" << Data.Start->getName()
1062 << ")" << " end: " << End << "(" << Data.End->getName()
1063 << ")" << " size: " << End - Start << "\n");
1064 W.write<uint32_t>(Val: Start);
1065 W.write<uint16_t>(Val: End - Start);
1066 W.write<uint16_t>(Val: Data.Kind);
1067 }
1068
1069 // Write out the loh commands, if there is one.
1070 if (LOHSize) {
1071#ifndef NDEBUG
1072 unsigned Start = W.OS.tell();
1073#endif
1074 LOHContainer.emit(Asm, ObjWriter&: *this);
1075 // Pad to a multiple of the pointer size.
1076 W.OS.write_zeros(
1077 NumZeros: offsetToAlignment(Value: LOHRawSize, Alignment: is64Bit() ? Align(8) : Align(4)));
1078 assert(W.OS.tell() - Start == LOHSize);
1079 }
1080
1081 // Write the symbol table data, if used.
1082 if (NumSymbols) {
1083 // Write the indirect symbol entries.
1084 for (auto &ISD : IndirectSymbols) {
1085 // Indirect symbols in the non-lazy symbol pointer section have some
1086 // special handling.
1087 const MCSectionMachO &Section =
1088 static_cast<const MCSectionMachO &>(*ISD.Section);
1089 if (Section.getType() == MachO::S_NON_LAZY_SYMBOL_POINTERS) {
1090 // If this symbol is defined and internal, mark it as such.
1091 if (ISD.Symbol->isDefined() && !ISD.Symbol->isExternal()) {
1092 uint32_t Flags = MachO::INDIRECT_SYMBOL_LOCAL;
1093 if (ISD.Symbol->isAbsolute())
1094 Flags |= MachO::INDIRECT_SYMBOL_ABS;
1095 W.write<uint32_t>(Val: Flags);
1096 continue;
1097 }
1098 }
1099
1100 W.write<uint32_t>(Val: ISD.Symbol->getIndex());
1101 }
1102
1103 // FIXME: Check that offsets match computed ones.
1104
1105 // Write the symbol table entries.
1106 for (auto *SymbolData :
1107 {&LocalSymbolData, &ExternalSymbolData, &UndefinedSymbolData})
1108 for (MachSymbolData &Entry : *SymbolData)
1109 writeNlist(MSD&: Entry, Asm);
1110
1111 // Write the string table.
1112 StringTable.write(OS&: W.OS);
1113 }
1114
1115 return NumBytesWritten();
1116}
1117