1 //===- MachOWriter.cpp ------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "MachOWriter.h"
10 #include "MachOLayoutBuilder.h"
11 #include "MachOObject.h"
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/BinaryFormat/MachO.h"
14 #include "llvm/Object/MachO.h"
15 #include "llvm/Support/Errc.h"
16 #include "llvm/Support/ErrorHandling.h"
17 #include "llvm/Support/SHA256.h"
20 #if defined(__APPLE__)
25 using namespace llvm::objcopy::macho
;
26 using namespace llvm::support::endian
;
28 size_t MachOWriter::headerSize() const {
29 return Is64Bit
? sizeof(MachO::mach_header_64
) : sizeof(MachO::mach_header
);
32 size_t MachOWriter::loadCommandsSize() const { return O
.Header
.SizeOfCmds
; }
34 size_t MachOWriter::symTableSize() const {
35 return O
.SymTable
.Symbols
.size() *
36 (Is64Bit
? sizeof(MachO::nlist_64
) : sizeof(MachO::nlist
));
39 size_t MachOWriter::totalSize() const {
40 // Going from tail to head and looking for an appropriate "anchor" to
41 // calculate the total size assuming that all the offsets are either valid
42 // ("true") or 0 (0 indicates that the corresponding part is missing).
44 SmallVector
<size_t, 7> Ends
;
45 if (O
.SymTabCommandIndex
) {
46 const MachO::symtab_command
&SymTabCommand
=
47 O
.LoadCommands
[*O
.SymTabCommandIndex
]
48 .MachOLoadCommand
.symtab_command_data
;
49 if (SymTabCommand
.symoff
)
50 Ends
.push_back(SymTabCommand
.symoff
+ symTableSize());
51 if (SymTabCommand
.stroff
)
52 Ends
.push_back(SymTabCommand
.stroff
+ SymTabCommand
.strsize
);
54 if (O
.DyLdInfoCommandIndex
) {
55 const MachO::dyld_info_command
&DyLdInfoCommand
=
56 O
.LoadCommands
[*O
.DyLdInfoCommandIndex
]
57 .MachOLoadCommand
.dyld_info_command_data
;
58 if (DyLdInfoCommand
.rebase_off
) {
59 assert((DyLdInfoCommand
.rebase_size
== O
.Rebases
.Opcodes
.size()) &&
60 "Incorrect rebase opcodes size");
61 Ends
.push_back(DyLdInfoCommand
.rebase_off
+ DyLdInfoCommand
.rebase_size
);
63 if (DyLdInfoCommand
.bind_off
) {
64 assert((DyLdInfoCommand
.bind_size
== O
.Binds
.Opcodes
.size()) &&
65 "Incorrect bind opcodes size");
66 Ends
.push_back(DyLdInfoCommand
.bind_off
+ DyLdInfoCommand
.bind_size
);
68 if (DyLdInfoCommand
.weak_bind_off
) {
69 assert((DyLdInfoCommand
.weak_bind_size
== O
.WeakBinds
.Opcodes
.size()) &&
70 "Incorrect weak bind opcodes size");
71 Ends
.push_back(DyLdInfoCommand
.weak_bind_off
+
72 DyLdInfoCommand
.weak_bind_size
);
74 if (DyLdInfoCommand
.lazy_bind_off
) {
75 assert((DyLdInfoCommand
.lazy_bind_size
== O
.LazyBinds
.Opcodes
.size()) &&
76 "Incorrect lazy bind opcodes size");
77 Ends
.push_back(DyLdInfoCommand
.lazy_bind_off
+
78 DyLdInfoCommand
.lazy_bind_size
);
80 if (DyLdInfoCommand
.export_off
) {
81 assert((DyLdInfoCommand
.export_size
== O
.Exports
.Trie
.size()) &&
82 "Incorrect trie size");
83 Ends
.push_back(DyLdInfoCommand
.export_off
+ DyLdInfoCommand
.export_size
);
87 if (O
.DySymTabCommandIndex
) {
88 const MachO::dysymtab_command
&DySymTabCommand
=
89 O
.LoadCommands
[*O
.DySymTabCommandIndex
]
90 .MachOLoadCommand
.dysymtab_command_data
;
92 if (DySymTabCommand
.indirectsymoff
)
93 Ends
.push_back(DySymTabCommand
.indirectsymoff
+
94 sizeof(uint32_t) * O
.IndirectSymTable
.Symbols
.size());
97 for (std::optional
<size_t> LinkEditDataCommandIndex
:
98 {O
.CodeSignatureCommandIndex
, O
.DylibCodeSignDRsIndex
,
99 O
.DataInCodeCommandIndex
, O
.LinkerOptimizationHintCommandIndex
,
100 O
.FunctionStartsCommandIndex
, O
.ChainedFixupsCommandIndex
,
101 O
.ExportsTrieCommandIndex
})
102 if (LinkEditDataCommandIndex
) {
103 const MachO::linkedit_data_command
&LinkEditDataCommand
=
104 O
.LoadCommands
[*LinkEditDataCommandIndex
]
105 .MachOLoadCommand
.linkedit_data_command_data
;
106 if (LinkEditDataCommand
.dataoff
)
107 Ends
.push_back(LinkEditDataCommand
.dataoff
+
108 LinkEditDataCommand
.datasize
);
111 // Otherwise, use the last section / reloction.
112 for (const LoadCommand
&LC
: O
.LoadCommands
)
113 for (const std::unique_ptr
<Section
> &S
: LC
.Sections
) {
114 if (!S
->hasValidOffset()) {
115 assert((S
->Offset
== 0) && "Skipped section's offset must be zero");
116 assert((S
->isVirtualSection() || S
->Size
== 0) &&
117 "Non-zero-fill sections with zero offset must have zero size");
120 assert((S
->Offset
!= 0) &&
121 "Non-zero-fill section's offset cannot be zero");
122 Ends
.push_back(S
->Offset
+ S
->Size
);
124 Ends
.push_back(S
->RelOff
+
125 S
->NReloc
* sizeof(MachO::any_relocation_info
));
129 return *std::max_element(Ends
.begin(), Ends
.end());
131 // Otherwise, we have only Mach header and load commands.
132 return headerSize() + loadCommandsSize();
135 void MachOWriter::writeHeader() {
136 MachO::mach_header_64 Header
;
138 Header
.magic
= O
.Header
.Magic
;
139 Header
.cputype
= O
.Header
.CPUType
;
140 Header
.cpusubtype
= O
.Header
.CPUSubType
;
141 Header
.filetype
= O
.Header
.FileType
;
142 Header
.ncmds
= O
.Header
.NCmds
;
143 Header
.sizeofcmds
= O
.Header
.SizeOfCmds
;
144 Header
.flags
= O
.Header
.Flags
;
145 Header
.reserved
= O
.Header
.Reserved
;
147 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
148 MachO::swapStruct(Header
);
151 Is64Bit
? sizeof(MachO::mach_header_64
) : sizeof(MachO::mach_header
);
152 memcpy(Buf
->getBufferStart(), &Header
, HeaderSize
);
155 void MachOWriter::writeLoadCommands() {
157 reinterpret_cast<uint8_t *>(Buf
->getBufferStart()) + headerSize();
158 for (const LoadCommand
&LC
: O
.LoadCommands
) {
159 // Construct a load command.
160 MachO::macho_load_command MLC
= LC
.MachOLoadCommand
;
161 switch (MLC
.load_command_data
.cmd
) {
162 case MachO::LC_SEGMENT
:
163 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
164 MachO::swapStruct(MLC
.segment_command_data
);
165 memcpy(Begin
, &MLC
.segment_command_data
, sizeof(MachO::segment_command
));
166 Begin
+= sizeof(MachO::segment_command
);
168 for (const std::unique_ptr
<Section
> &Sec
: LC
.Sections
)
169 writeSectionInLoadCommand
<MachO::section
>(*Sec
, Begin
);
171 case MachO::LC_SEGMENT_64
:
172 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
173 MachO::swapStruct(MLC
.segment_command_64_data
);
174 memcpy(Begin
, &MLC
.segment_command_64_data
,
175 sizeof(MachO::segment_command_64
));
176 Begin
+= sizeof(MachO::segment_command_64
);
178 for (const std::unique_ptr
<Section
> &Sec
: LC
.Sections
)
179 writeSectionInLoadCommand
<MachO::section_64
>(*Sec
, Begin
);
183 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
184 case MachO::LCName: \
185 assert(sizeof(MachO::LCStruct) + LC.Payload.size() == \
186 MLC.load_command_data.cmdsize); \
187 if (IsLittleEndian != sys::IsLittleEndianHost) \
188 MachO::swapStruct(MLC.LCStruct##_data); \
189 memcpy(Begin, &MLC.LCStruct##_data, sizeof(MachO::LCStruct)); \
190 Begin += sizeof(MachO::LCStruct); \
191 if (!LC.Payload.empty()) \
192 memcpy(Begin, LC.Payload.data(), LC.Payload.size()); \
193 Begin += LC.Payload.size(); \
196 // Copy the load command as it is.
197 switch (MLC
.load_command_data
.cmd
) {
199 assert(sizeof(MachO::load_command
) + LC
.Payload
.size() ==
200 MLC
.load_command_data
.cmdsize
);
201 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
202 MachO::swapStruct(MLC
.load_command_data
);
203 memcpy(Begin
, &MLC
.load_command_data
, sizeof(MachO::load_command
));
204 Begin
+= sizeof(MachO::load_command
);
205 if (!LC
.Payload
.empty())
206 memcpy(Begin
, LC
.Payload
.data(), LC
.Payload
.size());
207 Begin
+= LC
.Payload
.size();
209 #include "llvm/BinaryFormat/MachO.def"
214 template <typename StructType
>
215 void MachOWriter::writeSectionInLoadCommand(const Section
&Sec
, uint8_t *&Out
) {
217 assert(Sec
.Segname
.size() <= sizeof(Temp
.segname
) && "too long segment name");
218 assert(Sec
.Sectname
.size() <= sizeof(Temp
.sectname
) &&
219 "too long section name");
220 memset(&Temp
, 0, sizeof(StructType
));
221 memcpy(Temp
.segname
, Sec
.Segname
.data(), Sec
.Segname
.size());
222 memcpy(Temp
.sectname
, Sec
.Sectname
.data(), Sec
.Sectname
.size());
223 Temp
.addr
= Sec
.Addr
;
224 Temp
.size
= Sec
.Size
;
225 Temp
.offset
= Sec
.Offset
;
226 Temp
.align
= Sec
.Align
;
227 Temp
.reloff
= Sec
.RelOff
;
228 Temp
.nreloc
= Sec
.NReloc
;
229 Temp
.flags
= Sec
.Flags
;
230 Temp
.reserved1
= Sec
.Reserved1
;
231 Temp
.reserved2
= Sec
.Reserved2
;
233 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
234 MachO::swapStruct(Temp
);
235 memcpy(Out
, &Temp
, sizeof(StructType
));
236 Out
+= sizeof(StructType
);
239 void MachOWriter::writeSections() {
240 for (const LoadCommand
&LC
: O
.LoadCommands
)
241 for (const std::unique_ptr
<Section
> &Sec
: LC
.Sections
) {
242 if (!Sec
->hasValidOffset()) {
243 assert((Sec
->Offset
== 0) && "Skipped section's offset must be zero");
244 assert((Sec
->isVirtualSection() || Sec
->Size
== 0) &&
245 "Non-zero-fill sections with zero offset must have zero size");
249 assert(Sec
->Offset
&& "Section offset can not be zero");
250 assert((Sec
->Size
== Sec
->Content
.size()) && "Incorrect section size");
251 memcpy(Buf
->getBufferStart() + Sec
->Offset
, Sec
->Content
.data(),
252 Sec
->Content
.size());
253 for (size_t Index
= 0; Index
< Sec
->Relocations
.size(); ++Index
) {
254 RelocationInfo RelocInfo
= Sec
->Relocations
[Index
];
255 if (!RelocInfo
.Scattered
&& !RelocInfo
.IsAddend
) {
256 const uint32_t SymbolNum
= RelocInfo
.Extern
257 ? (*RelocInfo
.Symbol
)->Index
258 : (*RelocInfo
.Sec
)->Index
;
259 RelocInfo
.setPlainRelocationSymbolNum(SymbolNum
, IsLittleEndian
);
261 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
263 reinterpret_cast<MachO::any_relocation_info
&>(RelocInfo
.Info
));
264 memcpy(Buf
->getBufferStart() + Sec
->RelOff
+
265 Index
* sizeof(MachO::any_relocation_info
),
266 &RelocInfo
.Info
, sizeof(RelocInfo
.Info
));
271 template <typename NListType
>
272 void writeNListEntry(const SymbolEntry
&SE
, bool IsLittleEndian
, char *&Out
,
275 ListEntry
.n_strx
= Nstrx
;
276 ListEntry
.n_type
= SE
.n_type
;
277 ListEntry
.n_sect
= SE
.n_sect
;
278 ListEntry
.n_desc
= SE
.n_desc
;
279 ListEntry
.n_value
= SE
.n_value
;
281 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
282 MachO::swapStruct(ListEntry
);
283 memcpy(Out
, reinterpret_cast<const char *>(&ListEntry
), sizeof(NListType
));
284 Out
+= sizeof(NListType
);
287 void MachOWriter::writeStringTable() {
288 if (!O
.SymTabCommandIndex
)
290 const MachO::symtab_command
&SymTabCommand
=
291 O
.LoadCommands
[*O
.SymTabCommandIndex
]
292 .MachOLoadCommand
.symtab_command_data
;
294 uint8_t *StrTable
= (uint8_t *)Buf
->getBufferStart() + SymTabCommand
.stroff
;
295 LayoutBuilder
.getStringTableBuilder().write(StrTable
);
298 void MachOWriter::writeSymbolTable() {
299 if (!O
.SymTabCommandIndex
)
301 const MachO::symtab_command
&SymTabCommand
=
302 O
.LoadCommands
[*O
.SymTabCommandIndex
]
303 .MachOLoadCommand
.symtab_command_data
;
305 char *SymTable
= (char *)Buf
->getBufferStart() + SymTabCommand
.symoff
;
306 for (auto &Symbol
: O
.SymTable
.Symbols
) {
307 SymbolEntry
*Sym
= Symbol
.get();
308 uint32_t Nstrx
= LayoutBuilder
.getStringTableBuilder().getOffset(Sym
->Name
);
311 writeNListEntry
<MachO::nlist_64
>(*Sym
, IsLittleEndian
, SymTable
, Nstrx
);
313 writeNListEntry
<MachO::nlist
>(*Sym
, IsLittleEndian
, SymTable
, Nstrx
);
317 void MachOWriter::writeRebaseInfo() {
318 if (!O
.DyLdInfoCommandIndex
)
320 const MachO::dyld_info_command
&DyLdInfoCommand
=
321 O
.LoadCommands
[*O
.DyLdInfoCommandIndex
]
322 .MachOLoadCommand
.dyld_info_command_data
;
323 char *Out
= (char *)Buf
->getBufferStart() + DyLdInfoCommand
.rebase_off
;
324 assert((DyLdInfoCommand
.rebase_size
== O
.Rebases
.Opcodes
.size()) &&
325 "Incorrect rebase opcodes size");
326 memcpy(Out
, O
.Rebases
.Opcodes
.data(), O
.Rebases
.Opcodes
.size());
329 void MachOWriter::writeBindInfo() {
330 if (!O
.DyLdInfoCommandIndex
)
332 const MachO::dyld_info_command
&DyLdInfoCommand
=
333 O
.LoadCommands
[*O
.DyLdInfoCommandIndex
]
334 .MachOLoadCommand
.dyld_info_command_data
;
335 char *Out
= (char *)Buf
->getBufferStart() + DyLdInfoCommand
.bind_off
;
336 assert((DyLdInfoCommand
.bind_size
== O
.Binds
.Opcodes
.size()) &&
337 "Incorrect bind opcodes size");
338 memcpy(Out
, O
.Binds
.Opcodes
.data(), O
.Binds
.Opcodes
.size());
341 void MachOWriter::writeWeakBindInfo() {
342 if (!O
.DyLdInfoCommandIndex
)
344 const MachO::dyld_info_command
&DyLdInfoCommand
=
345 O
.LoadCommands
[*O
.DyLdInfoCommandIndex
]
346 .MachOLoadCommand
.dyld_info_command_data
;
347 char *Out
= (char *)Buf
->getBufferStart() + DyLdInfoCommand
.weak_bind_off
;
348 assert((DyLdInfoCommand
.weak_bind_size
== O
.WeakBinds
.Opcodes
.size()) &&
349 "Incorrect weak bind opcodes size");
350 memcpy(Out
, O
.WeakBinds
.Opcodes
.data(), O
.WeakBinds
.Opcodes
.size());
353 void MachOWriter::writeLazyBindInfo() {
354 if (!O
.DyLdInfoCommandIndex
)
356 const MachO::dyld_info_command
&DyLdInfoCommand
=
357 O
.LoadCommands
[*O
.DyLdInfoCommandIndex
]
358 .MachOLoadCommand
.dyld_info_command_data
;
359 char *Out
= (char *)Buf
->getBufferStart() + DyLdInfoCommand
.lazy_bind_off
;
360 assert((DyLdInfoCommand
.lazy_bind_size
== O
.LazyBinds
.Opcodes
.size()) &&
361 "Incorrect lazy bind opcodes size");
362 memcpy(Out
, O
.LazyBinds
.Opcodes
.data(), O
.LazyBinds
.Opcodes
.size());
365 void MachOWriter::writeExportInfo() {
366 if (!O
.DyLdInfoCommandIndex
)
368 const MachO::dyld_info_command
&DyLdInfoCommand
=
369 O
.LoadCommands
[*O
.DyLdInfoCommandIndex
]
370 .MachOLoadCommand
.dyld_info_command_data
;
371 char *Out
= (char *)Buf
->getBufferStart() + DyLdInfoCommand
.export_off
;
372 assert((DyLdInfoCommand
.export_size
== O
.Exports
.Trie
.size()) &&
373 "Incorrect export trie size");
374 memcpy(Out
, O
.Exports
.Trie
.data(), O
.Exports
.Trie
.size());
377 void MachOWriter::writeIndirectSymbolTable() {
378 if (!O
.DySymTabCommandIndex
)
381 const MachO::dysymtab_command
&DySymTabCommand
=
382 O
.LoadCommands
[*O
.DySymTabCommandIndex
]
383 .MachOLoadCommand
.dysymtab_command_data
;
386 (uint32_t *)(Buf
->getBufferStart() + DySymTabCommand
.indirectsymoff
);
387 for (const IndirectSymbolEntry
&Sym
: O
.IndirectSymTable
.Symbols
) {
388 uint32_t Entry
= (Sym
.Symbol
) ? (*Sym
.Symbol
)->Index
: Sym
.OriginalIndex
;
389 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
390 sys::swapByteOrder(Entry
);
395 void MachOWriter::writeLinkData(std::optional
<size_t> LCIndex
,
396 const LinkData
&LD
) {
399 const MachO::linkedit_data_command
&LinkEditDataCommand
=
400 O
.LoadCommands
[*LCIndex
].MachOLoadCommand
.linkedit_data_command_data
;
401 char *Out
= (char *)Buf
->getBufferStart() + LinkEditDataCommand
.dataoff
;
402 assert((LinkEditDataCommand
.datasize
== LD
.Data
.size()) &&
403 "Incorrect data size");
404 memcpy(Out
, LD
.Data
.data(), LD
.Data
.size());
408 getSegmentFileOffset(const LoadCommand
&TextSegmentLoadCommand
) {
409 const MachO::macho_load_command
&MLC
=
410 TextSegmentLoadCommand
.MachOLoadCommand
;
411 switch (MLC
.load_command_data
.cmd
) {
412 case MachO::LC_SEGMENT
:
413 return MLC
.segment_command_data
.fileoff
;
414 case MachO::LC_SEGMENT_64
:
415 return MLC
.segment_command_64_data
.fileoff
;
421 static uint64_t getSegmentFileSize(const LoadCommand
&TextSegmentLoadCommand
) {
422 const MachO::macho_load_command
&MLC
=
423 TextSegmentLoadCommand
.MachOLoadCommand
;
424 switch (MLC
.load_command_data
.cmd
) {
425 case MachO::LC_SEGMENT
:
426 return MLC
.segment_command_data
.filesize
;
427 case MachO::LC_SEGMENT_64
:
428 return MLC
.segment_command_64_data
.filesize
;
434 void MachOWriter::writeCodeSignatureData() {
435 // NOTE: This CodeSignature section behaviour must be kept in sync with that
436 // performed in LLD's CodeSignatureSection::write /
437 // CodeSignatureSection::writeHashes. Furthermore, this call must occur only
438 // after the rest of the binary has already been written to the buffer. This
439 // is because the buffer is read from to perform the necessary hashing.
441 // The CodeSignature section is the last section in the MachO binary and
442 // contains a hash of all content in the binary before it. Since llvm-objcopy
443 // has likely modified the target binary, the hash must be regenerated
444 // entirely. To generate this hash, we must read from the start of the binary
445 // (HashReadStart) to just before the start of the CodeSignature section
448 const CodeSignatureInfo
&CodeSignature
= LayoutBuilder
.getCodeSignature();
450 uint8_t *BufferStart
= reinterpret_cast<uint8_t *>(Buf
->getBufferStart());
451 uint8_t *HashReadStart
= BufferStart
;
452 uint8_t *HashReadEnd
= BufferStart
+ CodeSignature
.StartOffset
;
454 // The CodeSignature section begins with a header, after which the hashes
455 // of each page of the binary are written.
456 uint8_t *HashWriteStart
= HashReadEnd
+ CodeSignature
.AllHeadersSize
;
458 uint32_t TextSegmentFileOff
= 0;
459 uint32_t TextSegmentFileSize
= 0;
460 if (O
.TextSegmentCommandIndex
) {
461 const LoadCommand
&TextSegmentLoadCommand
=
462 O
.LoadCommands
[*O
.TextSegmentCommandIndex
];
463 assert(TextSegmentLoadCommand
.MachOLoadCommand
.load_command_data
.cmd
==
465 TextSegmentLoadCommand
.MachOLoadCommand
.load_command_data
.cmd
==
466 MachO::LC_SEGMENT_64
);
467 assert(StringRef(TextSegmentLoadCommand
.MachOLoadCommand
468 .segment_command_data
.segname
) == "__TEXT");
469 TextSegmentFileOff
= getSegmentFileOffset(TextSegmentLoadCommand
);
470 TextSegmentFileSize
= getSegmentFileSize(TextSegmentLoadCommand
);
473 const uint32_t FileNamePad
= CodeSignature
.AllHeadersSize
-
474 CodeSignature
.FixedHeadersSize
-
475 CodeSignature
.OutputFileName
.size();
477 // Write code section header.
478 auto *SuperBlob
= reinterpret_cast<MachO::CS_SuperBlob
*>(HashReadEnd
);
479 write32be(&SuperBlob
->magic
, MachO::CSMAGIC_EMBEDDED_SIGNATURE
);
480 write32be(&SuperBlob
->length
, CodeSignature
.Size
);
481 write32be(&SuperBlob
->count
, 1);
482 auto *BlobIndex
= reinterpret_cast<MachO::CS_BlobIndex
*>(&SuperBlob
[1]);
483 write32be(&BlobIndex
->type
, MachO::CSSLOT_CODEDIRECTORY
);
484 write32be(&BlobIndex
->offset
, CodeSignature
.BlobHeadersSize
);
485 auto *CodeDirectory
= reinterpret_cast<MachO::CS_CodeDirectory
*>(
486 HashReadEnd
+ CodeSignature
.BlobHeadersSize
);
487 write32be(&CodeDirectory
->magic
, MachO::CSMAGIC_CODEDIRECTORY
);
488 write32be(&CodeDirectory
->length
,
489 CodeSignature
.Size
- CodeSignature
.BlobHeadersSize
);
490 write32be(&CodeDirectory
->version
, MachO::CS_SUPPORTSEXECSEG
);
491 write32be(&CodeDirectory
->flags
, MachO::CS_ADHOC
| MachO::CS_LINKER_SIGNED
);
492 write32be(&CodeDirectory
->hashOffset
,
493 sizeof(MachO::CS_CodeDirectory
) +
494 CodeSignature
.OutputFileName
.size() + FileNamePad
);
495 write32be(&CodeDirectory
->identOffset
, sizeof(MachO::CS_CodeDirectory
));
496 CodeDirectory
->nSpecialSlots
= 0;
497 write32be(&CodeDirectory
->nCodeSlots
, CodeSignature
.BlockCount
);
498 write32be(&CodeDirectory
->codeLimit
, CodeSignature
.StartOffset
);
499 CodeDirectory
->hashSize
= static_cast<uint8_t>(CodeSignature
.HashSize
);
500 CodeDirectory
->hashType
= MachO::kSecCodeSignatureHashSHA256
;
501 CodeDirectory
->platform
= 0;
502 CodeDirectory
->pageSize
= CodeSignature
.BlockSizeShift
;
503 CodeDirectory
->spare2
= 0;
504 CodeDirectory
->scatterOffset
= 0;
505 CodeDirectory
->teamOffset
= 0;
506 CodeDirectory
->spare3
= 0;
507 CodeDirectory
->codeLimit64
= 0;
508 write64be(&CodeDirectory
->execSegBase
, TextSegmentFileOff
);
509 write64be(&CodeDirectory
->execSegLimit
, TextSegmentFileSize
);
510 write64be(&CodeDirectory
->execSegFlags
, O
.Header
.FileType
== MachO::MH_EXECUTE
511 ? MachO::CS_EXECSEG_MAIN_BINARY
514 auto *Id
= reinterpret_cast<char *>(&CodeDirectory
[1]);
515 memcpy(Id
, CodeSignature
.OutputFileName
.begin(),
516 CodeSignature
.OutputFileName
.size());
517 memset(Id
+ CodeSignature
.OutputFileName
.size(), 0, FileNamePad
);
520 uint8_t *CurrHashReadPosition
= HashReadStart
;
521 uint8_t *CurrHashWritePosition
= HashWriteStart
;
522 while (CurrHashReadPosition
< HashReadEnd
) {
523 StringRef
Block(reinterpret_cast<char *>(CurrHashReadPosition
),
524 std::min(static_cast<size_t>(HashReadEnd
525 - CurrHashReadPosition
),
526 static_cast<size_t>(CodeSignature
.BlockSize
)));
528 Hasher
.update(Block
);
529 std::array
<uint8_t, 32> Hash
= Hasher
.final();
530 assert(Hash
.size() == CodeSignature
.HashSize
);
531 memcpy(CurrHashWritePosition
, Hash
.data(), CodeSignature
.HashSize
);
532 CurrHashReadPosition
+= CodeSignature
.BlockSize
;
533 CurrHashWritePosition
+= CodeSignature
.HashSize
;
535 #if defined(__APPLE__)
536 // This is macOS-specific work-around and makes no sense for any
537 // other host OS. See https://openradar.appspot.com/FB8914231
539 // The macOS kernel maintains a signature-verification cache to
540 // quickly validate applications at time of execve(2). The trouble
541 // is that for the kernel creates the cache entry at the time of the
542 // mmap(2) call, before we have a chance to write either the code to
543 // sign or the signature header+hashes. The fix is to invalidate
544 // all cached data associated with the output file, thus discarding
545 // the bogus prematurely-cached signature.
546 msync(BufferStart
, CodeSignature
.StartOffset
+ CodeSignature
.Size
,
551 void MachOWriter::writeDataInCodeData() {
552 return writeLinkData(O
.DataInCodeCommandIndex
, O
.DataInCode
);
555 void MachOWriter::writeLinkerOptimizationHint() {
556 return writeLinkData(O
.LinkerOptimizationHintCommandIndex
,
557 O
.LinkerOptimizationHint
);
560 void MachOWriter::writeFunctionStartsData() {
561 return writeLinkData(O
.FunctionStartsCommandIndex
, O
.FunctionStarts
);
564 void MachOWriter::writeDylibCodeSignDRsData() {
565 return writeLinkData(O
.DylibCodeSignDRsIndex
, O
.DylibCodeSignDRs
);
568 void MachOWriter::writeChainedFixupsData() {
569 return writeLinkData(O
.ChainedFixupsCommandIndex
, O
.ChainedFixups
);
572 void MachOWriter::writeExportsTrieData() {
573 if (!O
.ExportsTrieCommandIndex
)
575 const MachO::linkedit_data_command
&ExportsTrieCmd
=
576 O
.LoadCommands
[*O
.ExportsTrieCommandIndex
]
577 .MachOLoadCommand
.linkedit_data_command_data
;
578 char *Out
= (char *)Buf
->getBufferStart() + ExportsTrieCmd
.dataoff
;
579 assert((ExportsTrieCmd
.datasize
== O
.Exports
.Trie
.size()) &&
580 "Incorrect export trie size");
581 memcpy(Out
, O
.Exports
.Trie
.data(), O
.Exports
.Trie
.size());
584 void MachOWriter::writeTail() {
585 typedef void (MachOWriter::*WriteHandlerType
)();
586 typedef std::pair
<uint64_t, WriteHandlerType
> WriteOperation
;
587 SmallVector
<WriteOperation
, 7> Queue
;
589 if (O
.SymTabCommandIndex
) {
590 const MachO::symtab_command
&SymTabCommand
=
591 O
.LoadCommands
[*O
.SymTabCommandIndex
]
592 .MachOLoadCommand
.symtab_command_data
;
593 if (SymTabCommand
.symoff
)
594 Queue
.push_back({SymTabCommand
.symoff
, &MachOWriter::writeSymbolTable
});
595 if (SymTabCommand
.stroff
)
596 Queue
.push_back({SymTabCommand
.stroff
, &MachOWriter::writeStringTable
});
599 if (O
.DyLdInfoCommandIndex
) {
600 const MachO::dyld_info_command
&DyLdInfoCommand
=
601 O
.LoadCommands
[*O
.DyLdInfoCommandIndex
]
602 .MachOLoadCommand
.dyld_info_command_data
;
603 if (DyLdInfoCommand
.rebase_off
)
605 {DyLdInfoCommand
.rebase_off
, &MachOWriter::writeRebaseInfo
});
606 if (DyLdInfoCommand
.bind_off
)
607 Queue
.push_back({DyLdInfoCommand
.bind_off
, &MachOWriter::writeBindInfo
});
608 if (DyLdInfoCommand
.weak_bind_off
)
610 {DyLdInfoCommand
.weak_bind_off
, &MachOWriter::writeWeakBindInfo
});
611 if (DyLdInfoCommand
.lazy_bind_off
)
613 {DyLdInfoCommand
.lazy_bind_off
, &MachOWriter::writeLazyBindInfo
});
614 if (DyLdInfoCommand
.export_off
)
616 {DyLdInfoCommand
.export_off
, &MachOWriter::writeExportInfo
});
619 if (O
.DySymTabCommandIndex
) {
620 const MachO::dysymtab_command
&DySymTabCommand
=
621 O
.LoadCommands
[*O
.DySymTabCommandIndex
]
622 .MachOLoadCommand
.dysymtab_command_data
;
624 if (DySymTabCommand
.indirectsymoff
)
625 Queue
.emplace_back(DySymTabCommand
.indirectsymoff
,
626 &MachOWriter::writeIndirectSymbolTable
);
629 std::initializer_list
<std::pair
<std::optional
<size_t>, WriteHandlerType
>>
630 LinkEditDataCommandWriters
= {
631 {O
.CodeSignatureCommandIndex
, &MachOWriter::writeCodeSignatureData
},
632 {O
.DylibCodeSignDRsIndex
, &MachOWriter::writeDylibCodeSignDRsData
},
633 {O
.DataInCodeCommandIndex
, &MachOWriter::writeDataInCodeData
},
634 {O
.LinkerOptimizationHintCommandIndex
,
635 &MachOWriter::writeLinkerOptimizationHint
},
636 {O
.FunctionStartsCommandIndex
, &MachOWriter::writeFunctionStartsData
},
637 {O
.ChainedFixupsCommandIndex
, &MachOWriter::writeChainedFixupsData
},
638 {O
.ExportsTrieCommandIndex
, &MachOWriter::writeExportsTrieData
}};
639 for (const auto &W
: LinkEditDataCommandWriters
) {
640 std::optional
<size_t> LinkEditDataCommandIndex
;
641 WriteHandlerType WriteHandler
;
642 std::tie(LinkEditDataCommandIndex
, WriteHandler
) = W
;
643 if (LinkEditDataCommandIndex
) {
644 const MachO::linkedit_data_command
&LinkEditDataCommand
=
645 O
.LoadCommands
[*LinkEditDataCommandIndex
]
646 .MachOLoadCommand
.linkedit_data_command_data
;
647 if (LinkEditDataCommand
.dataoff
)
648 Queue
.emplace_back(LinkEditDataCommand
.dataoff
, WriteHandler
);
652 llvm::sort(Queue
, llvm::less_first());
654 for (auto WriteOp
: Queue
)
655 (this->*WriteOp
.second
)();
658 Error
MachOWriter::finalize() { return LayoutBuilder
.layout(); }
660 Error
MachOWriter::write() {
661 size_t TotalSize
= totalSize();
662 Buf
= WritableMemoryBuffer::getNewMemBuffer(TotalSize
);
664 return createStringError(errc::not_enough_memory
,
665 "failed to allocate memory buffer of " +
666 Twine::utohexstr(TotalSize
) + " bytes");
672 // TODO: Implement direct writing to the output stream (without intermediate
673 // memory buffer Buf).
674 Out
.write(Buf
->getBufferStart(), Buf
->getBufferSize());
675 return Error::success();