MachOEmitter.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  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/Errc.h"
  18. #include "llvm/Support/Error.h"
  19. #include "llvm/Support/FormatVariadic.h"
  20. #include "llvm/Support/LEB128.h"
  21. #include "llvm/Support/YAMLTraits.h"
  22. #include "llvm/Support/raw_ostream.h"
  23. #include "llvm/Support/Format.h"
  24. using namespace llvm;
  25. namespace {
  26. class MachOWriter {
  27. public:
  28. MachOWriter(MachOYAML::Object &Obj) : Obj(Obj), fileStart(0) {
  29. is64Bit = Obj.Header.magic == MachO::MH_MAGIC_64 ||
  30. Obj.Header.magic == MachO::MH_CIGAM_64;
  31. memset(reinterpret_cast<void *>(&Header), 0, sizeof(MachO::mach_header_64));
  32. }
  33. Error writeMachO(raw_ostream &OS);
  34. private:
  35. void writeHeader(raw_ostream &OS);
  36. void writeLoadCommands(raw_ostream &OS);
  37. Error writeSectionData(raw_ostream &OS);
  38. void writeRelocations(raw_ostream &OS);
  39. void writeLinkEditData(raw_ostream &OS);
  40. void writeBindOpcodes(raw_ostream &OS,
  41. std::vector<MachOYAML::BindOpcode> &BindOpcodes);
  42. // LinkEdit writers
  43. void writeRebaseOpcodes(raw_ostream &OS);
  44. void writeBasicBindOpcodes(raw_ostream &OS);
  45. void writeWeakBindOpcodes(raw_ostream &OS);
  46. void writeLazyBindOpcodes(raw_ostream &OS);
  47. void writeNameList(raw_ostream &OS);
  48. void writeStringTable(raw_ostream &OS);
  49. void writeExportTrie(raw_ostream &OS);
  50. void writeDynamicSymbolTable(raw_ostream &OS);
  51. void writeFunctionStarts(raw_ostream &OS);
  52. void writeChainedFixups(raw_ostream &OS);
  53. void writeDyldExportsTrie(raw_ostream &OS);
  54. void writeDataInCode(raw_ostream &OS);
  55. void dumpExportEntry(raw_ostream &OS, MachOYAML::ExportEntry &Entry);
  56. void ZeroToOffset(raw_ostream &OS, size_t offset);
  57. MachOYAML::Object &Obj;
  58. bool is64Bit;
  59. uint64_t fileStart;
  60. MachO::mach_header_64 Header;
  61. // Old PPC Object Files didn't have __LINKEDIT segments, the data was just
  62. // stuck at the end of the file.
  63. bool FoundLinkEditSeg = false;
  64. };
  65. Error MachOWriter::writeMachO(raw_ostream &OS) {
  66. fileStart = OS.tell();
  67. writeHeader(OS);
  68. writeLoadCommands(OS);
  69. if (Error Err = writeSectionData(OS))
  70. return Err;
  71. writeRelocations(OS);
  72. if (!FoundLinkEditSeg)
  73. writeLinkEditData(OS);
  74. return Error::success();
  75. }
  76. void MachOWriter::writeHeader(raw_ostream &OS) {
  77. Header.magic = Obj.Header.magic;
  78. Header.cputype = Obj.Header.cputype;
  79. Header.cpusubtype = Obj.Header.cpusubtype;
  80. Header.filetype = Obj.Header.filetype;
  81. Header.ncmds = Obj.Header.ncmds;
  82. Header.sizeofcmds = Obj.Header.sizeofcmds;
  83. Header.flags = Obj.Header.flags;
  84. Header.reserved = Obj.Header.reserved;
  85. if (Obj.IsLittleEndian != sys::IsLittleEndianHost)
  86. MachO::swapStruct(Header);
  87. auto header_size =
  88. is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
  89. OS.write((const char *)&Header, header_size);
  90. }
  91. template <typename SectionType>
  92. SectionType constructSection(MachOYAML::Section Sec) {
  93. SectionType TempSec;
  94. memcpy(reinterpret_cast<void *>(&TempSec.sectname[0]), &Sec.sectname[0], 16);
  95. memcpy(reinterpret_cast<void *>(&TempSec.segname[0]), &Sec.segname[0], 16);
  96. TempSec.addr = Sec.addr;
  97. TempSec.size = Sec.size;
  98. TempSec.offset = Sec.offset;
  99. TempSec.align = Sec.align;
  100. TempSec.reloff = Sec.reloff;
  101. TempSec.nreloc = Sec.nreloc;
  102. TempSec.flags = Sec.flags;
  103. TempSec.reserved1 = Sec.reserved1;
  104. TempSec.reserved2 = Sec.reserved2;
  105. return TempSec;
  106. }
  107. template <typename StructType>
  108. size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS,
  109. bool IsLittleEndian) {
  110. return 0;
  111. }
  112. template <>
  113. size_t writeLoadCommandData<MachO::segment_command>(MachOYAML::LoadCommand &LC,
  114. raw_ostream &OS,
  115. bool IsLittleEndian) {
  116. size_t BytesWritten = 0;
  117. for (const auto &Sec : LC.Sections) {
  118. auto TempSec = constructSection<MachO::section>(Sec);
  119. if (IsLittleEndian != sys::IsLittleEndianHost)
  120. MachO::swapStruct(TempSec);
  121. OS.write(reinterpret_cast<const char *>(&(TempSec)),
  122. sizeof(MachO::section));
  123. BytesWritten += sizeof(MachO::section);
  124. }
  125. return BytesWritten;
  126. }
  127. template <>
  128. size_t writeLoadCommandData<MachO::segment_command_64>(
  129. MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
  130. size_t BytesWritten = 0;
  131. for (const auto &Sec : LC.Sections) {
  132. auto TempSec = constructSection<MachO::section_64>(Sec);
  133. TempSec.reserved3 = Sec.reserved3;
  134. if (IsLittleEndian != sys::IsLittleEndianHost)
  135. MachO::swapStruct(TempSec);
  136. OS.write(reinterpret_cast<const char *>(&(TempSec)),
  137. sizeof(MachO::section_64));
  138. BytesWritten += sizeof(MachO::section_64);
  139. }
  140. return BytesWritten;
  141. }
  142. size_t writePayloadString(MachOYAML::LoadCommand &LC, raw_ostream &OS) {
  143. size_t BytesWritten = 0;
  144. if (!LC.Content.empty()) {
  145. OS.write(LC.Content.c_str(), LC.Content.length());
  146. BytesWritten = LC.Content.length();
  147. }
  148. return BytesWritten;
  149. }
  150. template <>
  151. size_t writeLoadCommandData<MachO::dylib_command>(MachOYAML::LoadCommand &LC,
  152. raw_ostream &OS,
  153. bool IsLittleEndian) {
  154. return writePayloadString(LC, OS);
  155. }
  156. template <>
  157. size_t writeLoadCommandData<MachO::dylinker_command>(MachOYAML::LoadCommand &LC,
  158. raw_ostream &OS,
  159. bool IsLittleEndian) {
  160. return writePayloadString(LC, OS);
  161. }
  162. template <>
  163. size_t writeLoadCommandData<MachO::rpath_command>(MachOYAML::LoadCommand &LC,
  164. raw_ostream &OS,
  165. bool IsLittleEndian) {
  166. return writePayloadString(LC, OS);
  167. }
  168. template <>
  169. size_t writeLoadCommandData<MachO::sub_framework_command>(
  170. MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
  171. return writePayloadString(LC, OS);
  172. }
  173. template <>
  174. size_t writeLoadCommandData<MachO::sub_umbrella_command>(
  175. MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
  176. return writePayloadString(LC, OS);
  177. }
  178. template <>
  179. size_t writeLoadCommandData<MachO::sub_client_command>(
  180. MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
  181. return writePayloadString(LC, OS);
  182. }
  183. template <>
  184. size_t writeLoadCommandData<MachO::sub_library_command>(
  185. MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
  186. return writePayloadString(LC, OS);
  187. }
  188. template <>
  189. size_t writeLoadCommandData<MachO::build_version_command>(
  190. MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
  191. size_t BytesWritten = 0;
  192. for (const auto &T : LC.Tools) {
  193. struct MachO::build_tool_version tool = T;
  194. if (IsLittleEndian != sys::IsLittleEndianHost)
  195. MachO::swapStruct(tool);
  196. OS.write(reinterpret_cast<const char *>(&tool),
  197. sizeof(MachO::build_tool_version));
  198. BytesWritten += sizeof(MachO::build_tool_version);
  199. }
  200. return BytesWritten;
  201. }
  202. void ZeroFillBytes(raw_ostream &OS, size_t Size) {
  203. std::vector<uint8_t> FillData(Size, 0);
  204. OS.write(reinterpret_cast<char *>(FillData.data()), Size);
  205. }
  206. void Fill(raw_ostream &OS, size_t Size, uint32_t Data) {
  207. std::vector<uint32_t> FillData((Size / 4) + 1, Data);
  208. OS.write(reinterpret_cast<char *>(FillData.data()), Size);
  209. }
  210. void MachOWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) {
  211. auto currOffset = OS.tell() - fileStart;
  212. if (currOffset < Offset)
  213. ZeroFillBytes(OS, Offset - currOffset);
  214. }
  215. void MachOWriter::writeLoadCommands(raw_ostream &OS) {
  216. for (auto &LC : Obj.LoadCommands) {
  217. size_t BytesWritten = 0;
  218. llvm::MachO::macho_load_command Data = LC.Data;
  219. #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
  220. case MachO::LCName: \
  221. if (Obj.IsLittleEndian != sys::IsLittleEndianHost) \
  222. MachO::swapStruct(Data.LCStruct##_data); \
  223. OS.write(reinterpret_cast<const char *>(&(Data.LCStruct##_data)), \
  224. sizeof(MachO::LCStruct)); \
  225. BytesWritten = sizeof(MachO::LCStruct); \
  226. BytesWritten += \
  227. writeLoadCommandData<MachO::LCStruct>(LC, OS, Obj.IsLittleEndian); \
  228. break;
  229. switch (LC.Data.load_command_data.cmd) {
  230. default:
  231. if (Obj.IsLittleEndian != sys::IsLittleEndianHost)
  232. MachO::swapStruct(Data.load_command_data);
  233. OS.write(reinterpret_cast<const char *>(&(Data.load_command_data)),
  234. sizeof(MachO::load_command));
  235. BytesWritten = sizeof(MachO::load_command);
  236. BytesWritten +=
  237. writeLoadCommandData<MachO::load_command>(LC, OS, Obj.IsLittleEndian);
  238. break;
  239. #include "llvm/BinaryFormat/MachO.def"
  240. }
  241. if (LC.PayloadBytes.size() > 0) {
  242. OS.write(reinterpret_cast<const char *>(LC.PayloadBytes.data()),
  243. LC.PayloadBytes.size());
  244. BytesWritten += LC.PayloadBytes.size();
  245. }
  246. if (LC.ZeroPadBytes > 0) {
  247. ZeroFillBytes(OS, LC.ZeroPadBytes);
  248. BytesWritten += LC.ZeroPadBytes;
  249. }
  250. // Fill remaining bytes with 0. This will only get hit in partially
  251. // specified test cases.
  252. auto BytesRemaining = LC.Data.load_command_data.cmdsize - BytesWritten;
  253. if (BytesRemaining > 0) {
  254. ZeroFillBytes(OS, BytesRemaining);
  255. }
  256. }
  257. }
  258. Error MachOWriter::writeSectionData(raw_ostream &OS) {
  259. uint64_t LinkEditOff = 0;
  260. for (auto &LC : Obj.LoadCommands) {
  261. switch (LC.Data.load_command_data.cmd) {
  262. case MachO::LC_SEGMENT:
  263. case MachO::LC_SEGMENT_64:
  264. uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff
  265. : LC.Data.segment_command_data.fileoff;
  266. if (0 ==
  267. strncmp(&LC.Data.segment_command_data.segname[0], "__LINKEDIT", 16)) {
  268. FoundLinkEditSeg = true;
  269. LinkEditOff = segOff;
  270. if (Obj.RawLinkEditSegment)
  271. continue;
  272. writeLinkEditData(OS);
  273. }
  274. for (auto &Sec : LC.Sections) {
  275. ZeroToOffset(OS, Sec.offset);
  276. // Zero Fill any data between the end of the last thing we wrote and the
  277. // start of this section.
  278. if (OS.tell() - fileStart > Sec.offset && Sec.offset != (uint32_t)0)
  279. return createStringError(
  280. errc::invalid_argument,
  281. llvm::formatv(
  282. "wrote too much data somewhere, section offsets in "
  283. "section {0} for segment {1} don't line up: "
  284. "[cursor={2:x}], [fileStart={3:x}], [sectionOffset={4:x}]",
  285. Sec.sectname, Sec.segname, OS.tell(), fileStart,
  286. Sec.offset.value));
  287. StringRef SectName(Sec.sectname,
  288. strnlen(Sec.sectname, sizeof(Sec.sectname)));
  289. // If the section's content is specified in the 'DWARF' entry, we will
  290. // emit it regardless of the section's segname.
  291. if (Obj.DWARF.getNonEmptySectionNames().count(SectName.substr(2))) {
  292. if (Sec.content)
  293. return createStringError(errc::invalid_argument,
  294. "cannot specify section '" + SectName +
  295. "' contents in the 'DWARF' entry and "
  296. "the 'content' at the same time");
  297. auto EmitFunc = DWARFYAML::getDWARFEmitterByName(SectName.substr(2));
  298. if (Error Err = EmitFunc(OS, Obj.DWARF))
  299. return Err;
  300. continue;
  301. }
  302. // Skip if it's a virtual section.
  303. if (MachO::isVirtualSection(Sec.flags & MachO::SECTION_TYPE))
  304. continue;
  305. if (Sec.content) {
  306. yaml::BinaryRef Content = *Sec.content;
  307. Content.writeAsBinary(OS);
  308. ZeroFillBytes(OS, Sec.size - Content.binary_size());
  309. } else {
  310. // Fill section data with 0xDEADBEEF.
  311. Fill(OS, Sec.size, 0xDEADBEEFu);
  312. }
  313. }
  314. uint64_t segSize = is64Bit ? LC.Data.segment_command_64_data.filesize
  315. : LC.Data.segment_command_data.filesize;
  316. ZeroToOffset(OS, segOff + segSize);
  317. break;
  318. }
  319. }
  320. if (Obj.RawLinkEditSegment) {
  321. ZeroToOffset(OS, LinkEditOff);
  322. if (OS.tell() - fileStart > LinkEditOff || !LinkEditOff)
  323. return createStringError(errc::invalid_argument,
  324. "section offsets don't line up");
  325. Obj.RawLinkEditSegment->writeAsBinary(OS);
  326. }
  327. return Error::success();
  328. }
  329. // The implementation of makeRelocationInfo and makeScatteredRelocationInfo is
  330. // consistent with how libObject parses MachO binary files. For the reference
  331. // see getStruct, getRelocation, getPlainRelocationPCRel,
  332. // getPlainRelocationLength and related methods in MachOObjectFile.cpp
  333. static MachO::any_relocation_info
  334. makeRelocationInfo(const MachOYAML::Relocation &R, bool IsLE) {
  335. assert(!R.is_scattered && "non-scattered relocation expected");
  336. MachO::any_relocation_info MRE;
  337. MRE.r_word0 = R.address;
  338. if (IsLE)
  339. MRE.r_word1 = ((unsigned)R.symbolnum << 0) | ((unsigned)R.is_pcrel << 24) |
  340. ((unsigned)R.length << 25) | ((unsigned)R.is_extern << 27) |
  341. ((unsigned)R.type << 28);
  342. else
  343. MRE.r_word1 = ((unsigned)R.symbolnum << 8) | ((unsigned)R.is_pcrel << 7) |
  344. ((unsigned)R.length << 5) | ((unsigned)R.is_extern << 4) |
  345. ((unsigned)R.type << 0);
  346. return MRE;
  347. }
  348. static MachO::any_relocation_info
  349. makeScatteredRelocationInfo(const MachOYAML::Relocation &R) {
  350. assert(R.is_scattered && "scattered relocation expected");
  351. MachO::any_relocation_info MRE;
  352. MRE.r_word0 = (((unsigned)R.address << 0) | ((unsigned)R.type << 24) |
  353. ((unsigned)R.length << 28) | ((unsigned)R.is_pcrel << 30) |
  354. MachO::R_SCATTERED);
  355. MRE.r_word1 = R.value;
  356. return MRE;
  357. }
  358. void MachOWriter::writeRelocations(raw_ostream &OS) {
  359. for (const MachOYAML::LoadCommand &LC : Obj.LoadCommands) {
  360. switch (LC.Data.load_command_data.cmd) {
  361. case MachO::LC_SEGMENT:
  362. case MachO::LC_SEGMENT_64:
  363. for (const MachOYAML::Section &Sec : LC.Sections) {
  364. if (Sec.relocations.empty())
  365. continue;
  366. ZeroToOffset(OS, Sec.reloff);
  367. for (const MachOYAML::Relocation &R : Sec.relocations) {
  368. MachO::any_relocation_info MRE =
  369. R.is_scattered ? makeScatteredRelocationInfo(R)
  370. : makeRelocationInfo(R, Obj.IsLittleEndian);
  371. if (Obj.IsLittleEndian != sys::IsLittleEndianHost)
  372. MachO::swapStruct(MRE);
  373. OS.write(reinterpret_cast<const char *>(&MRE),
  374. sizeof(MachO::any_relocation_info));
  375. }
  376. }
  377. }
  378. }
  379. }
  380. void MachOWriter::writeBindOpcodes(
  381. raw_ostream &OS, std::vector<MachOYAML::BindOpcode> &BindOpcodes) {
  382. for (auto Opcode : BindOpcodes) {
  383. uint8_t OpByte = Opcode.Opcode | Opcode.Imm;
  384. OS.write(reinterpret_cast<char *>(&OpByte), 1);
  385. for (auto Data : Opcode.ULEBExtraData) {
  386. encodeULEB128(Data, OS);
  387. }
  388. for (auto Data : Opcode.SLEBExtraData) {
  389. encodeSLEB128(Data, OS);
  390. }
  391. if (!Opcode.Symbol.empty()) {
  392. OS.write(Opcode.Symbol.data(), Opcode.Symbol.size());
  393. OS.write('\0');
  394. }
  395. }
  396. }
  397. void MachOWriter::dumpExportEntry(raw_ostream &OS,
  398. MachOYAML::ExportEntry &Entry) {
  399. encodeULEB128(Entry.TerminalSize, OS);
  400. if (Entry.TerminalSize > 0) {
  401. encodeULEB128(Entry.Flags, OS);
  402. if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) {
  403. encodeULEB128(Entry.Other, OS);
  404. OS << Entry.ImportName;
  405. OS.write('\0');
  406. } else {
  407. encodeULEB128(Entry.Address, OS);
  408. if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
  409. encodeULEB128(Entry.Other, OS);
  410. }
  411. }
  412. OS.write(static_cast<uint8_t>(Entry.Children.size()));
  413. for (auto EE : Entry.Children) {
  414. OS << EE.Name;
  415. OS.write('\0');
  416. encodeULEB128(EE.NodeOffset, OS);
  417. }
  418. for (auto EE : Entry.Children)
  419. dumpExportEntry(OS, EE);
  420. }
  421. void MachOWriter::writeExportTrie(raw_ostream &OS) {
  422. dumpExportEntry(OS, Obj.LinkEdit.ExportTrie);
  423. }
  424. template <typename NListType>
  425. void writeNListEntry(MachOYAML::NListEntry &NLE, raw_ostream &OS,
  426. bool IsLittleEndian) {
  427. NListType ListEntry;
  428. ListEntry.n_strx = NLE.n_strx;
  429. ListEntry.n_type = NLE.n_type;
  430. ListEntry.n_sect = NLE.n_sect;
  431. ListEntry.n_desc = NLE.n_desc;
  432. ListEntry.n_value = NLE.n_value;
  433. if (IsLittleEndian != sys::IsLittleEndianHost)
  434. MachO::swapStruct(ListEntry);
  435. OS.write(reinterpret_cast<const char *>(&ListEntry), sizeof(NListType));
  436. }
  437. void MachOWriter::writeLinkEditData(raw_ostream &OS) {
  438. typedef void (MachOWriter::*writeHandler)(raw_ostream &);
  439. typedef std::pair<uint64_t, writeHandler> writeOperation;
  440. std::vector<writeOperation> WriteQueue;
  441. MachO::dyld_info_command *DyldInfoOnlyCmd = nullptr;
  442. MachO::symtab_command *SymtabCmd = nullptr;
  443. MachO::dysymtab_command *DSymtabCmd = nullptr;
  444. MachO::linkedit_data_command *FunctionStartsCmd = nullptr;
  445. MachO::linkedit_data_command *ChainedFixupsCmd = nullptr;
  446. MachO::linkedit_data_command *DyldExportsTrieCmd = nullptr;
  447. MachO::linkedit_data_command *DataInCodeCmd = nullptr;
  448. for (auto &LC : Obj.LoadCommands) {
  449. switch (LC.Data.load_command_data.cmd) {
  450. case MachO::LC_SYMTAB:
  451. SymtabCmd = &LC.Data.symtab_command_data;
  452. WriteQueue.push_back(
  453. std::make_pair(SymtabCmd->symoff, &MachOWriter::writeNameList));
  454. WriteQueue.push_back(
  455. std::make_pair(SymtabCmd->stroff, &MachOWriter::writeStringTable));
  456. break;
  457. case MachO::LC_DYLD_INFO_ONLY:
  458. DyldInfoOnlyCmd = &LC.Data.dyld_info_command_data;
  459. WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->rebase_off,
  460. &MachOWriter::writeRebaseOpcodes));
  461. WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->bind_off,
  462. &MachOWriter::writeBasicBindOpcodes));
  463. WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->weak_bind_off,
  464. &MachOWriter::writeWeakBindOpcodes));
  465. WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->lazy_bind_off,
  466. &MachOWriter::writeLazyBindOpcodes));
  467. WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->export_off,
  468. &MachOWriter::writeExportTrie));
  469. break;
  470. case MachO::LC_DYSYMTAB:
  471. DSymtabCmd = &LC.Data.dysymtab_command_data;
  472. WriteQueue.push_back(std::make_pair(
  473. DSymtabCmd->indirectsymoff, &MachOWriter::writeDynamicSymbolTable));
  474. break;
  475. case MachO::LC_FUNCTION_STARTS:
  476. FunctionStartsCmd = &LC.Data.linkedit_data_command_data;
  477. WriteQueue.push_back(std::make_pair(FunctionStartsCmd->dataoff,
  478. &MachOWriter::writeFunctionStarts));
  479. break;
  480. case MachO::LC_DYLD_CHAINED_FIXUPS:
  481. ChainedFixupsCmd = &LC.Data.linkedit_data_command_data;
  482. WriteQueue.push_back(std::make_pair(ChainedFixupsCmd->dataoff,
  483. &MachOWriter::writeChainedFixups));
  484. break;
  485. case MachO::LC_DYLD_EXPORTS_TRIE:
  486. DyldExportsTrieCmd = &LC.Data.linkedit_data_command_data;
  487. WriteQueue.push_back(std::make_pair(DyldExportsTrieCmd->dataoff,
  488. &MachOWriter::writeDyldExportsTrie));
  489. break;
  490. case MachO::LC_DATA_IN_CODE:
  491. DataInCodeCmd = &LC.Data.linkedit_data_command_data;
  492. WriteQueue.push_back(std::make_pair(DataInCodeCmd->dataoff,
  493. &MachOWriter::writeDataInCode));
  494. break;
  495. }
  496. }
  497. llvm::sort(WriteQueue, llvm::less_first());
  498. for (auto writeOp : WriteQueue) {
  499. ZeroToOffset(OS, writeOp.first);
  500. (this->*writeOp.second)(OS);
  501. }
  502. }
  503. void MachOWriter::writeRebaseOpcodes(raw_ostream &OS) {
  504. MachOYAML::LinkEditData &LinkEdit = Obj.LinkEdit;
  505. for (auto Opcode : LinkEdit.RebaseOpcodes) {
  506. uint8_t OpByte = Opcode.Opcode | Opcode.Imm;
  507. OS.write(reinterpret_cast<char *>(&OpByte), 1);
  508. for (auto Data : Opcode.ExtraData)
  509. encodeULEB128(Data, OS);
  510. }
  511. }
  512. void MachOWriter::writeBasicBindOpcodes(raw_ostream &OS) {
  513. writeBindOpcodes(OS, Obj.LinkEdit.BindOpcodes);
  514. }
  515. void MachOWriter::writeWeakBindOpcodes(raw_ostream &OS) {
  516. writeBindOpcodes(OS, Obj.LinkEdit.WeakBindOpcodes);
  517. }
  518. void MachOWriter::writeLazyBindOpcodes(raw_ostream &OS) {
  519. writeBindOpcodes(OS, Obj.LinkEdit.LazyBindOpcodes);
  520. }
  521. void MachOWriter::writeNameList(raw_ostream &OS) {
  522. for (auto NLE : Obj.LinkEdit.NameList) {
  523. if (is64Bit)
  524. writeNListEntry<MachO::nlist_64>(NLE, OS, Obj.IsLittleEndian);
  525. else
  526. writeNListEntry<MachO::nlist>(NLE, OS, Obj.IsLittleEndian);
  527. }
  528. }
  529. void MachOWriter::writeStringTable(raw_ostream &OS) {
  530. for (auto Str : Obj.LinkEdit.StringTable) {
  531. OS.write(Str.data(), Str.size());
  532. OS.write('\0');
  533. }
  534. }
  535. void MachOWriter::writeDynamicSymbolTable(raw_ostream &OS) {
  536. for (auto Data : Obj.LinkEdit.IndirectSymbols)
  537. OS.write(reinterpret_cast<const char *>(&Data),
  538. sizeof(yaml::Hex32::BaseType));
  539. }
  540. void MachOWriter::writeFunctionStarts(raw_ostream &OS) {
  541. uint64_t Addr = 0;
  542. for (uint64_t NextAddr : Obj.LinkEdit.FunctionStarts) {
  543. uint64_t Delta = NextAddr - Addr;
  544. encodeULEB128(Delta, OS);
  545. Addr = NextAddr;
  546. }
  547. OS.write('\0');
  548. }
  549. void MachOWriter::writeDataInCode(raw_ostream &OS) {
  550. for (const auto &Entry : Obj.LinkEdit.DataInCode) {
  551. MachO::data_in_code_entry DICE{Entry.Offset, Entry.Length, Entry.Kind};
  552. if (Obj.IsLittleEndian != sys::IsLittleEndianHost)
  553. MachO::swapStruct(DICE);
  554. OS.write(reinterpret_cast<const char *>(&DICE),
  555. sizeof(MachO::data_in_code_entry));
  556. }
  557. }
  558. void MachOWriter::writeChainedFixups(raw_ostream &OS) {
  559. if (Obj.LinkEdit.ChainedFixups.size() > 0)
  560. OS.write(reinterpret_cast<const char *>(Obj.LinkEdit.ChainedFixups.data()),
  561. Obj.LinkEdit.ChainedFixups.size());
  562. }
  563. void MachOWriter::writeDyldExportsTrie(raw_ostream &OS) {
  564. dumpExportEntry(OS, Obj.LinkEdit.ExportTrie);
  565. }
  566. class UniversalWriter {
  567. public:
  568. UniversalWriter(yaml::YamlObjectFile &ObjectFile)
  569. : ObjectFile(ObjectFile), fileStart(0) {}
  570. Error writeMachO(raw_ostream &OS);
  571. private:
  572. void writeFatHeader(raw_ostream &OS);
  573. void writeFatArchs(raw_ostream &OS);
  574. void ZeroToOffset(raw_ostream &OS, size_t offset);
  575. yaml::YamlObjectFile &ObjectFile;
  576. uint64_t fileStart;
  577. };
  578. Error UniversalWriter::writeMachO(raw_ostream &OS) {
  579. fileStart = OS.tell();
  580. if (ObjectFile.MachO) {
  581. MachOWriter Writer(*ObjectFile.MachO);
  582. return Writer.writeMachO(OS);
  583. }
  584. writeFatHeader(OS);
  585. writeFatArchs(OS);
  586. auto &FatFile = *ObjectFile.FatMachO;
  587. if (FatFile.FatArchs.size() < FatFile.Slices.size())
  588. return createStringError(
  589. errc::invalid_argument,
  590. "cannot write 'Slices' if not described in 'FatArches'");
  591. for (size_t i = 0; i < FatFile.Slices.size(); i++) {
  592. ZeroToOffset(OS, FatFile.FatArchs[i].offset);
  593. MachOWriter Writer(FatFile.Slices[i]);
  594. if (Error Err = Writer.writeMachO(OS))
  595. return Err;
  596. auto SliceEnd = FatFile.FatArchs[i].offset + FatFile.FatArchs[i].size;
  597. ZeroToOffset(OS, SliceEnd);
  598. }
  599. return Error::success();
  600. }
  601. void UniversalWriter::writeFatHeader(raw_ostream &OS) {
  602. auto &FatFile = *ObjectFile.FatMachO;
  603. MachO::fat_header header;
  604. header.magic = FatFile.Header.magic;
  605. header.nfat_arch = FatFile.Header.nfat_arch;
  606. if (sys::IsLittleEndianHost)
  607. swapStruct(header);
  608. OS.write(reinterpret_cast<const char *>(&header), sizeof(MachO::fat_header));
  609. }
  610. template <typename FatArchType>
  611. FatArchType constructFatArch(MachOYAML::FatArch &Arch) {
  612. FatArchType FatArch;
  613. FatArch.cputype = Arch.cputype;
  614. FatArch.cpusubtype = Arch.cpusubtype;
  615. FatArch.offset = Arch.offset;
  616. FatArch.size = Arch.size;
  617. FatArch.align = Arch.align;
  618. return FatArch;
  619. }
  620. template <typename StructType>
  621. void writeFatArch(MachOYAML::FatArch &LC, raw_ostream &OS) {}
  622. template <>
  623. void writeFatArch<MachO::fat_arch>(MachOYAML::FatArch &Arch, raw_ostream &OS) {
  624. auto FatArch = constructFatArch<MachO::fat_arch>(Arch);
  625. if (sys::IsLittleEndianHost)
  626. swapStruct(FatArch);
  627. OS.write(reinterpret_cast<const char *>(&FatArch), sizeof(MachO::fat_arch));
  628. }
  629. template <>
  630. void writeFatArch<MachO::fat_arch_64>(MachOYAML::FatArch &Arch,
  631. raw_ostream &OS) {
  632. auto FatArch = constructFatArch<MachO::fat_arch_64>(Arch);
  633. FatArch.reserved = Arch.reserved;
  634. if (sys::IsLittleEndianHost)
  635. swapStruct(FatArch);
  636. OS.write(reinterpret_cast<const char *>(&FatArch),
  637. sizeof(MachO::fat_arch_64));
  638. }
  639. void UniversalWriter::writeFatArchs(raw_ostream &OS) {
  640. auto &FatFile = *ObjectFile.FatMachO;
  641. bool is64Bit = FatFile.Header.magic == MachO::FAT_MAGIC_64;
  642. for (auto Arch : FatFile.FatArchs) {
  643. if (is64Bit)
  644. writeFatArch<MachO::fat_arch_64>(Arch, OS);
  645. else
  646. writeFatArch<MachO::fat_arch>(Arch, OS);
  647. }
  648. }
  649. void UniversalWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) {
  650. auto currOffset = OS.tell() - fileStart;
  651. if (currOffset < Offset)
  652. ZeroFillBytes(OS, Offset - currOffset);
  653. }
  654. } // end anonymous namespace
  655. namespace llvm {
  656. namespace yaml {
  657. bool yaml2macho(YamlObjectFile &Doc, raw_ostream &Out, ErrorHandler EH) {
  658. UniversalWriter Writer(Doc);
  659. if (Error Err = Writer.writeMachO(Out)) {
  660. handleAllErrors(std::move(Err),
  661. [&](const ErrorInfoBase &Err) { EH(Err.message()); });
  662. return false;
  663. }
  664. return true;
  665. }
  666. } // namespace yaml
  667. } // namespace llvm