1 //===- yaml2macho - Convert YAML to a Mach object file --------------------===//
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 //===----------------------------------------------------------------------===//
10 /// The Mach component of yaml2obj.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/BinaryFormat/MachO.h"
15 #include "llvm/ObjectYAML/DWARFEmitter.h"
16 #include "llvm/ObjectYAML/ObjectYAML.h"
17 #include "llvm/ObjectYAML/yaml2obj.h"
18 #include "llvm/Support/Errc.h"
19 #include "llvm/Support/Error.h"
20 #include "llvm/Support/LEB128.h"
21 #include "llvm/Support/YAMLTraits.h"
22 #include "llvm/Support/raw_ostream.h"
24 #include "llvm/Support/Format.h"
32 MachOWriter(MachOYAML::Object
&Obj
) : Obj(Obj
), fileStart(0) {
33 is64Bit
= Obj
.Header
.magic
== MachO::MH_MAGIC_64
||
34 Obj
.Header
.magic
== MachO::MH_CIGAM_64
;
35 memset(reinterpret_cast<void *>(&Header
), 0, sizeof(MachO::mach_header_64
));
38 Error
writeMachO(raw_ostream
&OS
);
41 void writeHeader(raw_ostream
&OS
);
42 void writeLoadCommands(raw_ostream
&OS
);
43 Error
writeSectionData(raw_ostream
&OS
);
44 void writeRelocations(raw_ostream
&OS
);
45 void writeLinkEditData(raw_ostream
&OS
);
47 void writeBindOpcodes(raw_ostream
&OS
,
48 std::vector
<MachOYAML::BindOpcode
> &BindOpcodes
);
50 void writeRebaseOpcodes(raw_ostream
&OS
);
51 void writeBasicBindOpcodes(raw_ostream
&OS
);
52 void writeWeakBindOpcodes(raw_ostream
&OS
);
53 void writeLazyBindOpcodes(raw_ostream
&OS
);
54 void writeNameList(raw_ostream
&OS
);
55 void writeStringTable(raw_ostream
&OS
);
56 void writeExportTrie(raw_ostream
&OS
);
58 void dumpExportEntry(raw_ostream
&OS
, MachOYAML::ExportEntry
&Entry
);
59 void ZeroToOffset(raw_ostream
&OS
, size_t offset
);
61 MachOYAML::Object
&Obj
;
64 MachO::mach_header_64 Header
;
66 // Old PPC Object Files didn't have __LINKEDIT segments, the data was just
67 // stuck at the end of the file.
68 bool FoundLinkEditSeg
= false;
71 Error
MachOWriter::writeMachO(raw_ostream
&OS
) {
72 fileStart
= OS
.tell();
74 writeLoadCommands(OS
);
75 if (Error Err
= writeSectionData(OS
))
78 if (!FoundLinkEditSeg
)
79 writeLinkEditData(OS
);
80 return Error::success();
83 void MachOWriter::writeHeader(raw_ostream
&OS
) {
84 Header
.magic
= Obj
.Header
.magic
;
85 Header
.cputype
= Obj
.Header
.cputype
;
86 Header
.cpusubtype
= Obj
.Header
.cpusubtype
;
87 Header
.filetype
= Obj
.Header
.filetype
;
88 Header
.ncmds
= Obj
.Header
.ncmds
;
89 Header
.sizeofcmds
= Obj
.Header
.sizeofcmds
;
90 Header
.flags
= Obj
.Header
.flags
;
91 Header
.reserved
= Obj
.Header
.reserved
;
93 if (Obj
.IsLittleEndian
!= sys::IsLittleEndianHost
)
94 MachO::swapStruct(Header
);
97 is64Bit
? sizeof(MachO::mach_header_64
) : sizeof(MachO::mach_header
);
98 OS
.write((const char *)&Header
, header_size
);
101 template <typename SectionType
>
102 SectionType
constructSection(MachOYAML::Section Sec
) {
104 memcpy(reinterpret_cast<void *>(&TempSec
.sectname
[0]), &Sec
.sectname
[0], 16);
105 memcpy(reinterpret_cast<void *>(&TempSec
.segname
[0]), &Sec
.segname
[0], 16);
106 TempSec
.addr
= Sec
.addr
;
107 TempSec
.size
= Sec
.size
;
108 TempSec
.offset
= Sec
.offset
;
109 TempSec
.align
= Sec
.align
;
110 TempSec
.reloff
= Sec
.reloff
;
111 TempSec
.nreloc
= Sec
.nreloc
;
112 TempSec
.flags
= Sec
.flags
;
113 TempSec
.reserved1
= Sec
.reserved1
;
114 TempSec
.reserved2
= Sec
.reserved2
;
118 template <typename StructType
>
119 size_t writeLoadCommandData(MachOYAML::LoadCommand
&LC
, raw_ostream
&OS
,
120 bool IsLittleEndian
) {
125 size_t writeLoadCommandData
<MachO::segment_command
>(MachOYAML::LoadCommand
&LC
,
127 bool IsLittleEndian
) {
128 size_t BytesWritten
= 0;
129 for (const auto &Sec
: LC
.Sections
) {
130 auto TempSec
= constructSection
<MachO::section
>(Sec
);
131 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
132 MachO::swapStruct(TempSec
);
133 OS
.write(reinterpret_cast<const char *>(&(TempSec
)),
134 sizeof(MachO::section
));
135 BytesWritten
+= sizeof(MachO::section
);
141 size_t writeLoadCommandData
<MachO::segment_command_64
>(
142 MachOYAML::LoadCommand
&LC
, raw_ostream
&OS
, bool IsLittleEndian
) {
143 size_t BytesWritten
= 0;
144 for (const auto &Sec
: LC
.Sections
) {
145 auto TempSec
= constructSection
<MachO::section_64
>(Sec
);
146 TempSec
.reserved3
= Sec
.reserved3
;
147 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
148 MachO::swapStruct(TempSec
);
149 OS
.write(reinterpret_cast<const char *>(&(TempSec
)),
150 sizeof(MachO::section_64
));
151 BytesWritten
+= sizeof(MachO::section_64
);
156 size_t writePayloadString(MachOYAML::LoadCommand
&LC
, raw_ostream
&OS
) {
157 size_t BytesWritten
= 0;
158 if (!LC
.Content
.empty()) {
159 OS
.write(LC
.Content
.c_str(), LC
.Content
.length());
160 BytesWritten
= LC
.Content
.length();
166 size_t writeLoadCommandData
<MachO::dylib_command
>(MachOYAML::LoadCommand
&LC
,
168 bool IsLittleEndian
) {
169 return writePayloadString(LC
, OS
);
173 size_t writeLoadCommandData
<MachO::dylinker_command
>(MachOYAML::LoadCommand
&LC
,
175 bool IsLittleEndian
) {
176 return writePayloadString(LC
, OS
);
180 size_t writeLoadCommandData
<MachO::rpath_command
>(MachOYAML::LoadCommand
&LC
,
182 bool IsLittleEndian
) {
183 return writePayloadString(LC
, OS
);
187 size_t writeLoadCommandData
<MachO::sub_framework_command
>(
188 MachOYAML::LoadCommand
&LC
, raw_ostream
&OS
, bool IsLittleEndian
) {
189 return writePayloadString(LC
, OS
);
193 size_t writeLoadCommandData
<MachO::sub_umbrella_command
>(
194 MachOYAML::LoadCommand
&LC
, raw_ostream
&OS
, bool IsLittleEndian
) {
195 return writePayloadString(LC
, OS
);
199 size_t writeLoadCommandData
<MachO::sub_client_command
>(
200 MachOYAML::LoadCommand
&LC
, raw_ostream
&OS
, bool IsLittleEndian
) {
201 return writePayloadString(LC
, OS
);
205 size_t writeLoadCommandData
<MachO::sub_library_command
>(
206 MachOYAML::LoadCommand
&LC
, raw_ostream
&OS
, bool IsLittleEndian
) {
207 return writePayloadString(LC
, OS
);
211 size_t writeLoadCommandData
<MachO::build_version_command
>(
212 MachOYAML::LoadCommand
&LC
, raw_ostream
&OS
, bool IsLittleEndian
) {
213 size_t BytesWritten
= 0;
214 for (const auto &T
: LC
.Tools
) {
215 struct MachO::build_tool_version tool
= T
;
216 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
217 MachO::swapStruct(tool
);
218 OS
.write(reinterpret_cast<const char *>(&tool
),
219 sizeof(MachO::build_tool_version
));
220 BytesWritten
+= sizeof(MachO::build_tool_version
);
225 void ZeroFillBytes(raw_ostream
&OS
, size_t Size
) {
226 std::vector
<uint8_t> FillData(Size
, 0);
227 OS
.write(reinterpret_cast<char *>(FillData
.data()), Size
);
230 void Fill(raw_ostream
&OS
, size_t Size
, uint32_t Data
) {
231 std::vector
<uint32_t> FillData((Size
/ 4) + 1, Data
);
232 OS
.write(reinterpret_cast<char *>(FillData
.data()), Size
);
235 void MachOWriter::ZeroToOffset(raw_ostream
&OS
, size_t Offset
) {
236 auto currOffset
= OS
.tell() - fileStart
;
237 if (currOffset
< Offset
)
238 ZeroFillBytes(OS
, Offset
- currOffset
);
241 void MachOWriter::writeLoadCommands(raw_ostream
&OS
) {
242 for (auto &LC
: Obj
.LoadCommands
) {
243 size_t BytesWritten
= 0;
244 llvm::MachO::macho_load_command Data
= LC
.Data
;
246 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
247 case MachO::LCName: \
248 if (Obj.IsLittleEndian != sys::IsLittleEndianHost) \
249 MachO::swapStruct(Data.LCStruct##_data); \
250 OS.write(reinterpret_cast<const char *>(&(Data.LCStruct##_data)), \
251 sizeof(MachO::LCStruct)); \
252 BytesWritten = sizeof(MachO::LCStruct); \
254 writeLoadCommandData<MachO::LCStruct>(LC, OS, Obj.IsLittleEndian); \
257 switch (LC
.Data
.load_command_data
.cmd
) {
259 if (Obj
.IsLittleEndian
!= sys::IsLittleEndianHost
)
260 MachO::swapStruct(Data
.load_command_data
);
261 OS
.write(reinterpret_cast<const char *>(&(Data
.load_command_data
)),
262 sizeof(MachO::load_command
));
263 BytesWritten
= sizeof(MachO::load_command
);
265 writeLoadCommandData
<MachO::load_command
>(LC
, OS
, Obj
.IsLittleEndian
);
267 #include "llvm/BinaryFormat/MachO.def"
270 if (LC
.PayloadBytes
.size() > 0) {
271 OS
.write(reinterpret_cast<const char *>(LC
.PayloadBytes
.data()),
272 LC
.PayloadBytes
.size());
273 BytesWritten
+= LC
.PayloadBytes
.size();
276 if (LC
.ZeroPadBytes
> 0) {
277 ZeroFillBytes(OS
, LC
.ZeroPadBytes
);
278 BytesWritten
+= LC
.ZeroPadBytes
;
281 // Fill remaining bytes with 0. This will only get hit in partially
282 // specified test cases.
283 auto BytesRemaining
= LC
.Data
.load_command_data
.cmdsize
- BytesWritten
;
284 if (BytesRemaining
> 0) {
285 ZeroFillBytes(OS
, BytesRemaining
);
290 Error
MachOWriter::writeSectionData(raw_ostream
&OS
) {
291 for (auto &LC
: Obj
.LoadCommands
) {
292 switch (LC
.Data
.load_command_data
.cmd
) {
293 case MachO::LC_SEGMENT
:
294 case MachO::LC_SEGMENT_64
:
295 uint64_t segOff
= is64Bit
? LC
.Data
.segment_command_64_data
.fileoff
296 : LC
.Data
.segment_command_data
.fileoff
;
298 strncmp(&LC
.Data
.segment_command_data
.segname
[0], "__LINKEDIT", 16)) {
299 FoundLinkEditSeg
= true;
300 writeLinkEditData(OS
);
302 for (auto &Sec
: LC
.Sections
) {
303 ZeroToOffset(OS
, Sec
.offset
);
304 // Zero Fill any data between the end of the last thing we wrote and the
305 // start of this section.
306 if (OS
.tell() - fileStart
> Sec
.offset
&& Sec
.offset
!= (uint32_t)0)
307 return createStringError(
308 errc::invalid_argument
,
309 "wrote too much data somewhere, section offsets don't line up");
311 StringRef
SectName(Sec
.sectname
,
312 strnlen(Sec
.sectname
, sizeof(Sec
.sectname
)));
313 // If the section's content is specified in the 'DWARF' entry, we will
314 // emit it regardless of the section's segname.
315 if (Obj
.DWARF
.getNonEmptySectionNames().count(SectName
.substr(2))) {
317 return createStringError(errc::invalid_argument
,
318 "cannot specify section '" + SectName
+
319 "' contents in the 'DWARF' entry and "
320 "the 'content' at the same time");
321 auto EmitFunc
= DWARFYAML::getDWARFEmitterByName(SectName
.substr(2));
322 if (Error Err
= EmitFunc(OS
, Obj
.DWARF
))
327 // Skip if it's a virtual section.
328 if (MachO::isVirtualSection(Sec
.flags
& MachO::SECTION_TYPE
))
332 yaml::BinaryRef Content
= *Sec
.content
;
333 Content
.writeAsBinary(OS
);
334 ZeroFillBytes(OS
, Sec
.size
- Content
.binary_size());
336 // Fill section data with 0xDEADBEEF.
337 Fill(OS
, Sec
.size
, 0xDEADBEEFu
);
340 uint64_t segSize
= is64Bit
? LC
.Data
.segment_command_64_data
.filesize
341 : LC
.Data
.segment_command_data
.filesize
;
342 ZeroToOffset(OS
, segOff
+ segSize
);
347 return Error::success();
350 // The implementation of makeRelocationInfo and makeScatteredRelocationInfo is
351 // consistent with how libObject parses MachO binary files. For the reference
352 // see getStruct, getRelocation, getPlainRelocationPCRel,
353 // getPlainRelocationLength and related methods in MachOObjectFile.cpp
354 static MachO::any_relocation_info
355 makeRelocationInfo(const MachOYAML::Relocation
&R
, bool IsLE
) {
356 assert(!R
.is_scattered
&& "non-scattered relocation expected");
357 MachO::any_relocation_info MRE
;
358 MRE
.r_word0
= R
.address
;
360 MRE
.r_word1
= ((unsigned)R
.symbolnum
<< 0) | ((unsigned)R
.is_pcrel
<< 24) |
361 ((unsigned)R
.length
<< 25) | ((unsigned)R
.is_extern
<< 27) |
362 ((unsigned)R
.type
<< 28);
364 MRE
.r_word1
= ((unsigned)R
.symbolnum
<< 8) | ((unsigned)R
.is_pcrel
<< 7) |
365 ((unsigned)R
.length
<< 5) | ((unsigned)R
.is_extern
<< 4) |
366 ((unsigned)R
.type
<< 0);
370 static MachO::any_relocation_info
371 makeScatteredRelocationInfo(const MachOYAML::Relocation
&R
) {
372 assert(R
.is_scattered
&& "scattered relocation expected");
373 MachO::any_relocation_info MRE
;
374 MRE
.r_word0
= (((unsigned)R
.address
<< 0) | ((unsigned)R
.type
<< 24) |
375 ((unsigned)R
.length
<< 28) | ((unsigned)R
.is_pcrel
<< 30) |
377 MRE
.r_word1
= R
.value
;
381 void MachOWriter::writeRelocations(raw_ostream
&OS
) {
382 for (const MachOYAML::LoadCommand
&LC
: Obj
.LoadCommands
) {
383 switch (LC
.Data
.load_command_data
.cmd
) {
384 case MachO::LC_SEGMENT
:
385 case MachO::LC_SEGMENT_64
:
386 for (const MachOYAML::Section
&Sec
: LC
.Sections
) {
387 if (Sec
.relocations
.empty())
389 ZeroToOffset(OS
, Sec
.reloff
);
390 for (const MachOYAML::Relocation
&R
: Sec
.relocations
) {
391 MachO::any_relocation_info MRE
=
392 R
.is_scattered
? makeScatteredRelocationInfo(R
)
393 : makeRelocationInfo(R
, Obj
.IsLittleEndian
);
394 if (Obj
.IsLittleEndian
!= sys::IsLittleEndianHost
)
395 MachO::swapStruct(MRE
);
396 OS
.write(reinterpret_cast<const char *>(&MRE
),
397 sizeof(MachO::any_relocation_info
));
404 void MachOWriter::writeBindOpcodes(
405 raw_ostream
&OS
, std::vector
<MachOYAML::BindOpcode
> &BindOpcodes
) {
407 for (auto Opcode
: BindOpcodes
) {
408 uint8_t OpByte
= Opcode
.Opcode
| Opcode
.Imm
;
409 OS
.write(reinterpret_cast<char *>(&OpByte
), 1);
410 for (auto Data
: Opcode
.ULEBExtraData
) {
411 encodeULEB128(Data
, OS
);
413 for (auto Data
: Opcode
.SLEBExtraData
) {
414 encodeSLEB128(Data
, OS
);
416 if (!Opcode
.Symbol
.empty()) {
417 OS
.write(Opcode
.Symbol
.data(), Opcode
.Symbol
.size());
423 void MachOWriter::dumpExportEntry(raw_ostream
&OS
,
424 MachOYAML::ExportEntry
&Entry
) {
425 encodeSLEB128(Entry
.TerminalSize
, OS
);
426 if (Entry
.TerminalSize
> 0) {
427 encodeSLEB128(Entry
.Flags
, OS
);
428 if (Entry
.Flags
& MachO::EXPORT_SYMBOL_FLAGS_REEXPORT
) {
429 encodeSLEB128(Entry
.Other
, OS
);
430 OS
<< Entry
.ImportName
;
433 encodeSLEB128(Entry
.Address
, OS
);
434 if (Entry
.Flags
& MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
435 encodeSLEB128(Entry
.Other
, OS
);
438 OS
.write(static_cast<uint8_t>(Entry
.Children
.size()));
439 for (auto EE
: Entry
.Children
) {
442 encodeSLEB128(EE
.NodeOffset
, OS
);
444 for (auto EE
: Entry
.Children
)
445 dumpExportEntry(OS
, EE
);
448 void MachOWriter::writeExportTrie(raw_ostream
&OS
) {
449 dumpExportEntry(OS
, Obj
.LinkEdit
.ExportTrie
);
452 template <typename NListType
>
453 void writeNListEntry(MachOYAML::NListEntry
&NLE
, raw_ostream
&OS
,
454 bool IsLittleEndian
) {
456 ListEntry
.n_strx
= NLE
.n_strx
;
457 ListEntry
.n_type
= NLE
.n_type
;
458 ListEntry
.n_sect
= NLE
.n_sect
;
459 ListEntry
.n_desc
= NLE
.n_desc
;
460 ListEntry
.n_value
= NLE
.n_value
;
462 if (IsLittleEndian
!= sys::IsLittleEndianHost
)
463 MachO::swapStruct(ListEntry
);
464 OS
.write(reinterpret_cast<const char *>(&ListEntry
), sizeof(NListType
));
467 void MachOWriter::writeLinkEditData(raw_ostream
&OS
) {
468 typedef void (MachOWriter::*writeHandler
)(raw_ostream
&);
469 typedef std::pair
<uint64_t, writeHandler
> writeOperation
;
470 std::vector
<writeOperation
> WriteQueue
;
472 MachO::dyld_info_command
*DyldInfoOnlyCmd
= 0;
473 MachO::symtab_command
*SymtabCmd
= 0;
474 for (auto &LC
: Obj
.LoadCommands
) {
475 switch (LC
.Data
.load_command_data
.cmd
) {
476 case MachO::LC_SYMTAB
:
477 SymtabCmd
= &LC
.Data
.symtab_command_data
;
478 WriteQueue
.push_back(
479 std::make_pair(SymtabCmd
->symoff
, &MachOWriter::writeNameList
));
480 WriteQueue
.push_back(
481 std::make_pair(SymtabCmd
->stroff
, &MachOWriter::writeStringTable
));
483 case MachO::LC_DYLD_INFO_ONLY
:
484 DyldInfoOnlyCmd
= &LC
.Data
.dyld_info_command_data
;
485 WriteQueue
.push_back(std::make_pair(DyldInfoOnlyCmd
->rebase_off
,
486 &MachOWriter::writeRebaseOpcodes
));
487 WriteQueue
.push_back(std::make_pair(DyldInfoOnlyCmd
->bind_off
,
488 &MachOWriter::writeBasicBindOpcodes
));
489 WriteQueue
.push_back(std::make_pair(DyldInfoOnlyCmd
->weak_bind_off
,
490 &MachOWriter::writeWeakBindOpcodes
));
491 WriteQueue
.push_back(std::make_pair(DyldInfoOnlyCmd
->lazy_bind_off
,
492 &MachOWriter::writeLazyBindOpcodes
));
493 WriteQueue
.push_back(std::make_pair(DyldInfoOnlyCmd
->export_off
,
494 &MachOWriter::writeExportTrie
));
499 llvm::sort(WriteQueue
, [](const writeOperation
&a
, const writeOperation
&b
) {
500 return a
.first
< b
.first
;
503 for (auto writeOp
: WriteQueue
) {
504 ZeroToOffset(OS
, writeOp
.first
);
505 (this->*writeOp
.second
)(OS
);
509 void MachOWriter::writeRebaseOpcodes(raw_ostream
&OS
) {
510 MachOYAML::LinkEditData
&LinkEdit
= Obj
.LinkEdit
;
512 for (auto Opcode
: LinkEdit
.RebaseOpcodes
) {
513 uint8_t OpByte
= Opcode
.Opcode
| Opcode
.Imm
;
514 OS
.write(reinterpret_cast<char *>(&OpByte
), 1);
515 for (auto Data
: Opcode
.ExtraData
)
516 encodeULEB128(Data
, OS
);
520 void MachOWriter::writeBasicBindOpcodes(raw_ostream
&OS
) {
521 writeBindOpcodes(OS
, Obj
.LinkEdit
.BindOpcodes
);
524 void MachOWriter::writeWeakBindOpcodes(raw_ostream
&OS
) {
525 writeBindOpcodes(OS
, Obj
.LinkEdit
.WeakBindOpcodes
);
528 void MachOWriter::writeLazyBindOpcodes(raw_ostream
&OS
) {
529 writeBindOpcodes(OS
, Obj
.LinkEdit
.LazyBindOpcodes
);
532 void MachOWriter::writeNameList(raw_ostream
&OS
) {
533 for (auto NLE
: Obj
.LinkEdit
.NameList
) {
535 writeNListEntry
<MachO::nlist_64
>(NLE
, OS
, Obj
.IsLittleEndian
);
537 writeNListEntry
<MachO::nlist
>(NLE
, OS
, Obj
.IsLittleEndian
);
541 void MachOWriter::writeStringTable(raw_ostream
&OS
) {
542 for (auto Str
: Obj
.LinkEdit
.StringTable
) {
543 OS
.write(Str
.data(), Str
.size());
548 class UniversalWriter
{
550 UniversalWriter(yaml::YamlObjectFile
&ObjectFile
)
551 : ObjectFile(ObjectFile
), fileStart(0) {}
553 Error
writeMachO(raw_ostream
&OS
);
556 void writeFatHeader(raw_ostream
&OS
);
557 void writeFatArchs(raw_ostream
&OS
);
559 void ZeroToOffset(raw_ostream
&OS
, size_t offset
);
561 yaml::YamlObjectFile
&ObjectFile
;
565 Error
UniversalWriter::writeMachO(raw_ostream
&OS
) {
566 fileStart
= OS
.tell();
567 if (ObjectFile
.MachO
) {
568 MachOWriter
Writer(*ObjectFile
.MachO
);
569 return Writer
.writeMachO(OS
);
575 auto &FatFile
= *ObjectFile
.FatMachO
;
576 if (FatFile
.FatArchs
.size() < FatFile
.Slices
.size())
577 return createStringError(
578 errc::invalid_argument
,
579 "cannot write 'Slices' if not described in 'FatArches'");
581 for (size_t i
= 0; i
< FatFile
.Slices
.size(); i
++) {
582 ZeroToOffset(OS
, FatFile
.FatArchs
[i
].offset
);
583 MachOWriter
Writer(FatFile
.Slices
[i
]);
584 if (Error Err
= Writer
.writeMachO(OS
))
587 auto SliceEnd
= FatFile
.FatArchs
[i
].offset
+ FatFile
.FatArchs
[i
].size
;
588 ZeroToOffset(OS
, SliceEnd
);
591 return Error::success();
594 void UniversalWriter::writeFatHeader(raw_ostream
&OS
) {
595 auto &FatFile
= *ObjectFile
.FatMachO
;
596 MachO::fat_header header
;
597 header
.magic
= FatFile
.Header
.magic
;
598 header
.nfat_arch
= FatFile
.Header
.nfat_arch
;
599 if (sys::IsLittleEndianHost
)
601 OS
.write(reinterpret_cast<const char *>(&header
), sizeof(MachO::fat_header
));
604 template <typename FatArchType
>
605 FatArchType
constructFatArch(MachOYAML::FatArch
&Arch
) {
607 FatArch
.cputype
= Arch
.cputype
;
608 FatArch
.cpusubtype
= Arch
.cpusubtype
;
609 FatArch
.offset
= Arch
.offset
;
610 FatArch
.size
= Arch
.size
;
611 FatArch
.align
= Arch
.align
;
615 template <typename StructType
>
616 void writeFatArch(MachOYAML::FatArch
&LC
, raw_ostream
&OS
) {}
619 void writeFatArch
<MachO::fat_arch
>(MachOYAML::FatArch
&Arch
, raw_ostream
&OS
) {
620 auto FatArch
= constructFatArch
<MachO::fat_arch
>(Arch
);
621 if (sys::IsLittleEndianHost
)
623 OS
.write(reinterpret_cast<const char *>(&FatArch
), sizeof(MachO::fat_arch
));
627 void writeFatArch
<MachO::fat_arch_64
>(MachOYAML::FatArch
&Arch
,
629 auto FatArch
= constructFatArch
<MachO::fat_arch_64
>(Arch
);
630 FatArch
.reserved
= Arch
.reserved
;
631 if (sys::IsLittleEndianHost
)
633 OS
.write(reinterpret_cast<const char *>(&FatArch
),
634 sizeof(MachO::fat_arch_64
));
637 void UniversalWriter::writeFatArchs(raw_ostream
&OS
) {
638 auto &FatFile
= *ObjectFile
.FatMachO
;
639 bool is64Bit
= FatFile
.Header
.magic
== MachO::FAT_MAGIC_64
;
640 for (auto Arch
: FatFile
.FatArchs
) {
642 writeFatArch
<MachO::fat_arch_64
>(Arch
, OS
);
644 writeFatArch
<MachO::fat_arch
>(Arch
, OS
);
648 void UniversalWriter::ZeroToOffset(raw_ostream
&OS
, size_t Offset
) {
649 auto currOffset
= OS
.tell() - fileStart
;
650 if (currOffset
< Offset
)
651 ZeroFillBytes(OS
, Offset
- currOffset
);
654 } // end anonymous namespace
659 bool yaml2macho(YamlObjectFile
&Doc
, raw_ostream
&Out
, ErrorHandler EH
) {
660 UniversalWriter
Writer(Doc
);
661 if (Error Err
= Writer
.writeMachO(Out
)) {
662 handleAllErrors(std::move(Err
),
663 [&](const ErrorInfoBase
&Err
) { EH(Err
.message()); });