Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/ObjCopy/MachO/MachOWriter.cpp
35269 views
1
//===- MachOWriter.cpp ------------------------------------------*- 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
#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"
18
#include <memory>
19
20
#if defined(__APPLE__)
21
#include <sys/mman.h>
22
#endif
23
24
using namespace llvm;
25
using namespace llvm::objcopy::macho;
26
using namespace llvm::support::endian;
27
28
size_t MachOWriter::headerSize() const {
29
return Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
30
}
31
32
size_t MachOWriter::loadCommandsSize() const { return O.Header.SizeOfCmds; }
33
34
size_t MachOWriter::symTableSize() const {
35
return O.SymTable.Symbols.size() *
36
(Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist));
37
}
38
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).
43
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);
53
}
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);
62
}
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);
67
}
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);
73
}
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);
79
}
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);
84
}
85
}
86
87
if (O.DySymTabCommandIndex) {
88
const MachO::dysymtab_command &DySymTabCommand =
89
O.LoadCommands[*O.DySymTabCommandIndex]
90
.MachOLoadCommand.dysymtab_command_data;
91
92
if (DySymTabCommand.indirectsymoff)
93
Ends.push_back(DySymTabCommand.indirectsymoff +
94
sizeof(uint32_t) * O.IndirectSymTable.Symbols.size());
95
}
96
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);
109
}
110
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");
118
continue;
119
}
120
assert((S->Offset != 0) &&
121
"Non-zero-fill section's offset cannot be zero");
122
Ends.push_back(S->Offset + S->Size);
123
if (S->RelOff)
124
Ends.push_back(S->RelOff +
125
S->NReloc * sizeof(MachO::any_relocation_info));
126
}
127
128
if (!Ends.empty())
129
return *llvm::max_element(Ends);
130
131
// Otherwise, we have only Mach header and load commands.
132
return headerSize() + loadCommandsSize();
133
}
134
135
void MachOWriter::writeHeader() {
136
MachO::mach_header_64 Header;
137
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;
146
147
if (IsLittleEndian != sys::IsLittleEndianHost)
148
MachO::swapStruct(Header);
149
150
auto HeaderSize =
151
Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
152
memcpy(Buf->getBufferStart(), &Header, HeaderSize);
153
}
154
155
void MachOWriter::writeLoadCommands() {
156
uint8_t *Begin =
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);
167
168
for (const std::unique_ptr<Section> &Sec : LC.Sections)
169
writeSectionInLoadCommand<MachO::section>(*Sec, Begin);
170
continue;
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);
177
178
for (const std::unique_ptr<Section> &Sec : LC.Sections)
179
writeSectionInLoadCommand<MachO::section_64>(*Sec, Begin);
180
continue;
181
}
182
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(); \
194
break;
195
196
// Copy the load command as it is.
197
switch (MLC.load_command_data.cmd) {
198
default:
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();
208
break;
209
#include "llvm/BinaryFormat/MachO.def"
210
}
211
}
212
}
213
214
template <typename StructType>
215
void MachOWriter::writeSectionInLoadCommand(const Section &Sec, uint8_t *&Out) {
216
StructType Temp;
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;
232
233
if (IsLittleEndian != sys::IsLittleEndianHost)
234
MachO::swapStruct(Temp);
235
memcpy(Out, &Temp, sizeof(StructType));
236
Out += sizeof(StructType);
237
}
238
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");
246
continue;
247
}
248
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);
260
}
261
if (IsLittleEndian != sys::IsLittleEndianHost)
262
MachO::swapStruct(
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));
267
}
268
}
269
}
270
271
template <typename NListType>
272
void writeNListEntry(const SymbolEntry &SE, bool IsLittleEndian, char *&Out,
273
uint32_t Nstrx) {
274
NListType ListEntry;
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;
280
281
if (IsLittleEndian != sys::IsLittleEndianHost)
282
MachO::swapStruct(ListEntry);
283
memcpy(Out, reinterpret_cast<const char *>(&ListEntry), sizeof(NListType));
284
Out += sizeof(NListType);
285
}
286
287
void MachOWriter::writeStringTable() {
288
if (!O.SymTabCommandIndex)
289
return;
290
const MachO::symtab_command &SymTabCommand =
291
O.LoadCommands[*O.SymTabCommandIndex]
292
.MachOLoadCommand.symtab_command_data;
293
294
uint8_t *StrTable = (uint8_t *)Buf->getBufferStart() + SymTabCommand.stroff;
295
LayoutBuilder.getStringTableBuilder().write(StrTable);
296
}
297
298
void MachOWriter::writeSymbolTable() {
299
if (!O.SymTabCommandIndex)
300
return;
301
const MachO::symtab_command &SymTabCommand =
302
O.LoadCommands[*O.SymTabCommandIndex]
303
.MachOLoadCommand.symtab_command_data;
304
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);
309
310
if (Is64Bit)
311
writeNListEntry<MachO::nlist_64>(*Sym, IsLittleEndian, SymTable, Nstrx);
312
else
313
writeNListEntry<MachO::nlist>(*Sym, IsLittleEndian, SymTable, Nstrx);
314
}
315
}
316
317
void MachOWriter::writeRebaseInfo() {
318
if (!O.DyLdInfoCommandIndex)
319
return;
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());
327
}
328
329
void MachOWriter::writeBindInfo() {
330
if (!O.DyLdInfoCommandIndex)
331
return;
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());
339
}
340
341
void MachOWriter::writeWeakBindInfo() {
342
if (!O.DyLdInfoCommandIndex)
343
return;
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());
351
}
352
353
void MachOWriter::writeLazyBindInfo() {
354
if (!O.DyLdInfoCommandIndex)
355
return;
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());
363
}
364
365
void MachOWriter::writeExportInfo() {
366
if (!O.DyLdInfoCommandIndex)
367
return;
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());
375
}
376
377
void MachOWriter::writeIndirectSymbolTable() {
378
if (!O.DySymTabCommandIndex)
379
return;
380
381
const MachO::dysymtab_command &DySymTabCommand =
382
O.LoadCommands[*O.DySymTabCommandIndex]
383
.MachOLoadCommand.dysymtab_command_data;
384
385
uint32_t *Out =
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);
391
*Out++ = Entry;
392
}
393
}
394
395
void MachOWriter::writeLinkData(std::optional<size_t> LCIndex,
396
const LinkData &LD) {
397
if (!LCIndex)
398
return;
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());
405
}
406
407
static uint64_t
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;
416
default:
417
return 0;
418
}
419
}
420
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;
429
default:
430
return 0;
431
}
432
}
433
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.
440
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
446
// (HashReadEnd).
447
448
const CodeSignatureInfo &CodeSignature = LayoutBuilder.getCodeSignature();
449
450
uint8_t *BufferStart = reinterpret_cast<uint8_t *>(Buf->getBufferStart());
451
uint8_t *HashReadStart = BufferStart;
452
uint8_t *HashReadEnd = BufferStart + CodeSignature.StartOffset;
453
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;
457
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 ==
464
MachO::LC_SEGMENT ||
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);
471
}
472
473
const uint32_t FileNamePad = CodeSignature.AllHeadersSize -
474
CodeSignature.FixedHeadersSize -
475
CodeSignature.OutputFileName.size();
476
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
512
: 0);
513
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);
518
519
// Write the hashes.
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)));
527
SHA256 Hasher;
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;
534
}
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
538
//
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,
547
MS_INVALIDATE);
548
#endif
549
}
550
551
void MachOWriter::writeDataInCodeData() {
552
return writeLinkData(O.DataInCodeCommandIndex, O.DataInCode);
553
}
554
555
void MachOWriter::writeLinkerOptimizationHint() {
556
return writeLinkData(O.LinkerOptimizationHintCommandIndex,
557
O.LinkerOptimizationHint);
558
}
559
560
void MachOWriter::writeFunctionStartsData() {
561
return writeLinkData(O.FunctionStartsCommandIndex, O.FunctionStarts);
562
}
563
564
void MachOWriter::writeDylibCodeSignDRsData() {
565
return writeLinkData(O.DylibCodeSignDRsIndex, O.DylibCodeSignDRs);
566
}
567
568
void MachOWriter::writeChainedFixupsData() {
569
return writeLinkData(O.ChainedFixupsCommandIndex, O.ChainedFixups);
570
}
571
572
void MachOWriter::writeExportsTrieData() {
573
if (!O.ExportsTrieCommandIndex)
574
return;
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());
582
}
583
584
void MachOWriter::writeTail() {
585
typedef void (MachOWriter::*WriteHandlerType)();
586
typedef std::pair<uint64_t, WriteHandlerType> WriteOperation;
587
SmallVector<WriteOperation, 7> Queue;
588
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});
597
}
598
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)
604
Queue.push_back(
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)
609
Queue.push_back(
610
{DyLdInfoCommand.weak_bind_off, &MachOWriter::writeWeakBindInfo});
611
if (DyLdInfoCommand.lazy_bind_off)
612
Queue.push_back(
613
{DyLdInfoCommand.lazy_bind_off, &MachOWriter::writeLazyBindInfo});
614
if (DyLdInfoCommand.export_off)
615
Queue.push_back(
616
{DyLdInfoCommand.export_off, &MachOWriter::writeExportInfo});
617
}
618
619
if (O.DySymTabCommandIndex) {
620
const MachO::dysymtab_command &DySymTabCommand =
621
O.LoadCommands[*O.DySymTabCommandIndex]
622
.MachOLoadCommand.dysymtab_command_data;
623
624
if (DySymTabCommand.indirectsymoff)
625
Queue.emplace_back(DySymTabCommand.indirectsymoff,
626
&MachOWriter::writeIndirectSymbolTable);
627
}
628
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);
649
}
650
}
651
652
llvm::sort(Queue, llvm::less_first());
653
654
for (auto WriteOp : Queue)
655
(this->*WriteOp.second)();
656
}
657
658
Error MachOWriter::finalize() { return LayoutBuilder.layout(); }
659
660
Error MachOWriter::write() {
661
size_t TotalSize = totalSize();
662
Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize);
663
if (!Buf)
664
return createStringError(errc::not_enough_memory,
665
"failed to allocate memory buffer of " +
666
Twine::utohexstr(TotalSize) + " bytes");
667
writeHeader();
668
writeLoadCommands();
669
writeSections();
670
writeTail();
671
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();
676
}
677
678