MachOEmitter.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. //===- yaml2macho - Convert YAML to a Mach object file --------------------===//
  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. /// \file
  10. /// The Mach component of yaml2obj.
  11. ///
  12. //===----------------------------------------------------------------------===//
  13. #include "llvm/BinaryFormat/MachO.h"
  14. #include "llvm/ObjectYAML/DWARFEmitter.h"
  15. #include "llvm/ObjectYAML/ObjectYAML.h"
  16. #include "llvm/ObjectYAML/yaml2obj.h"
  17. #include "llvm/Support/LEB128.h"
  18. #include "llvm/Support/YAMLTraits.h"
  19. #include "llvm/Support/raw_ostream.h"
  20. #include "llvm/Support/Format.h"
  21. using namespace llvm;
  22. namespace {
  23. class MachOWriter {
  24. public:
  25. MachOWriter(MachOYAML::Object &Obj) : Obj(Obj), is64Bit(true), fileStart(0) {
  26. is64Bit = Obj.Header.magic == MachO::MH_MAGIC_64 ||
  27. Obj.Header.magic == MachO::MH_CIGAM_64;
  28. memset(reinterpret_cast<void *>(&Header), 0, sizeof(MachO::mach_header_64));
  29. }
  30. void writeMachO(raw_ostream &OS);
  31. private:
  32. void writeHeader(raw_ostream &OS);
  33. void writeLoadCommands(raw_ostream &OS);
  34. void writeSectionData(raw_ostream &OS);
  35. void writeLinkEditData(raw_ostream &OS);
  36. void writeBindOpcodes(raw_ostream &OS,
  37. std::vector<MachOYAML::BindOpcode> &BindOpcodes);
  38. // LinkEdit writers
  39. void writeRebaseOpcodes(raw_ostream &OS);
  40. void writeBasicBindOpcodes(raw_ostream &OS);
  41. void writeWeakBindOpcodes(raw_ostream &OS);
  42. void writeLazyBindOpcodes(raw_ostream &OS);
  43. void writeNameList(raw_ostream &OS);
  44. void writeStringTable(raw_ostream &OS);
  45. void writeExportTrie(raw_ostream &OS);
  46. void dumpExportEntry(raw_ostream &OS, MachOYAML::ExportEntry &Entry);
  47. void ZeroToOffset(raw_ostream &OS, size_t offset);
  48. MachOYAML::Object &Obj;
  49. bool is64Bit;
  50. uint64_t fileStart;
  51. MachO::mach_header_64 Header;
  52. };
  53. void MachOWriter::writeMachO(raw_ostream &OS) {
  54. fileStart = OS.tell();
  55. writeHeader(OS);
  56. writeLoadCommands(OS);
  57. writeSectionData(OS);
  58. }
  59. void MachOWriter::writeHeader(raw_ostream &OS) {
  60. Header.magic = Obj.Header.magic;
  61. Header.cputype = Obj.Header.cputype;
  62. Header.cpusubtype = Obj.Header.cpusubtype;
  63. Header.filetype = Obj.Header.filetype;
  64. Header.ncmds = Obj.Header.ncmds;
  65. Header.sizeofcmds = Obj.Header.sizeofcmds;
  66. Header.flags = Obj.Header.flags;
  67. Header.reserved = Obj.Header.reserved;
  68. if (Obj.IsLittleEndian != sys::IsLittleEndianHost)
  69. MachO::swapStruct(Header);
  70. auto header_size =
  71. is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
  72. OS.write((const char *)&Header, header_size);
  73. }
  74. template <typename SectionType>
  75. SectionType constructSection(MachOYAML::Section Sec) {
  76. SectionType TempSec;
  77. memcpy(reinterpret_cast<void *>(&TempSec.sectname[0]), &Sec.sectname[0], 16);
  78. memcpy(reinterpret_cast<void *>(&TempSec.segname[0]), &Sec.segname[0], 16);
  79. TempSec.addr = Sec.addr;
  80. TempSec.size = Sec.size;
  81. TempSec.offset = Sec.offset;
  82. TempSec.align = Sec.align;
  83. TempSec.reloff = Sec.reloff;
  84. TempSec.nreloc = Sec.nreloc;
  85. TempSec.flags = Sec.flags;
  86. TempSec.reserved1 = Sec.reserved1;
  87. TempSec.reserved2 = Sec.reserved2;
  88. return TempSec;
  89. }
  90. template <typename StructType>
  91. size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS,
  92. bool IsLittleEndian) {
  93. return 0;
  94. }
  95. template <>
  96. size_t writeLoadCommandData<MachO::segment_command>(MachOYAML::LoadCommand &LC,
  97. raw_ostream &OS,
  98. bool IsLittleEndian) {
  99. size_t BytesWritten = 0;
  100. for (const auto &Sec : LC.Sections) {
  101. auto TempSec = constructSection<MachO::section>(Sec);
  102. if (IsLittleEndian != sys::IsLittleEndianHost)
  103. MachO::swapStruct(TempSec);
  104. OS.write(reinterpret_cast<const char *>(&(TempSec)),
  105. sizeof(MachO::section));
  106. BytesWritten += sizeof(MachO::section);
  107. }
  108. return BytesWritten;
  109. }
  110. template <>
  111. size_t writeLoadCommandData<MachO::segment_command_64>(
  112. MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
  113. size_t BytesWritten = 0;
  114. for (const auto &Sec : LC.Sections) {
  115. auto TempSec = constructSection<MachO::section_64>(Sec);
  116. TempSec.reserved3 = Sec.reserved3;
  117. if (IsLittleEndian != sys::IsLittleEndianHost)
  118. MachO::swapStruct(TempSec);
  119. OS.write(reinterpret_cast<const char *>(&(TempSec)),
  120. sizeof(MachO::section_64));
  121. BytesWritten += sizeof(MachO::section_64);
  122. }
  123. return BytesWritten;
  124. }
  125. size_t writePayloadString(MachOYAML::LoadCommand &LC, raw_ostream &OS) {
  126. size_t BytesWritten = 0;
  127. if (!LC.PayloadString.empty()) {
  128. OS.write(LC.PayloadString.c_str(), LC.PayloadString.length());
  129. BytesWritten = LC.PayloadString.length();
  130. }
  131. return BytesWritten;
  132. }
  133. template <>
  134. size_t writeLoadCommandData<MachO::dylib_command>(MachOYAML::LoadCommand &LC,
  135. raw_ostream &OS,
  136. bool IsLittleEndian) {
  137. return writePayloadString(LC, OS);
  138. }
  139. template <>
  140. size_t writeLoadCommandData<MachO::dylinker_command>(MachOYAML::LoadCommand &LC,
  141. raw_ostream &OS,
  142. bool IsLittleEndian) {
  143. return writePayloadString(LC, OS);
  144. }
  145. template <>
  146. size_t writeLoadCommandData<MachO::rpath_command>(MachOYAML::LoadCommand &LC,
  147. raw_ostream &OS,
  148. bool IsLittleEndian) {
  149. return writePayloadString(LC, OS);
  150. }
  151. template <>
  152. size_t writeLoadCommandData<MachO::build_version_command>(
  153. MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
  154. size_t BytesWritten = 0;
  155. for (const auto &T : LC.Tools) {
  156. struct MachO::build_tool_version tool = T;
  157. if (IsLittleEndian != sys::IsLittleEndianHost)
  158. MachO::swapStruct(tool);
  159. OS.write(reinterpret_cast<const char *>(&tool),
  160. sizeof(MachO::build_tool_version));
  161. BytesWritten += sizeof(MachO::build_tool_version);
  162. }
  163. return BytesWritten;
  164. }
  165. void ZeroFillBytes(raw_ostream &OS, size_t Size) {
  166. std::vector<uint8_t> FillData;
  167. FillData.insert(FillData.begin(), Size, 0);
  168. OS.write(reinterpret_cast<char *>(FillData.data()), Size);
  169. }
  170. void Fill(raw_ostream &OS, size_t Size, uint32_t Data) {
  171. std::vector<uint32_t> FillData;
  172. FillData.insert(FillData.begin(), (Size / 4) + 1, Data);
  173. OS.write(reinterpret_cast<char *>(FillData.data()), Size);
  174. }
  175. void MachOWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) {
  176. auto currOffset = OS.tell() - fileStart;
  177. if (currOffset < Offset)
  178. ZeroFillBytes(OS, Offset - currOffset);
  179. }
  180. void MachOWriter::writeLoadCommands(raw_ostream &OS) {
  181. for (auto &LC : Obj.LoadCommands) {
  182. size_t BytesWritten = 0;
  183. llvm::MachO::macho_load_command Data = LC.Data;
  184. #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
  185. case MachO::LCName: \
  186. if (Obj.IsLittleEndian != sys::IsLittleEndianHost) \
  187. MachO::swapStruct(Data.LCStruct##_data); \
  188. OS.write(reinterpret_cast<const char *>(&(Data.LCStruct##_data)), \
  189. sizeof(MachO::LCStruct)); \
  190. BytesWritten = sizeof(MachO::LCStruct); \
  191. BytesWritten += \
  192. writeLoadCommandData<MachO::LCStruct>(LC, OS, Obj.IsLittleEndian); \
  193. break;
  194. switch (LC.Data.load_command_data.cmd) {
  195. default:
  196. if (Obj.IsLittleEndian != sys::IsLittleEndianHost)
  197. MachO::swapStruct(Data.load_command_data);
  198. OS.write(reinterpret_cast<const char *>(&(Data.load_command_data)),
  199. sizeof(MachO::load_command));
  200. BytesWritten = sizeof(MachO::load_command);
  201. BytesWritten +=
  202. writeLoadCommandData<MachO::load_command>(LC, OS, Obj.IsLittleEndian);
  203. break;
  204. #include "llvm/BinaryFormat/MachO.def"
  205. }
  206. if (LC.PayloadBytes.size() > 0) {
  207. OS.write(reinterpret_cast<const char *>(LC.PayloadBytes.data()),
  208. LC.PayloadBytes.size());
  209. BytesWritten += LC.PayloadBytes.size();
  210. }
  211. if (LC.ZeroPadBytes > 0) {
  212. ZeroFillBytes(OS, LC.ZeroPadBytes);
  213. BytesWritten += LC.ZeroPadBytes;
  214. }
  215. // Fill remaining bytes with 0. This will only get hit in partially
  216. // specified test cases.
  217. auto BytesRemaining = LC.Data.load_command_data.cmdsize - BytesWritten;
  218. if (BytesRemaining > 0) {
  219. ZeroFillBytes(OS, BytesRemaining);
  220. }
  221. }
  222. }
  223. void MachOWriter::writeSectionData(raw_ostream &OS) {
  224. bool FoundLinkEditSeg = false;
  225. for (auto &LC : Obj.LoadCommands) {
  226. switch (LC.Data.load_command_data.cmd) {
  227. case MachO::LC_SEGMENT:
  228. case MachO::LC_SEGMENT_64:
  229. uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff
  230. : LC.Data.segment_command_data.fileoff;
  231. if (0 ==
  232. strncmp(&LC.Data.segment_command_data.segname[0], "__LINKEDIT", 16)) {
  233. FoundLinkEditSeg = true;
  234. writeLinkEditData(OS);
  235. }
  236. for (auto &Sec : LC.Sections) {
  237. ZeroToOffset(OS, Sec.offset);
  238. // Zero Fill any data between the end of the last thing we wrote and the
  239. // start of this section.
  240. assert((OS.tell() - fileStart <= Sec.offset ||
  241. Sec.offset == (uint32_t)0) &&
  242. "Wrote too much data somewhere, section offsets don't line up.");
  243. if (0 == strncmp(&Sec.segname[0], "__DWARF", 16)) {
  244. if (0 == strncmp(&Sec.sectname[0], "__debug_str", 16)) {
  245. DWARFYAML::EmitDebugStr(OS, Obj.DWARF);
  246. } else if (0 == strncmp(&Sec.sectname[0], "__debug_abbrev", 16)) {
  247. DWARFYAML::EmitDebugAbbrev(OS, Obj.DWARF);
  248. } else if (0 == strncmp(&Sec.sectname[0], "__debug_aranges", 16)) {
  249. DWARFYAML::EmitDebugAranges(OS, Obj.DWARF);
  250. } else if (0 == strncmp(&Sec.sectname[0], "__debug_pubnames", 16)) {
  251. DWARFYAML::EmitPubSection(OS, Obj.DWARF.PubNames,
  252. Obj.IsLittleEndian);
  253. } else if (0 == strncmp(&Sec.sectname[0], "__debug_pubtypes", 16)) {
  254. DWARFYAML::EmitPubSection(OS, Obj.DWARF.PubTypes,
  255. Obj.IsLittleEndian);
  256. } else if (0 == strncmp(&Sec.sectname[0], "__debug_info", 16)) {
  257. DWARFYAML::EmitDebugInfo(OS, Obj.DWARF);
  258. } else if (0 == strncmp(&Sec.sectname[0], "__debug_line", 16)) {
  259. DWARFYAML::EmitDebugLine(OS, Obj.DWARF);
  260. }
  261. continue;
  262. }
  263. // Skip if it's a virtual section.
  264. if (MachO::isVirtualSection(Sec.flags & MachO::SECTION_TYPE))
  265. continue;
  266. if (Sec.content) {
  267. yaml::BinaryRef Content = *Sec.content;
  268. Content.writeAsBinary(OS);
  269. ZeroFillBytes(OS, Sec.size - Content.binary_size());
  270. } else {
  271. // Fill section data with 0xDEADBEEF.
  272. Fill(OS, Sec.size, 0xDEADBEEFu);
  273. }
  274. }
  275. uint64_t segSize = is64Bit ? LC.Data.segment_command_64_data.filesize
  276. : LC.Data.segment_command_data.filesize;
  277. ZeroToOffset(OS, segOff + segSize);
  278. break;
  279. }
  280. }
  281. // Old PPC Object Files didn't have __LINKEDIT segments, the data was just
  282. // stuck at the end of the file.
  283. if (!FoundLinkEditSeg)
  284. writeLinkEditData(OS);
  285. }
  286. void MachOWriter::writeBindOpcodes(
  287. raw_ostream &OS, std::vector<MachOYAML::BindOpcode> &BindOpcodes) {
  288. for (auto Opcode : BindOpcodes) {
  289. uint8_t OpByte = Opcode.Opcode | Opcode.Imm;
  290. OS.write(reinterpret_cast<char *>(&OpByte), 1);
  291. for (auto Data : Opcode.ULEBExtraData) {
  292. encodeULEB128(Data, OS);
  293. }
  294. for (auto Data : Opcode.SLEBExtraData) {
  295. encodeSLEB128(Data, OS);
  296. }
  297. if (!Opcode.Symbol.empty()) {
  298. OS.write(Opcode.Symbol.data(), Opcode.Symbol.size());
  299. OS.write('\0');
  300. }
  301. }
  302. }
  303. void MachOWriter::dumpExportEntry(raw_ostream &OS,
  304. MachOYAML::ExportEntry &Entry) {
  305. encodeSLEB128(Entry.TerminalSize, OS);
  306. if (Entry.TerminalSize > 0) {
  307. encodeSLEB128(Entry.Flags, OS);
  308. if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) {
  309. encodeSLEB128(Entry.Other, OS);
  310. OS << Entry.ImportName;
  311. OS.write('\0');
  312. } else {
  313. encodeSLEB128(Entry.Address, OS);
  314. if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
  315. encodeSLEB128(Entry.Other, OS);
  316. }
  317. }
  318. OS.write(static_cast<uint8_t>(Entry.Children.size()));
  319. for (auto EE : Entry.Children) {
  320. OS << EE.Name;
  321. OS.write('\0');
  322. encodeSLEB128(EE.NodeOffset, OS);
  323. }
  324. for (auto EE : Entry.Children)
  325. dumpExportEntry(OS, EE);
  326. }
  327. void MachOWriter::writeExportTrie(raw_ostream &OS) {
  328. dumpExportEntry(OS, Obj.LinkEdit.ExportTrie);
  329. }
  330. template <typename NListType>
  331. void writeNListEntry(MachOYAML::NListEntry &NLE, raw_ostream &OS,
  332. bool IsLittleEndian) {
  333. NListType ListEntry;
  334. ListEntry.n_strx = NLE.n_strx;
  335. ListEntry.n_type = NLE.n_type;
  336. ListEntry.n_sect = NLE.n_sect;
  337. ListEntry.n_desc = NLE.n_desc;
  338. ListEntry.n_value = NLE.n_value;
  339. if (IsLittleEndian != sys::IsLittleEndianHost)
  340. MachO::swapStruct(ListEntry);
  341. OS.write(reinterpret_cast<const char *>(&ListEntry), sizeof(NListType));
  342. }
  343. void MachOWriter::writeLinkEditData(raw_ostream &OS) {
  344. typedef void (MachOWriter::*writeHandler)(raw_ostream &);
  345. typedef std::pair<uint64_t, writeHandler> writeOperation;
  346. std::vector<writeOperation> WriteQueue;
  347. MachO::dyld_info_command *DyldInfoOnlyCmd = 0;
  348. MachO::symtab_command *SymtabCmd = 0;
  349. for (auto &LC : Obj.LoadCommands) {
  350. switch (LC.Data.load_command_data.cmd) {
  351. case MachO::LC_SYMTAB:
  352. SymtabCmd = &LC.Data.symtab_command_data;
  353. WriteQueue.push_back(
  354. std::make_pair(SymtabCmd->symoff, &MachOWriter::writeNameList));
  355. WriteQueue.push_back(
  356. std::make_pair(SymtabCmd->stroff, &MachOWriter::writeStringTable));
  357. break;
  358. case MachO::LC_DYLD_INFO_ONLY:
  359. DyldInfoOnlyCmd = &LC.Data.dyld_info_command_data;
  360. WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->rebase_off,
  361. &MachOWriter::writeRebaseOpcodes));
  362. WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->bind_off,
  363. &MachOWriter::writeBasicBindOpcodes));
  364. WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->weak_bind_off,
  365. &MachOWriter::writeWeakBindOpcodes));
  366. WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->lazy_bind_off,
  367. &MachOWriter::writeLazyBindOpcodes));
  368. WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->export_off,
  369. &MachOWriter::writeExportTrie));
  370. break;
  371. }
  372. }
  373. llvm::sort(WriteQueue, [](const writeOperation &a, const writeOperation &b) {
  374. return a.first < b.first;
  375. });
  376. for (auto writeOp : WriteQueue) {
  377. ZeroToOffset(OS, writeOp.first);
  378. (this->*writeOp.second)(OS);
  379. }
  380. }
  381. void MachOWriter::writeRebaseOpcodes(raw_ostream &OS) {
  382. MachOYAML::LinkEditData &LinkEdit = Obj.LinkEdit;
  383. for (auto Opcode : LinkEdit.RebaseOpcodes) {
  384. uint8_t OpByte = Opcode.Opcode | Opcode.Imm;
  385. OS.write(reinterpret_cast<char *>(&OpByte), 1);
  386. for (auto Data : Opcode.ExtraData)
  387. encodeULEB128(Data, OS);
  388. }
  389. }
  390. void MachOWriter::writeBasicBindOpcodes(raw_ostream &OS) {
  391. writeBindOpcodes(OS, Obj.LinkEdit.BindOpcodes);
  392. }
  393. void MachOWriter::writeWeakBindOpcodes(raw_ostream &OS) {
  394. writeBindOpcodes(OS, Obj.LinkEdit.WeakBindOpcodes);
  395. }
  396. void MachOWriter::writeLazyBindOpcodes(raw_ostream &OS) {
  397. writeBindOpcodes(OS, Obj.LinkEdit.LazyBindOpcodes);
  398. }
  399. void MachOWriter::writeNameList(raw_ostream &OS) {
  400. for (auto NLE : Obj.LinkEdit.NameList) {
  401. if (is64Bit)
  402. writeNListEntry<MachO::nlist_64>(NLE, OS, Obj.IsLittleEndian);
  403. else
  404. writeNListEntry<MachO::nlist>(NLE, OS, Obj.IsLittleEndian);
  405. }
  406. }
  407. void MachOWriter::writeStringTable(raw_ostream &OS) {
  408. for (auto Str : Obj.LinkEdit.StringTable) {
  409. OS.write(Str.data(), Str.size());
  410. OS.write('\0');
  411. }
  412. }
  413. class UniversalWriter {
  414. public:
  415. UniversalWriter(yaml::YamlObjectFile &ObjectFile)
  416. : ObjectFile(ObjectFile), fileStart(0) {}
  417. void writeMachO(raw_ostream &OS);
  418. private:
  419. void writeFatHeader(raw_ostream &OS);
  420. void writeFatArchs(raw_ostream &OS);
  421. void ZeroToOffset(raw_ostream &OS, size_t offset);
  422. yaml::YamlObjectFile &ObjectFile;
  423. uint64_t fileStart;
  424. };
  425. void UniversalWriter::writeMachO(raw_ostream &OS) {
  426. fileStart = OS.tell();
  427. if (ObjectFile.MachO) {
  428. MachOWriter Writer(*ObjectFile.MachO);
  429. Writer.writeMachO(OS);
  430. return;
  431. }
  432. writeFatHeader(OS);
  433. writeFatArchs(OS);
  434. auto &FatFile = *ObjectFile.FatMachO;
  435. assert(FatFile.FatArchs.size() == FatFile.Slices.size());
  436. for (size_t i = 0; i < FatFile.Slices.size(); i++) {
  437. ZeroToOffset(OS, FatFile.FatArchs[i].offset);
  438. MachOWriter Writer(FatFile.Slices[i]);
  439. Writer.writeMachO(OS);
  440. auto SliceEnd = FatFile.FatArchs[i].offset + FatFile.FatArchs[i].size;
  441. ZeroToOffset(OS, SliceEnd);
  442. }
  443. }
  444. void UniversalWriter::writeFatHeader(raw_ostream &OS) {
  445. auto &FatFile = *ObjectFile.FatMachO;
  446. MachO::fat_header header;
  447. header.magic = FatFile.Header.magic;
  448. header.nfat_arch = FatFile.Header.nfat_arch;
  449. if (sys::IsLittleEndianHost)
  450. swapStruct(header);
  451. OS.write(reinterpret_cast<const char *>(&header), sizeof(MachO::fat_header));
  452. }
  453. template <typename FatArchType>
  454. FatArchType constructFatArch(MachOYAML::FatArch &Arch) {
  455. FatArchType FatArch;
  456. FatArch.cputype = Arch.cputype;
  457. FatArch.cpusubtype = Arch.cpusubtype;
  458. FatArch.offset = Arch.offset;
  459. FatArch.size = Arch.size;
  460. FatArch.align = Arch.align;
  461. return FatArch;
  462. }
  463. template <typename StructType>
  464. void writeFatArch(MachOYAML::FatArch &LC, raw_ostream &OS) {}
  465. template <>
  466. void writeFatArch<MachO::fat_arch>(MachOYAML::FatArch &Arch, raw_ostream &OS) {
  467. auto FatArch = constructFatArch<MachO::fat_arch>(Arch);
  468. if (sys::IsLittleEndianHost)
  469. swapStruct(FatArch);
  470. OS.write(reinterpret_cast<const char *>(&FatArch), sizeof(MachO::fat_arch));
  471. }
  472. template <>
  473. void writeFatArch<MachO::fat_arch_64>(MachOYAML::FatArch &Arch,
  474. raw_ostream &OS) {
  475. auto FatArch = constructFatArch<MachO::fat_arch_64>(Arch);
  476. FatArch.reserved = Arch.reserved;
  477. if (sys::IsLittleEndianHost)
  478. swapStruct(FatArch);
  479. OS.write(reinterpret_cast<const char *>(&FatArch),
  480. sizeof(MachO::fat_arch_64));
  481. }
  482. void UniversalWriter::writeFatArchs(raw_ostream &OS) {
  483. auto &FatFile = *ObjectFile.FatMachO;
  484. bool is64Bit = FatFile.Header.magic == MachO::FAT_MAGIC_64;
  485. for (auto Arch : FatFile.FatArchs) {
  486. if (is64Bit)
  487. writeFatArch<MachO::fat_arch_64>(Arch, OS);
  488. else
  489. writeFatArch<MachO::fat_arch>(Arch, OS);
  490. }
  491. }
  492. void UniversalWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) {
  493. auto currOffset = OS.tell() - fileStart;
  494. if (currOffset < Offset)
  495. ZeroFillBytes(OS, Offset - currOffset);
  496. }
  497. } // end anonymous namespace
  498. namespace llvm {
  499. namespace yaml {
  500. bool yaml2macho(YamlObjectFile &Doc, raw_ostream &Out, ErrorHandler /*EH*/) {
  501. UniversalWriter Writer(Doc);
  502. Writer.writeMachO(Out);
  503. return true;
  504. }
  505. } // namespace yaml
  506. } // namespace llvm