48 std::vector<MachOYAML::BindOpcode> &BindOpcodes);
70 bool FoundLinkEditSeg =
false;
74 fileStart = OS.
tell();
76 writeLoadCommands(OS);
77 if (
Error Err = writeSectionData(OS))
80 if (!FoundLinkEditSeg)
81 writeLinkEditData(OS);
100 OS.
write((
const char *)&Header, header_size);
103 template <
typename SectionType>
106 memcpy(
reinterpret_cast<void *
>(&TempSec.sectname[0]), &Sec.
sectname[0], 16);
107 memcpy(
reinterpret_cast<void *
>(&TempSec.segname[0]), &Sec.
segname[0], 16);
108 TempSec.addr = Sec.
addr;
109 TempSec.size = Sec.
size;
110 TempSec.offset = Sec.
offset;
111 TempSec.align = Sec.
align;
112 TempSec.reloff = Sec.
reloff;
113 TempSec.nreloc = Sec.
nreloc;
114 TempSec.flags = Sec.
flags;
120 template <
typename StructType>
122 bool IsLittleEndian) {
129 bool IsLittleEndian) {
130 size_t BytesWritten = 0;
131 for (
const auto &Sec : LC.
Sections) {
132 auto TempSec = constructSection<MachO::section>(Sec);
135 OS.
write(
reinterpret_cast<const char *
>(&(TempSec)),
143 size_t writeLoadCommandData<MachO::segment_command_64>(
145 size_t BytesWritten = 0;
146 for (
const auto &Sec : LC.
Sections) {
147 auto TempSec = constructSection<MachO::section_64>(Sec);
151 OS.
write(
reinterpret_cast<const char *
>(&(TempSec)),
159 size_t BytesWritten = 0;
162 BytesWritten = LC.
Content.length();
170 bool IsLittleEndian) {
171 return writePayloadString(LC, OS);
177 bool IsLittleEndian) {
178 return writePayloadString(LC, OS);
184 bool IsLittleEndian) {
185 return writePayloadString(LC, OS);
189 size_t writeLoadCommandData<MachO::sub_framework_command>(
191 return writePayloadString(LC, OS);
195 size_t writeLoadCommandData<MachO::sub_umbrella_command>(
197 return writePayloadString(LC, OS);
201 size_t writeLoadCommandData<MachO::sub_client_command>(
203 return writePayloadString(LC, OS);
207 size_t writeLoadCommandData<MachO::sub_library_command>(
209 return writePayloadString(LC, OS);
213 size_t writeLoadCommandData<MachO::build_version_command>(
215 size_t BytesWritten = 0;
216 for (
const auto &
T : LC.
Tools) {
220 OS.
write(
reinterpret_cast<const char *
>(&tool),
228 std::vector<uint8_t> FillData(
Size, 0);
229 OS.
write(
reinterpret_cast<char *
>(FillData.data()),
Size);
233 std::vector<uint32_t> FillData((
Size / 4) + 1,
Data);
234 OS.
write(
reinterpret_cast<char *
>(FillData.data()),
Size);
238 auto currOffset = OS.
tell() - fileStart;
243 void MachOWriter::writeLoadCommands(
raw_ostream &OS) {
245 size_t BytesWritten = 0;
248 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
249 case MachO::LCName: \
250 if (Obj.IsLittleEndian != sys::IsLittleEndianHost) \
251 MachO::swapStruct(Data.LCStruct##_data); \
252 OS.write(reinterpret_cast<const char *>(&(Data.LCStruct##_data)), \
253 sizeof(MachO::LCStruct)); \
254 BytesWritten = sizeof(MachO::LCStruct); \
256 writeLoadCommandData<MachO::LCStruct>(LC, OS, Obj.IsLittleEndian); \
259 switch (LC.
Data.load_command_data.cmd) {
263 OS.
write(
reinterpret_cast<const char *
>(&(
Data.load_command_data)),
267 writeLoadCommandData<MachO::load_command>(LC, OS, Obj.
IsLittleEndian);
269 #include "llvm/BinaryFormat/MachO.def"
285 auto BytesRemaining = LC.
Data.load_command_data.cmdsize - BytesWritten;
286 if (BytesRemaining > 0) {
295 switch (LC.
Data.load_command_data.cmd) {
296 case MachO::LC_SEGMENT:
297 case MachO::LC_SEGMENT_64:
299 : LC.
Data.segment_command_data.fileoff;
301 strncmp(&LC.
Data.segment_command_data.segname[0],
"__LINKEDIT", 16)) {
302 FoundLinkEditSeg =
true;
303 LinkEditOff = segOff;
306 writeLinkEditData(OS);
309 ZeroToOffset(OS, Sec.
offset);
315 "wrote too much data somewhere, section offsets don't line up");
324 "cannot specify section '" + SectName +
325 "' contents in the 'DWARF' entry and "
326 "the 'content' at the same time");
343 Fill(OS, Sec.
size, 0xDEADBEEFu);
347 : LC.
Data.segment_command_data.filesize;
348 ZeroToOffset(OS, segOff + segSize);
354 ZeroToOffset(OS, LinkEditOff);
355 if (OS.
tell() - fileStart > LinkEditOff || !LinkEditOff)
357 "section offsets don't line up");
369 assert(!
R.is_scattered &&
"non-scattered relocation expected");
373 MRE.
r_word1 = ((unsigned)
R.symbolnum << 0) | ((unsigned)
R.is_pcrel << 24) |
374 ((unsigned)
R.length << 25) | ((unsigned)
R.is_extern << 27) |
375 ((unsigned)
R.type << 28);
377 MRE.
r_word1 = ((unsigned)
R.symbolnum << 8) | ((unsigned)
R.is_pcrel << 7) |
378 ((unsigned)
R.length << 5) | ((unsigned)
R.is_extern << 4) |
379 ((unsigned)
R.type << 0);
385 assert(
R.is_scattered &&
"scattered relocation expected");
387 MRE.
r_word0 = (((unsigned)
R.address << 0) | ((unsigned)
R.type << 24) |
388 ((unsigned)
R.length << 28) | ((unsigned)
R.is_pcrel << 30) |
394 void MachOWriter::writeRelocations(
raw_ostream &OS) {
396 switch (LC.
Data.load_command_data.cmd) {
397 case MachO::LC_SEGMENT:
398 case MachO::LC_SEGMENT_64:
402 ZeroToOffset(OS, Sec.
reloff);
405 R.is_scattered ? makeScatteredRelocationInfo(
R)
406 : makeRelocationInfo(
R, Obj.IsLittleEndian);
409 OS.
write(
reinterpret_cast<const char *
>(&MRE),
417 void MachOWriter::writeBindOpcodes(
418 raw_ostream &OS, std::vector<MachOYAML::BindOpcode> &BindOpcodes) {
420 for (
auto Opcode : BindOpcodes) {
421 uint8_t OpByte = Opcode.Opcode | Opcode.Imm;
422 OS.
write(
reinterpret_cast<char *
>(&OpByte), 1);
423 for (
auto Data : Opcode.ULEBExtraData) {
426 for (
auto Data : Opcode.SLEBExtraData) {
429 if (!Opcode.Symbol.empty()) {
430 OS.
write(Opcode.Symbol.data(), Opcode.Symbol.size());
439 if (Entry.TerminalSize > 0) {
443 OS << Entry.ImportName;
451 OS.
write(
static_cast<uint8_t
>(Entry.Children.size()));
452 for (
auto EE : Entry.Children) {
457 for (
auto EE : Entry.Children)
458 dumpExportEntry(OS, EE);
461 void MachOWriter::writeExportTrie(
raw_ostream &OS) {
465 template <
typename NListType>
467 bool IsLittleEndian) {
469 ListEntry.n_strx = NLE.
n_strx;
470 ListEntry.n_type = NLE.
n_type;
471 ListEntry.n_sect = NLE.
n_sect;
472 ListEntry.n_desc = NLE.
n_desc;
473 ListEntry.n_value = NLE.
n_value;
477 OS.
write(
reinterpret_cast<const char *
>(&ListEntry),
sizeof(
NListType));
480 void MachOWriter::writeLinkEditData(
raw_ostream &OS) {
481 typedef void (MachOWriter::*writeHandler)(
raw_ostream &);
482 typedef std::pair<uint64_t, writeHandler> writeOperation;
483 std::vector<writeOperation> WriteQueue;
490 switch (LC.
Data.load_command_data.cmd) {
491 case MachO::LC_SYMTAB:
492 SymtabCmd = &LC.
Data.symtab_command_data;
493 WriteQueue.push_back(
494 std::make_pair(SymtabCmd->
symoff, &MachOWriter::writeNameList));
495 WriteQueue.push_back(
498 case MachO::LC_DYLD_INFO_ONLY:
499 DyldInfoOnlyCmd = &LC.
Data.dyld_info_command_data;
500 WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->
rebase_off,
501 &MachOWriter::writeRebaseOpcodes));
502 WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->
bind_off,
503 &MachOWriter::writeBasicBindOpcodes));
504 WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->
weak_bind_off,
505 &MachOWriter::writeWeakBindOpcodes));
506 WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->
lazy_bind_off,
507 &MachOWriter::writeLazyBindOpcodes));
508 WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->
export_off,
509 &MachOWriter::writeExportTrie));
511 case MachO::LC_DYSYMTAB:
512 DSymtabCmd = &LC.
Data.dysymtab_command_data;
513 WriteQueue.push_back(std::make_pair(
514 DSymtabCmd->
indirectsymoff, &MachOWriter::writeDynamicSymbolTable));
516 case MachO::LC_FUNCTION_STARTS:
517 FunctionStartsCmd = &LC.
Data.linkedit_data_command_data;
518 WriteQueue.push_back(std::make_pair(FunctionStartsCmd->
dataoff,
519 &MachOWriter::writeFunctionStarts));
526 for (
auto writeOp : WriteQueue) {
527 ZeroToOffset(OS, writeOp.first);
528 (this->*writeOp.second)(OS);
532 void MachOWriter::writeRebaseOpcodes(
raw_ostream &OS) {
536 uint8_t OpByte = Opcode.Opcode | Opcode.Imm;
537 OS.
write(
reinterpret_cast<char *
>(&OpByte), 1);
538 for (
auto Data : Opcode.ExtraData)
543 void MachOWriter::writeBasicBindOpcodes(
raw_ostream &OS) {
547 void MachOWriter::writeWeakBindOpcodes(
raw_ostream &OS) {
551 void MachOWriter::writeLazyBindOpcodes(
raw_ostream &OS) {
566 OS.
write(Str.data(), Str.size());
571 void MachOWriter::writeDynamicSymbolTable(
raw_ostream &OS) {
573 OS.
write(
reinterpret_cast<const char *
>(&
Data),
577 void MachOWriter::writeFunctionStarts(
raw_ostream &OS) {
588 class UniversalWriter {
606 fileStart = OS.
tell();
609 return Writer.writeMachO(OS);
616 if (FatFile.FatArchs.size() < FatFile.Slices.size())
619 "cannot write 'Slices' if not described in 'FatArches'");
621 for (
size_t i = 0;
i < FatFile.Slices.size();
i++) {
622 ZeroToOffset(OS, FatFile.FatArchs[
i].offset);
623 MachOWriter Writer(FatFile.Slices[
i]);
624 if (
Error Err = Writer.writeMachO(OS))
627 auto SliceEnd = FatFile.FatArchs[
i].offset + FatFile.FatArchs[
i].size;
628 ZeroToOffset(OS, SliceEnd);
634 void UniversalWriter::writeFatHeader(
raw_ostream &OS) {
637 header.
magic = FatFile.Header.magic;
638 header.
nfat_arch = FatFile.Header.nfat_arch;
644 template <
typename FatArchType>
647 FatArch.cputype = Arch.
cputype;
649 FatArch.offset = Arch.
offset;
650 FatArch.size = Arch.
size;
651 FatArch.align = Arch.
align;
655 template <
typename StructType>
660 auto FatArch = constructFatArch<MachO::fat_arch>(Arch);
669 auto FatArch = constructFatArch<MachO::fat_arch_64>(Arch);
673 OS.
write(
reinterpret_cast<const char *
>(&FatArch),
677 void UniversalWriter::writeFatArchs(
raw_ostream &OS) {
680 for (
auto Arch : FatFile.FatArchs) {
682 writeFatArch<MachO::fat_arch_64>(Arch, OS);
684 writeFatArch<MachO::fat_arch>(Arch, OS);
688 void UniversalWriter::ZeroToOffset(
raw_ostream &OS,
size_t Offset) {
689 auto currOffset = OS.
tell() - fileStart;
690 if (currOffset < Offset)
700 UniversalWriter Writer(Doc);
701 if (
Error Err = Writer.writeMachO(Out)) {