49 std::vector<MachOYAML::BindOpcode> &BindOpcodes);
74 bool FoundLinkEditSeg =
false;
78 fileStart = OS.
tell();
80 writeLoadCommands(OS);
81 if (
Error Err = writeSectionData(OS))
84 if (!FoundLinkEditSeg)
85 writeLinkEditData(OS);
104 OS.
write((
const char *)&Header, header_size);
107 template <
typename SectionType>
110 memcpy(
reinterpret_cast<void *
>(&TempSec.sectname[0]), &Sec.
sectname[0], 16);
111 memcpy(
reinterpret_cast<void *
>(&TempSec.segname[0]), &Sec.
segname[0], 16);
112 TempSec.addr = Sec.
addr;
113 TempSec.size = Sec.
size;
114 TempSec.offset = Sec.
offset;
115 TempSec.align = Sec.
align;
116 TempSec.reloff = Sec.
reloff;
117 TempSec.nreloc = Sec.
nreloc;
118 TempSec.flags = Sec.
flags;
124 template <
typename StructType>
126 bool IsLittleEndian) {
133 bool IsLittleEndian) {
134 size_t BytesWritten = 0;
135 for (
const auto &Sec : LC.
Sections) {
136 auto TempSec = constructSection<MachO::section>(Sec);
139 OS.
write(
reinterpret_cast<const char *
>(&(TempSec)),
147 size_t writeLoadCommandData<MachO::segment_command_64>(
149 size_t BytesWritten = 0;
150 for (
const auto &Sec : LC.
Sections) {
151 auto TempSec = constructSection<MachO::section_64>(Sec);
155 OS.
write(
reinterpret_cast<const char *
>(&(TempSec)),
163 size_t BytesWritten = 0;
166 BytesWritten = LC.
Content.length();
174 bool IsLittleEndian) {
175 return writePayloadString(LC, OS);
181 bool IsLittleEndian) {
182 return writePayloadString(LC, OS);
188 bool IsLittleEndian) {
189 return writePayloadString(LC, OS);
193 size_t writeLoadCommandData<MachO::sub_framework_command>(
195 return writePayloadString(LC, OS);
199 size_t writeLoadCommandData<MachO::sub_umbrella_command>(
201 return writePayloadString(LC, OS);
205 size_t writeLoadCommandData<MachO::sub_client_command>(
207 return writePayloadString(LC, OS);
211 size_t writeLoadCommandData<MachO::sub_library_command>(
213 return writePayloadString(LC, OS);
217 size_t writeLoadCommandData<MachO::build_version_command>(
219 size_t BytesWritten = 0;
220 for (
const auto &
T : LC.
Tools) {
224 OS.
write(
reinterpret_cast<const char *
>(&tool),
232 std::vector<uint8_t> FillData(
Size, 0);
233 OS.
write(
reinterpret_cast<char *
>(FillData.data()),
Size);
237 std::vector<uint32_t> FillData((
Size / 4) + 1,
Data);
238 OS.
write(
reinterpret_cast<char *
>(FillData.data()),
Size);
242 auto currOffset = OS.
tell() - fileStart;
247 void MachOWriter::writeLoadCommands(
raw_ostream &OS) {
249 size_t BytesWritten = 0;
252 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
253 case MachO::LCName: \
254 if (Obj.IsLittleEndian != sys::IsLittleEndianHost) \
255 MachO::swapStruct(Data.LCStruct##_data); \
256 OS.write(reinterpret_cast<const char *>(&(Data.LCStruct##_data)), \
257 sizeof(MachO::LCStruct)); \
258 BytesWritten = sizeof(MachO::LCStruct); \
260 writeLoadCommandData<MachO::LCStruct>(LC, OS, Obj.IsLittleEndian); \
263 switch (LC.
Data.load_command_data.cmd) {
267 OS.
write(
reinterpret_cast<const char *
>(&(
Data.load_command_data)),
271 writeLoadCommandData<MachO::load_command>(LC, OS, Obj.
IsLittleEndian);
273 #include "llvm/BinaryFormat/MachO.def"
289 auto BytesRemaining = LC.
Data.load_command_data.cmdsize - BytesWritten;
290 if (BytesRemaining > 0) {
299 switch (LC.
Data.load_command_data.cmd) {
300 case MachO::LC_SEGMENT:
301 case MachO::LC_SEGMENT_64:
303 : LC.
Data.segment_command_data.fileoff;
305 strncmp(&LC.
Data.segment_command_data.segname[0],
"__LINKEDIT", 16)) {
306 FoundLinkEditSeg =
true;
307 LinkEditOff = segOff;
310 writeLinkEditData(OS);
313 ZeroToOffset(OS, Sec.
offset);
320 "wrote too much data somewhere, section offsets in "
321 "section {0} for segment {1} don't line up: "
322 "[cursor={2:x}], [fileStart={3:x}], [sectionOffset={4:x}]",
333 "cannot specify section '" + SectName +
334 "' contents in the 'DWARF' entry and "
335 "the 'content' at the same time");
352 Fill(OS, Sec.
size, 0xDEADBEEFu);
356 : LC.
Data.segment_command_data.filesize;
357 ZeroToOffset(OS, segOff + segSize);
363 ZeroToOffset(OS, LinkEditOff);
364 if (OS.
tell() - fileStart > LinkEditOff || !LinkEditOff)
366 "section offsets don't line up");
378 assert(!
R.is_scattered &&
"non-scattered relocation expected");
382 MRE.
r_word1 = ((unsigned)
R.symbolnum << 0) | ((unsigned)
R.is_pcrel << 24) |
383 ((unsigned)
R.length << 25) | ((unsigned)
R.is_extern << 27) |
384 ((unsigned)
R.type << 28);
386 MRE.
r_word1 = ((unsigned)
R.symbolnum << 8) | ((unsigned)
R.is_pcrel << 7) |
387 ((unsigned)
R.length << 5) | ((unsigned)
R.is_extern << 4) |
388 ((unsigned)
R.type << 0);
394 assert(
R.is_scattered &&
"scattered relocation expected");
396 MRE.
r_word0 = (((unsigned)
R.address << 0) | ((unsigned)
R.type << 24) |
397 ((unsigned)
R.length << 28) | ((unsigned)
R.is_pcrel << 30) |
403 void MachOWriter::writeRelocations(
raw_ostream &OS) {
405 switch (LC.
Data.load_command_data.cmd) {
406 case MachO::LC_SEGMENT:
407 case MachO::LC_SEGMENT_64:
411 ZeroToOffset(OS, Sec.
reloff);
414 R.is_scattered ? makeScatteredRelocationInfo(
R)
415 : makeRelocationInfo(
R, Obj.IsLittleEndian);
418 OS.
write(
reinterpret_cast<const char *
>(&MRE),
426 void MachOWriter::writeBindOpcodes(
427 raw_ostream &OS, std::vector<MachOYAML::BindOpcode> &BindOpcodes) {
429 for (
auto Opcode : BindOpcodes) {
430 uint8_t OpByte = Opcode.Opcode | Opcode.Imm;
431 OS.
write(
reinterpret_cast<char *
>(&OpByte), 1);
432 for (
auto Data : Opcode.ULEBExtraData) {
435 for (
auto Data : Opcode.SLEBExtraData) {
438 if (!Opcode.Symbol.empty()) {
439 OS.
write(Opcode.Symbol.data(), Opcode.Symbol.size());
448 if (Entry.TerminalSize > 0) {
452 OS << Entry.ImportName;
460 OS.
write(
static_cast<uint8_t
>(Entry.Children.size()));
461 for (
auto EE : Entry.Children) {
466 for (
auto EE : Entry.Children)
467 dumpExportEntry(OS, EE);
470 void MachOWriter::writeExportTrie(
raw_ostream &OS) {
474 template <
typename NListType>
476 bool IsLittleEndian) {
478 ListEntry.n_strx = NLE.
n_strx;
479 ListEntry.n_type = NLE.
n_type;
480 ListEntry.n_sect = NLE.
n_sect;
481 ListEntry.n_desc = NLE.
n_desc;
482 ListEntry.n_value = NLE.
n_value;
486 OS.
write(
reinterpret_cast<const char *
>(&ListEntry),
sizeof(
NListType));
489 void MachOWriter::writeLinkEditData(
raw_ostream &OS) {
490 typedef void (MachOWriter::*writeHandler)(
raw_ostream &);
491 typedef std::pair<uint64_t, writeHandler> writeOperation;
492 std::vector<writeOperation> WriteQueue;
502 switch (LC.
Data.load_command_data.cmd) {
503 case MachO::LC_SYMTAB:
504 SymtabCmd = &LC.
Data.symtab_command_data;
505 WriteQueue.push_back(
506 std::make_pair(SymtabCmd->
symoff, &MachOWriter::writeNameList));
507 WriteQueue.push_back(
510 case MachO::LC_DYLD_INFO_ONLY:
511 DyldInfoOnlyCmd = &LC.
Data.dyld_info_command_data;
512 WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->
rebase_off,
513 &MachOWriter::writeRebaseOpcodes));
514 WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->
bind_off,
515 &MachOWriter::writeBasicBindOpcodes));
516 WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->
weak_bind_off,
517 &MachOWriter::writeWeakBindOpcodes));
518 WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->
lazy_bind_off,
519 &MachOWriter::writeLazyBindOpcodes));
520 WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->
export_off,
521 &MachOWriter::writeExportTrie));
523 case MachO::LC_DYSYMTAB:
524 DSymtabCmd = &LC.
Data.dysymtab_command_data;
525 WriteQueue.push_back(std::make_pair(
526 DSymtabCmd->
indirectsymoff, &MachOWriter::writeDynamicSymbolTable));
528 case MachO::LC_FUNCTION_STARTS:
529 FunctionStartsCmd = &LC.
Data.linkedit_data_command_data;
530 WriteQueue.push_back(std::make_pair(FunctionStartsCmd->
dataoff,
531 &MachOWriter::writeFunctionStarts));
533 case MachO::LC_DYLD_CHAINED_FIXUPS:
534 ChainedFixupsCmd = &LC.
Data.linkedit_data_command_data;
535 WriteQueue.push_back(std::make_pair(ChainedFixupsCmd->
dataoff,
536 &MachOWriter::writeChainedFixups));
538 case MachO::LC_DYLD_EXPORTS_TRIE:
539 DyldExportsTrieCmd = &LC.
Data.linkedit_data_command_data;
540 WriteQueue.push_back(std::make_pair(DyldExportsTrieCmd->
dataoff,
541 &MachOWriter::writeDyldExportsTrie));
543 case MachO::LC_DATA_IN_CODE:
544 DataInCodeCmd = &LC.
Data.linkedit_data_command_data;
545 WriteQueue.push_back(std::make_pair(DataInCodeCmd->
dataoff,
546 &MachOWriter::writeDataInCode));
553 for (
auto writeOp : WriteQueue) {
554 ZeroToOffset(OS, writeOp.first);
555 (this->*writeOp.second)(OS);
559 void MachOWriter::writeRebaseOpcodes(
raw_ostream &OS) {
563 uint8_t OpByte = Opcode.Opcode | Opcode.Imm;
564 OS.
write(
reinterpret_cast<char *
>(&OpByte), 1);
565 for (
auto Data : Opcode.ExtraData)
570 void MachOWriter::writeBasicBindOpcodes(
raw_ostream &OS) {
574 void MachOWriter::writeWeakBindOpcodes(
raw_ostream &OS) {
578 void MachOWriter::writeLazyBindOpcodes(
raw_ostream &OS) {
593 OS.
write(Str.data(), Str.size());
598 void MachOWriter::writeDynamicSymbolTable(
raw_ostream &OS) {
600 OS.
write(
reinterpret_cast<const char *
>(&
Data),
604 void MachOWriter::writeFunctionStarts(
raw_ostream &OS) {
615 void MachOWriter::writeDataInCode(
raw_ostream &OS) {
620 OS.
write(
reinterpret_cast<const char *
>(&DICE),
625 void MachOWriter::writeChainedFixups(
raw_ostream &OS) {
631 void MachOWriter::writeDyldExportsTrie(
raw_ostream &OS) {
635 class UniversalWriter {
653 fileStart = OS.
tell();
656 return Writer.writeMachO(OS);
663 if (FatFile.FatArchs.size() < FatFile.Slices.size())
666 "cannot write 'Slices' if not described in 'FatArches'");
668 for (
size_t i = 0;
i < FatFile.Slices.size();
i++) {
669 ZeroToOffset(OS, FatFile.FatArchs[
i].offset);
670 MachOWriter Writer(FatFile.Slices[
i]);
671 if (
Error Err = Writer.writeMachO(OS))
674 auto SliceEnd = FatFile.FatArchs[
i].offset + FatFile.FatArchs[
i].size;
675 ZeroToOffset(OS, SliceEnd);
681 void UniversalWriter::writeFatHeader(
raw_ostream &OS) {
684 header.
magic = FatFile.Header.magic;
685 header.
nfat_arch = FatFile.Header.nfat_arch;
691 template <
typename FatArchType>
694 FatArch.cputype = Arch.
cputype;
696 FatArch.offset = Arch.
offset;
697 FatArch.size = Arch.
size;
698 FatArch.align = Arch.
align;
702 template <
typename StructType>
707 auto FatArch = constructFatArch<MachO::fat_arch>(Arch);
716 auto FatArch = constructFatArch<MachO::fat_arch_64>(Arch);
720 OS.
write(
reinterpret_cast<const char *
>(&FatArch),
724 void UniversalWriter::writeFatArchs(
raw_ostream &OS) {
727 for (
auto Arch : FatFile.FatArchs) {
729 writeFatArch<MachO::fat_arch_64>(Arch, OS);
731 writeFatArch<MachO::fat_arch>(Arch, OS);
736 auto currOffset = OS.
tell() - fileStart;
747 UniversalWriter Writer(Doc);
748 if (
Error Err = Writer.writeMachO(Out)) {