xref: /freebsd/contrib/llvm-project/llvm/lib/ObjectYAML/MachOEmitter.cpp (revision 8bcb0991864975618c09697b1aca10683346d9f0)
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