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