1353940Sdim//===- yaml2macho - Convert YAML to a Mach object file --------------------===// 2353940Sdim// 3353940Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353940Sdim// See https://llvm.org/LICENSE.txt for license information. 5353940Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353940Sdim// 7353940Sdim//===----------------------------------------------------------------------===// 8353940Sdim/// 9353940Sdim/// \file 10353940Sdim/// The Mach component of yaml2obj. 11353940Sdim/// 12353940Sdim//===----------------------------------------------------------------------===// 13353940Sdim 14353940Sdim#include "llvm/BinaryFormat/MachO.h" 15353940Sdim#include "llvm/ObjectYAML/DWARFEmitter.h" 16353940Sdim#include "llvm/ObjectYAML/ObjectYAML.h" 17353940Sdim#include "llvm/ObjectYAML/yaml2obj.h" 18353940Sdim#include "llvm/Support/LEB128.h" 19353940Sdim#include "llvm/Support/YAMLTraits.h" 20353940Sdim#include "llvm/Support/raw_ostream.h" 21353940Sdim 22353940Sdim#include "llvm/Support/Format.h" 23353940Sdim 24353940Sdimusing namespace llvm; 25353940Sdim 26353940Sdimnamespace { 27353940Sdim 28353940Sdimclass MachOWriter { 29353940Sdimpublic: 30353940Sdim MachOWriter(MachOYAML::Object &Obj) : Obj(Obj), is64Bit(true), fileStart(0) { 31353940Sdim is64Bit = Obj.Header.magic == MachO::MH_MAGIC_64 || 32353940Sdim Obj.Header.magic == MachO::MH_CIGAM_64; 33353940Sdim memset(reinterpret_cast<void *>(&Header), 0, sizeof(MachO::mach_header_64)); 34353940Sdim } 35353940Sdim 36353940Sdim void writeMachO(raw_ostream &OS); 37353940Sdim 38353940Sdimprivate: 39353940Sdim void writeHeader(raw_ostream &OS); 40353940Sdim void writeLoadCommands(raw_ostream &OS); 41353940Sdim void writeSectionData(raw_ostream &OS); 42353940Sdim void writeLinkEditData(raw_ostream &OS); 43353940Sdim 44353940Sdim void writeBindOpcodes(raw_ostream &OS, 45353940Sdim std::vector<MachOYAML::BindOpcode> &BindOpcodes); 46353940Sdim // LinkEdit writers 47353940Sdim void writeRebaseOpcodes(raw_ostream &OS); 48353940Sdim void writeBasicBindOpcodes(raw_ostream &OS); 49353940Sdim void writeWeakBindOpcodes(raw_ostream &OS); 50353940Sdim void writeLazyBindOpcodes(raw_ostream &OS); 51353940Sdim void writeNameList(raw_ostream &OS); 52353940Sdim void writeStringTable(raw_ostream &OS); 53353940Sdim void writeExportTrie(raw_ostream &OS); 54353940Sdim 55353940Sdim void dumpExportEntry(raw_ostream &OS, MachOYAML::ExportEntry &Entry); 56353940Sdim void ZeroToOffset(raw_ostream &OS, size_t offset); 57353940Sdim 58353940Sdim MachOYAML::Object &Obj; 59353940Sdim bool is64Bit; 60353940Sdim uint64_t fileStart; 61353940Sdim 62353940Sdim MachO::mach_header_64 Header; 63353940Sdim}; 64353940Sdim 65353940Sdimvoid MachOWriter::writeMachO(raw_ostream &OS) { 66353940Sdim fileStart = OS.tell(); 67353940Sdim writeHeader(OS); 68353940Sdim writeLoadCommands(OS); 69353940Sdim writeSectionData(OS); 70353940Sdim} 71353940Sdim 72353940Sdimvoid MachOWriter::writeHeader(raw_ostream &OS) { 73353940Sdim Header.magic = Obj.Header.magic; 74353940Sdim Header.cputype = Obj.Header.cputype; 75353940Sdim Header.cpusubtype = Obj.Header.cpusubtype; 76353940Sdim Header.filetype = Obj.Header.filetype; 77353940Sdim Header.ncmds = Obj.Header.ncmds; 78353940Sdim Header.sizeofcmds = Obj.Header.sizeofcmds; 79353940Sdim Header.flags = Obj.Header.flags; 80353940Sdim Header.reserved = Obj.Header.reserved; 81353940Sdim 82353940Sdim if (Obj.IsLittleEndian != sys::IsLittleEndianHost) 83353940Sdim MachO::swapStruct(Header); 84353940Sdim 85353940Sdim auto header_size = 86353940Sdim is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); 87353940Sdim OS.write((const char *)&Header, header_size); 88353940Sdim} 89353940Sdim 90353940Sdimtemplate <typename SectionType> 91353940SdimSectionType constructSection(MachOYAML::Section Sec) { 92353940Sdim SectionType TempSec; 93353940Sdim memcpy(reinterpret_cast<void *>(&TempSec.sectname[0]), &Sec.sectname[0], 16); 94353940Sdim memcpy(reinterpret_cast<void *>(&TempSec.segname[0]), &Sec.segname[0], 16); 95353940Sdim TempSec.addr = Sec.addr; 96353940Sdim TempSec.size = Sec.size; 97353940Sdim TempSec.offset = Sec.offset; 98353940Sdim TempSec.align = Sec.align; 99353940Sdim TempSec.reloff = Sec.reloff; 100353940Sdim TempSec.nreloc = Sec.nreloc; 101353940Sdim TempSec.flags = Sec.flags; 102353940Sdim TempSec.reserved1 = Sec.reserved1; 103353940Sdim TempSec.reserved2 = Sec.reserved2; 104353940Sdim return TempSec; 105353940Sdim} 106353940Sdim 107353940Sdimtemplate <typename StructType> 108353940Sdimsize_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS, 109353940Sdim bool IsLittleEndian) { 110353940Sdim return 0; 111353940Sdim} 112353940Sdim 113353940Sdimtemplate <> 114353940Sdimsize_t writeLoadCommandData<MachO::segment_command>(MachOYAML::LoadCommand &LC, 115353940Sdim raw_ostream &OS, 116353940Sdim bool IsLittleEndian) { 117353940Sdim size_t BytesWritten = 0; 118353940Sdim for (const auto &Sec : LC.Sections) { 119353940Sdim auto TempSec = constructSection<MachO::section>(Sec); 120353940Sdim if (IsLittleEndian != sys::IsLittleEndianHost) 121353940Sdim MachO::swapStruct(TempSec); 122353940Sdim OS.write(reinterpret_cast<const char *>(&(TempSec)), 123353940Sdim sizeof(MachO::section)); 124353940Sdim BytesWritten += sizeof(MachO::section); 125353940Sdim } 126353940Sdim return BytesWritten; 127353940Sdim} 128353940Sdim 129353940Sdimtemplate <> 130353940Sdimsize_t writeLoadCommandData<MachO::segment_command_64>( 131353940Sdim MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) { 132353940Sdim size_t BytesWritten = 0; 133353940Sdim for (const auto &Sec : LC.Sections) { 134353940Sdim auto TempSec = constructSection<MachO::section_64>(Sec); 135353940Sdim TempSec.reserved3 = Sec.reserved3; 136353940Sdim if (IsLittleEndian != sys::IsLittleEndianHost) 137353940Sdim MachO::swapStruct(TempSec); 138353940Sdim OS.write(reinterpret_cast<const char *>(&(TempSec)), 139353940Sdim sizeof(MachO::section_64)); 140353940Sdim BytesWritten += sizeof(MachO::section_64); 141353940Sdim } 142353940Sdim return BytesWritten; 143353940Sdim} 144353940Sdim 145353940Sdimsize_t writePayloadString(MachOYAML::LoadCommand &LC, raw_ostream &OS) { 146353940Sdim size_t BytesWritten = 0; 147353940Sdim if (!LC.PayloadString.empty()) { 148353940Sdim OS.write(LC.PayloadString.c_str(), LC.PayloadString.length()); 149353940Sdim BytesWritten = LC.PayloadString.length(); 150353940Sdim } 151353940Sdim return BytesWritten; 152353940Sdim} 153353940Sdim 154353940Sdimtemplate <> 155353940Sdimsize_t writeLoadCommandData<MachO::dylib_command>(MachOYAML::LoadCommand &LC, 156353940Sdim raw_ostream &OS, 157353940Sdim bool IsLittleEndian) { 158353940Sdim return writePayloadString(LC, OS); 159353940Sdim} 160353940Sdim 161353940Sdimtemplate <> 162353940Sdimsize_t writeLoadCommandData<MachO::dylinker_command>(MachOYAML::LoadCommand &LC, 163353940Sdim raw_ostream &OS, 164353940Sdim bool IsLittleEndian) { 165353940Sdim return writePayloadString(LC, OS); 166353940Sdim} 167353940Sdim 168353940Sdimtemplate <> 169353940Sdimsize_t writeLoadCommandData<MachO::rpath_command>(MachOYAML::LoadCommand &LC, 170353940Sdim raw_ostream &OS, 171353940Sdim bool IsLittleEndian) { 172353940Sdim return writePayloadString(LC, OS); 173353940Sdim} 174353940Sdim 175353940Sdimtemplate <> 176353940Sdimsize_t writeLoadCommandData<MachO::build_version_command>( 177353940Sdim MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) { 178353940Sdim size_t BytesWritten = 0; 179353940Sdim for (const auto &T : LC.Tools) { 180353940Sdim struct MachO::build_tool_version tool = T; 181353940Sdim if (IsLittleEndian != sys::IsLittleEndianHost) 182353940Sdim MachO::swapStruct(tool); 183353940Sdim OS.write(reinterpret_cast<const char *>(&tool), 184353940Sdim sizeof(MachO::build_tool_version)); 185353940Sdim BytesWritten += sizeof(MachO::build_tool_version); 186353940Sdim } 187353940Sdim return BytesWritten; 188353940Sdim} 189353940Sdim 190353940Sdimvoid ZeroFillBytes(raw_ostream &OS, size_t Size) { 191353940Sdim std::vector<uint8_t> FillData; 192353940Sdim FillData.insert(FillData.begin(), Size, 0); 193353940Sdim OS.write(reinterpret_cast<char *>(FillData.data()), Size); 194353940Sdim} 195353940Sdim 196353940Sdimvoid Fill(raw_ostream &OS, size_t Size, uint32_t Data) { 197353940Sdim std::vector<uint32_t> FillData; 198353940Sdim FillData.insert(FillData.begin(), (Size / 4) + 1, Data); 199353940Sdim OS.write(reinterpret_cast<char *>(FillData.data()), Size); 200353940Sdim} 201353940Sdim 202353940Sdimvoid MachOWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) { 203353940Sdim auto currOffset = OS.tell() - fileStart; 204353940Sdim if (currOffset < Offset) 205353940Sdim ZeroFillBytes(OS, Offset - currOffset); 206353940Sdim} 207353940Sdim 208353940Sdimvoid MachOWriter::writeLoadCommands(raw_ostream &OS) { 209353940Sdim for (auto &LC : Obj.LoadCommands) { 210353940Sdim size_t BytesWritten = 0; 211353940Sdim llvm::MachO::macho_load_command Data = LC.Data; 212353940Sdim 213353940Sdim#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ 214353940Sdim case MachO::LCName: \ 215353940Sdim if (Obj.IsLittleEndian != sys::IsLittleEndianHost) \ 216353940Sdim MachO::swapStruct(Data.LCStruct##_data); \ 217353940Sdim OS.write(reinterpret_cast<const char *>(&(Data.LCStruct##_data)), \ 218353940Sdim sizeof(MachO::LCStruct)); \ 219353940Sdim BytesWritten = sizeof(MachO::LCStruct); \ 220353940Sdim BytesWritten += \ 221353940Sdim writeLoadCommandData<MachO::LCStruct>(LC, OS, Obj.IsLittleEndian); \ 222353940Sdim break; 223353940Sdim 224353940Sdim switch (LC.Data.load_command_data.cmd) { 225353940Sdim default: 226353940Sdim if (Obj.IsLittleEndian != sys::IsLittleEndianHost) 227353940Sdim MachO::swapStruct(Data.load_command_data); 228353940Sdim OS.write(reinterpret_cast<const char *>(&(Data.load_command_data)), 229353940Sdim sizeof(MachO::load_command)); 230353940Sdim BytesWritten = sizeof(MachO::load_command); 231353940Sdim BytesWritten += 232353940Sdim writeLoadCommandData<MachO::load_command>(LC, OS, Obj.IsLittleEndian); 233353940Sdim break; 234353940Sdim#include "llvm/BinaryFormat/MachO.def" 235353940Sdim } 236353940Sdim 237353940Sdim if (LC.PayloadBytes.size() > 0) { 238353940Sdim OS.write(reinterpret_cast<const char *>(LC.PayloadBytes.data()), 239353940Sdim LC.PayloadBytes.size()); 240353940Sdim BytesWritten += LC.PayloadBytes.size(); 241353940Sdim } 242353940Sdim 243353940Sdim if (LC.ZeroPadBytes > 0) { 244353940Sdim ZeroFillBytes(OS, LC.ZeroPadBytes); 245353940Sdim BytesWritten += LC.ZeroPadBytes; 246353940Sdim } 247353940Sdim 248353940Sdim // Fill remaining bytes with 0. This will only get hit in partially 249353940Sdim // specified test cases. 250353940Sdim auto BytesRemaining = LC.Data.load_command_data.cmdsize - BytesWritten; 251353940Sdim if (BytesRemaining > 0) { 252353940Sdim ZeroFillBytes(OS, BytesRemaining); 253353940Sdim } 254353940Sdim } 255353940Sdim} 256353940Sdim 257353940Sdimvoid MachOWriter::writeSectionData(raw_ostream &OS) { 258353940Sdim bool FoundLinkEditSeg = false; 259353940Sdim for (auto &LC : Obj.LoadCommands) { 260353940Sdim switch (LC.Data.load_command_data.cmd) { 261353940Sdim case MachO::LC_SEGMENT: 262353940Sdim case MachO::LC_SEGMENT_64: 263353940Sdim uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff 264353940Sdim : LC.Data.segment_command_data.fileoff; 265353940Sdim if (0 == 266353940Sdim strncmp(&LC.Data.segment_command_data.segname[0], "__LINKEDIT", 16)) { 267353940Sdim FoundLinkEditSeg = true; 268353940Sdim writeLinkEditData(OS); 269353940Sdim } 270353940Sdim for (auto &Sec : LC.Sections) { 271353940Sdim ZeroToOffset(OS, Sec.offset); 272353940Sdim // Zero Fill any data between the end of the last thing we wrote and the 273353940Sdim // start of this section. 274353940Sdim assert((OS.tell() - fileStart <= Sec.offset || 275353940Sdim Sec.offset == (uint32_t)0) && 276353940Sdim "Wrote too much data somewhere, section offsets don't line up."); 277353940Sdim if (0 == strncmp(&Sec.segname[0], "__DWARF", 16)) { 278353940Sdim if (0 == strncmp(&Sec.sectname[0], "__debug_str", 16)) { 279353940Sdim DWARFYAML::EmitDebugStr(OS, Obj.DWARF); 280353940Sdim } else if (0 == strncmp(&Sec.sectname[0], "__debug_abbrev", 16)) { 281353940Sdim DWARFYAML::EmitDebugAbbrev(OS, Obj.DWARF); 282353940Sdim } else if (0 == strncmp(&Sec.sectname[0], "__debug_aranges", 16)) { 283353940Sdim DWARFYAML::EmitDebugAranges(OS, Obj.DWARF); 284353940Sdim } else if (0 == strncmp(&Sec.sectname[0], "__debug_pubnames", 16)) { 285353940Sdim DWARFYAML::EmitPubSection(OS, Obj.DWARF.PubNames, 286353940Sdim Obj.IsLittleEndian); 287353940Sdim } else if (0 == strncmp(&Sec.sectname[0], "__debug_pubtypes", 16)) { 288353940Sdim DWARFYAML::EmitPubSection(OS, Obj.DWARF.PubTypes, 289353940Sdim Obj.IsLittleEndian); 290353940Sdim } else if (0 == strncmp(&Sec.sectname[0], "__debug_info", 16)) { 291353940Sdim DWARFYAML::EmitDebugInfo(OS, Obj.DWARF); 292353940Sdim } else if (0 == strncmp(&Sec.sectname[0], "__debug_line", 16)) { 293353940Sdim DWARFYAML::EmitDebugLine(OS, Obj.DWARF); 294353940Sdim } 295353940Sdim 296353940Sdim continue; 297353940Sdim } 298353940Sdim 299353940Sdim // Skip if it's a virtual section. 300353940Sdim if (MachO::isVirtualSection(Sec.flags & MachO::SECTION_TYPE)) 301353940Sdim continue; 302353940Sdim 303353940Sdim if (Sec.content) { 304353940Sdim yaml::BinaryRef Content = *Sec.content; 305353940Sdim Content.writeAsBinary(OS); 306353940Sdim ZeroFillBytes(OS, Sec.size - Content.binary_size()); 307353940Sdim } else { 308353940Sdim // Fill section data with 0xDEADBEEF. 309353940Sdim Fill(OS, Sec.size, 0xDEADBEEFu); 310353940Sdim } 311353940Sdim } 312353940Sdim uint64_t segSize = is64Bit ? LC.Data.segment_command_64_data.filesize 313353940Sdim : LC.Data.segment_command_data.filesize; 314353940Sdim ZeroToOffset(OS, segOff + segSize); 315353940Sdim break; 316353940Sdim } 317353940Sdim } 318353940Sdim // Old PPC Object Files didn't have __LINKEDIT segments, the data was just 319353940Sdim // stuck at the end of the file. 320353940Sdim if (!FoundLinkEditSeg) 321353940Sdim writeLinkEditData(OS); 322353940Sdim} 323353940Sdim 324353940Sdimvoid MachOWriter::writeBindOpcodes( 325353940Sdim raw_ostream &OS, std::vector<MachOYAML::BindOpcode> &BindOpcodes) { 326353940Sdim 327353940Sdim for (auto Opcode : BindOpcodes) { 328353940Sdim uint8_t OpByte = Opcode.Opcode | Opcode.Imm; 329353940Sdim OS.write(reinterpret_cast<char *>(&OpByte), 1); 330353940Sdim for (auto Data : Opcode.ULEBExtraData) { 331353940Sdim encodeULEB128(Data, OS); 332353940Sdim } 333353940Sdim for (auto Data : Opcode.SLEBExtraData) { 334353940Sdim encodeSLEB128(Data, OS); 335353940Sdim } 336353940Sdim if (!Opcode.Symbol.empty()) { 337353940Sdim OS.write(Opcode.Symbol.data(), Opcode.Symbol.size()); 338353940Sdim OS.write('\0'); 339353940Sdim } 340353940Sdim } 341353940Sdim} 342353940Sdim 343353940Sdimvoid MachOWriter::dumpExportEntry(raw_ostream &OS, 344353940Sdim MachOYAML::ExportEntry &Entry) { 345353940Sdim encodeSLEB128(Entry.TerminalSize, OS); 346353940Sdim if (Entry.TerminalSize > 0) { 347353940Sdim encodeSLEB128(Entry.Flags, OS); 348353940Sdim if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) { 349353940Sdim encodeSLEB128(Entry.Other, OS); 350353940Sdim OS << Entry.ImportName; 351353940Sdim OS.write('\0'); 352353940Sdim } else { 353353940Sdim encodeSLEB128(Entry.Address, OS); 354353940Sdim if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) 355353940Sdim encodeSLEB128(Entry.Other, OS); 356353940Sdim } 357353940Sdim } 358353940Sdim OS.write(static_cast<uint8_t>(Entry.Children.size())); 359353940Sdim for (auto EE : Entry.Children) { 360353940Sdim OS << EE.Name; 361353940Sdim OS.write('\0'); 362353940Sdim encodeSLEB128(EE.NodeOffset, OS); 363353940Sdim } 364353940Sdim for (auto EE : Entry.Children) 365353940Sdim dumpExportEntry(OS, EE); 366353940Sdim} 367353940Sdim 368353940Sdimvoid MachOWriter::writeExportTrie(raw_ostream &OS) { 369353940Sdim dumpExportEntry(OS, Obj.LinkEdit.ExportTrie); 370353940Sdim} 371353940Sdim 372353940Sdimtemplate <typename NListType> 373353940Sdimvoid writeNListEntry(MachOYAML::NListEntry &NLE, raw_ostream &OS, 374353940Sdim bool IsLittleEndian) { 375353940Sdim NListType ListEntry; 376353940Sdim ListEntry.n_strx = NLE.n_strx; 377353940Sdim ListEntry.n_type = NLE.n_type; 378353940Sdim ListEntry.n_sect = NLE.n_sect; 379353940Sdim ListEntry.n_desc = NLE.n_desc; 380353940Sdim ListEntry.n_value = NLE.n_value; 381353940Sdim 382353940Sdim if (IsLittleEndian != sys::IsLittleEndianHost) 383353940Sdim MachO::swapStruct(ListEntry); 384353940Sdim OS.write(reinterpret_cast<const char *>(&ListEntry), sizeof(NListType)); 385353940Sdim} 386353940Sdim 387353940Sdimvoid MachOWriter::writeLinkEditData(raw_ostream &OS) { 388353940Sdim typedef void (MachOWriter::*writeHandler)(raw_ostream &); 389353940Sdim typedef std::pair<uint64_t, writeHandler> writeOperation; 390353940Sdim std::vector<writeOperation> WriteQueue; 391353940Sdim 392353940Sdim MachO::dyld_info_command *DyldInfoOnlyCmd = 0; 393353940Sdim MachO::symtab_command *SymtabCmd = 0; 394353940Sdim for (auto &LC : Obj.LoadCommands) { 395353940Sdim switch (LC.Data.load_command_data.cmd) { 396353940Sdim case MachO::LC_SYMTAB: 397353940Sdim SymtabCmd = &LC.Data.symtab_command_data; 398353940Sdim WriteQueue.push_back( 399353940Sdim std::make_pair(SymtabCmd->symoff, &MachOWriter::writeNameList)); 400353940Sdim WriteQueue.push_back( 401353940Sdim std::make_pair(SymtabCmd->stroff, &MachOWriter::writeStringTable)); 402353940Sdim break; 403353940Sdim case MachO::LC_DYLD_INFO_ONLY: 404353940Sdim DyldInfoOnlyCmd = &LC.Data.dyld_info_command_data; 405353940Sdim WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->rebase_off, 406353940Sdim &MachOWriter::writeRebaseOpcodes)); 407353940Sdim WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->bind_off, 408353940Sdim &MachOWriter::writeBasicBindOpcodes)); 409353940Sdim WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->weak_bind_off, 410353940Sdim &MachOWriter::writeWeakBindOpcodes)); 411353940Sdim WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->lazy_bind_off, 412353940Sdim &MachOWriter::writeLazyBindOpcodes)); 413353940Sdim WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->export_off, 414353940Sdim &MachOWriter::writeExportTrie)); 415353940Sdim break; 416353940Sdim } 417353940Sdim } 418353940Sdim 419353940Sdim llvm::sort(WriteQueue, [](const writeOperation &a, const writeOperation &b) { 420353940Sdim return a.first < b.first; 421353940Sdim }); 422353940Sdim 423353940Sdim for (auto writeOp : WriteQueue) { 424353940Sdim ZeroToOffset(OS, writeOp.first); 425353940Sdim (this->*writeOp.second)(OS); 426353940Sdim } 427353940Sdim} 428353940Sdim 429353940Sdimvoid MachOWriter::writeRebaseOpcodes(raw_ostream &OS) { 430353940Sdim MachOYAML::LinkEditData &LinkEdit = Obj.LinkEdit; 431353940Sdim 432353940Sdim for (auto Opcode : LinkEdit.RebaseOpcodes) { 433353940Sdim uint8_t OpByte = Opcode.Opcode | Opcode.Imm; 434353940Sdim OS.write(reinterpret_cast<char *>(&OpByte), 1); 435353940Sdim for (auto Data : Opcode.ExtraData) 436353940Sdim encodeULEB128(Data, OS); 437353940Sdim } 438353940Sdim} 439353940Sdim 440353940Sdimvoid MachOWriter::writeBasicBindOpcodes(raw_ostream &OS) { 441353940Sdim writeBindOpcodes(OS, Obj.LinkEdit.BindOpcodes); 442353940Sdim} 443353940Sdim 444353940Sdimvoid MachOWriter::writeWeakBindOpcodes(raw_ostream &OS) { 445353940Sdim writeBindOpcodes(OS, Obj.LinkEdit.WeakBindOpcodes); 446353940Sdim} 447353940Sdim 448353940Sdimvoid MachOWriter::writeLazyBindOpcodes(raw_ostream &OS) { 449353940Sdim writeBindOpcodes(OS, Obj.LinkEdit.LazyBindOpcodes); 450353940Sdim} 451353940Sdim 452353940Sdimvoid MachOWriter::writeNameList(raw_ostream &OS) { 453353940Sdim for (auto NLE : Obj.LinkEdit.NameList) { 454353940Sdim if (is64Bit) 455353940Sdim writeNListEntry<MachO::nlist_64>(NLE, OS, Obj.IsLittleEndian); 456353940Sdim else 457353940Sdim writeNListEntry<MachO::nlist>(NLE, OS, Obj.IsLittleEndian); 458353940Sdim } 459353940Sdim} 460353940Sdim 461353940Sdimvoid MachOWriter::writeStringTable(raw_ostream &OS) { 462353940Sdim for (auto Str : Obj.LinkEdit.StringTable) { 463353940Sdim OS.write(Str.data(), Str.size()); 464353940Sdim OS.write('\0'); 465353940Sdim } 466353940Sdim} 467353940Sdim 468353940Sdimclass UniversalWriter { 469353940Sdimpublic: 470353940Sdim UniversalWriter(yaml::YamlObjectFile &ObjectFile) 471353940Sdim : ObjectFile(ObjectFile), fileStart(0) {} 472353940Sdim 473353940Sdim void writeMachO(raw_ostream &OS); 474353940Sdim 475353940Sdimprivate: 476353940Sdim void writeFatHeader(raw_ostream &OS); 477353940Sdim void writeFatArchs(raw_ostream &OS); 478353940Sdim 479353940Sdim void ZeroToOffset(raw_ostream &OS, size_t offset); 480353940Sdim 481353940Sdim yaml::YamlObjectFile &ObjectFile; 482353940Sdim uint64_t fileStart; 483353940Sdim}; 484353940Sdim 485353940Sdimvoid UniversalWriter::writeMachO(raw_ostream &OS) { 486353940Sdim fileStart = OS.tell(); 487353940Sdim if (ObjectFile.MachO) { 488353940Sdim MachOWriter Writer(*ObjectFile.MachO); 489353940Sdim Writer.writeMachO(OS); 490353940Sdim return; 491353940Sdim } 492353940Sdim 493353940Sdim writeFatHeader(OS); 494353940Sdim writeFatArchs(OS); 495353940Sdim 496353940Sdim auto &FatFile = *ObjectFile.FatMachO; 497357095Sdim assert(FatFile.FatArchs.size() >= FatFile.Slices.size() && 498357095Sdim "Cannot write Slices if not decribed in FatArches"); 499353940Sdim for (size_t i = 0; i < FatFile.Slices.size(); i++) { 500353940Sdim ZeroToOffset(OS, FatFile.FatArchs[i].offset); 501353940Sdim MachOWriter Writer(FatFile.Slices[i]); 502353940Sdim Writer.writeMachO(OS); 503353940Sdim 504353940Sdim auto SliceEnd = FatFile.FatArchs[i].offset + FatFile.FatArchs[i].size; 505353940Sdim ZeroToOffset(OS, SliceEnd); 506353940Sdim } 507353940Sdim} 508353940Sdim 509353940Sdimvoid UniversalWriter::writeFatHeader(raw_ostream &OS) { 510353940Sdim auto &FatFile = *ObjectFile.FatMachO; 511353940Sdim MachO::fat_header header; 512353940Sdim header.magic = FatFile.Header.magic; 513353940Sdim header.nfat_arch = FatFile.Header.nfat_arch; 514353940Sdim if (sys::IsLittleEndianHost) 515353940Sdim swapStruct(header); 516353940Sdim OS.write(reinterpret_cast<const char *>(&header), sizeof(MachO::fat_header)); 517353940Sdim} 518353940Sdim 519353940Sdimtemplate <typename FatArchType> 520353940SdimFatArchType constructFatArch(MachOYAML::FatArch &Arch) { 521353940Sdim FatArchType FatArch; 522353940Sdim FatArch.cputype = Arch.cputype; 523353940Sdim FatArch.cpusubtype = Arch.cpusubtype; 524353940Sdim FatArch.offset = Arch.offset; 525353940Sdim FatArch.size = Arch.size; 526353940Sdim FatArch.align = Arch.align; 527353940Sdim return FatArch; 528353940Sdim} 529353940Sdim 530353940Sdimtemplate <typename StructType> 531353940Sdimvoid writeFatArch(MachOYAML::FatArch &LC, raw_ostream &OS) {} 532353940Sdim 533353940Sdimtemplate <> 534353940Sdimvoid writeFatArch<MachO::fat_arch>(MachOYAML::FatArch &Arch, raw_ostream &OS) { 535353940Sdim auto FatArch = constructFatArch<MachO::fat_arch>(Arch); 536353940Sdim if (sys::IsLittleEndianHost) 537353940Sdim swapStruct(FatArch); 538353940Sdim OS.write(reinterpret_cast<const char *>(&FatArch), sizeof(MachO::fat_arch)); 539353940Sdim} 540353940Sdim 541353940Sdimtemplate <> 542353940Sdimvoid writeFatArch<MachO::fat_arch_64>(MachOYAML::FatArch &Arch, 543353940Sdim raw_ostream &OS) { 544353940Sdim auto FatArch = constructFatArch<MachO::fat_arch_64>(Arch); 545353940Sdim FatArch.reserved = Arch.reserved; 546353940Sdim if (sys::IsLittleEndianHost) 547353940Sdim swapStruct(FatArch); 548353940Sdim OS.write(reinterpret_cast<const char *>(&FatArch), 549353940Sdim sizeof(MachO::fat_arch_64)); 550353940Sdim} 551353940Sdim 552353940Sdimvoid UniversalWriter::writeFatArchs(raw_ostream &OS) { 553353940Sdim auto &FatFile = *ObjectFile.FatMachO; 554353940Sdim bool is64Bit = FatFile.Header.magic == MachO::FAT_MAGIC_64; 555353940Sdim for (auto Arch : FatFile.FatArchs) { 556353940Sdim if (is64Bit) 557353940Sdim writeFatArch<MachO::fat_arch_64>(Arch, OS); 558353940Sdim else 559353940Sdim writeFatArch<MachO::fat_arch>(Arch, OS); 560353940Sdim } 561353940Sdim} 562353940Sdim 563353940Sdimvoid UniversalWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) { 564353940Sdim auto currOffset = OS.tell() - fileStart; 565353940Sdim if (currOffset < Offset) 566353940Sdim ZeroFillBytes(OS, Offset - currOffset); 567353940Sdim} 568353940Sdim 569353940Sdim} // end anonymous namespace 570353940Sdim 571353940Sdimnamespace llvm { 572353940Sdimnamespace yaml { 573353940Sdim 574353940Sdimbool yaml2macho(YamlObjectFile &Doc, raw_ostream &Out, ErrorHandler /*EH*/) { 575353940Sdim UniversalWriter Writer(Doc); 576353940Sdim Writer.writeMachO(Out); 577353940Sdim return true; 578353940Sdim} 579353940Sdim 580353940Sdim} // namespace yaml 581353940Sdim} // namespace llvm 582