LLVM  17.0.0git
MachOEmitter.cpp
Go to the documentation of this file.
1 //===- yaml2macho - Convert YAML to a Mach object file --------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// The Mach component of yaml2obj.
11 ///
12 //===----------------------------------------------------------------------===//
13 
18 #include "llvm/Support/Errc.h"
19 #include "llvm/Support/Error.h"
21 #include "llvm/Support/LEB128.h"
24 
25 #include "llvm/Support/Format.h"
26 
27 using namespace llvm;
28 
29 namespace {
30 
31 class MachOWriter {
32 public:
33  MachOWriter(MachOYAML::Object &Obj) : Obj(Obj), fileStart(0) {
36  memset(reinterpret_cast<void *>(&Header), 0, sizeof(MachO::mach_header_64));
37  }
38 
39  Error writeMachO(raw_ostream &OS);
40 
41 private:
42  void writeHeader(raw_ostream &OS);
43  void writeLoadCommands(raw_ostream &OS);
44  Error writeSectionData(raw_ostream &OS);
45  void writeRelocations(raw_ostream &OS);
46  void writeLinkEditData(raw_ostream &OS);
47 
48  void writeBindOpcodes(raw_ostream &OS,
49  std::vector<MachOYAML::BindOpcode> &BindOpcodes);
50  // LinkEdit writers
51  void writeRebaseOpcodes(raw_ostream &OS);
52  void writeBasicBindOpcodes(raw_ostream &OS);
53  void writeWeakBindOpcodes(raw_ostream &OS);
54  void writeLazyBindOpcodes(raw_ostream &OS);
55  void writeNameList(raw_ostream &OS);
56  void writeStringTable(raw_ostream &OS);
57  void writeExportTrie(raw_ostream &OS);
58  void writeDynamicSymbolTable(raw_ostream &OS);
59  void writeFunctionStarts(raw_ostream &OS);
60  void writeChainedFixups(raw_ostream &OS);
61  void writeDyldExportsTrie(raw_ostream &OS);
62  void writeDataInCode(raw_ostream &OS);
63 
64  void dumpExportEntry(raw_ostream &OS, MachOYAML::ExportEntry &Entry);
65  void ZeroToOffset(raw_ostream &OS, size_t offset);
66 
67  MachOYAML::Object &Obj;
68  bool is64Bit;
69  uint64_t fileStart;
70  MachO::mach_header_64 Header;
71 
72  // Old PPC Object Files didn't have __LINKEDIT segments, the data was just
73  // stuck at the end of the file.
74  bool FoundLinkEditSeg = false;
75 };
76 
77 Error MachOWriter::writeMachO(raw_ostream &OS) {
78  fileStart = OS.tell();
79  writeHeader(OS);
80  writeLoadCommands(OS);
81  if (Error Err = writeSectionData(OS))
82  return Err;
83  writeRelocations(OS);
84  if (!FoundLinkEditSeg)
85  writeLinkEditData(OS);
86  return Error::success();
87 }
88 
89 void MachOWriter::writeHeader(raw_ostream &OS) {
90  Header.magic = Obj.Header.magic;
91  Header.cputype = Obj.Header.cputype;
92  Header.cpusubtype = Obj.Header.cpusubtype;
93  Header.filetype = Obj.Header.filetype;
94  Header.ncmds = Obj.Header.ncmds;
95  Header.sizeofcmds = Obj.Header.sizeofcmds;
96  Header.flags = Obj.Header.flags;
97  Header.reserved = Obj.Header.reserved;
98 
100  MachO::swapStruct(Header);
101 
102  auto header_size =
104  OS.write((const char *)&Header, header_size);
105 }
106 
107 template <typename SectionType>
109  SectionType TempSec;
110  memcpy(reinterpret_cast<void *>(&TempSec.sectname[0]), &Sec.sectname[0], 16);
111  memcpy(reinterpret_cast<void *>(&TempSec.segname[0]), &Sec.segname[0], 16);
112  TempSec.addr = Sec.addr;
113  TempSec.size = Sec.size;
114  TempSec.offset = Sec.offset;
115  TempSec.align = Sec.align;
116  TempSec.reloff = Sec.reloff;
117  TempSec.nreloc = Sec.nreloc;
118  TempSec.flags = Sec.flags;
119  TempSec.reserved1 = Sec.reserved1;
120  TempSec.reserved2 = Sec.reserved2;
121  return TempSec;
122 }
123 
124 template <typename StructType>
125 size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS,
126  bool IsLittleEndian) {
127  return 0;
128 }
129 
130 template <>
131 size_t writeLoadCommandData<MachO::segment_command>(MachOYAML::LoadCommand &LC,
132  raw_ostream &OS,
133  bool IsLittleEndian) {
134  size_t BytesWritten = 0;
135  for (const auto &Sec : LC.Sections) {
136  auto TempSec = constructSection<MachO::section>(Sec);
137  if (IsLittleEndian != sys::IsLittleEndianHost)
138  MachO::swapStruct(TempSec);
139  OS.write(reinterpret_cast<const char *>(&(TempSec)),
140  sizeof(MachO::section));
141  BytesWritten += sizeof(MachO::section);
142  }
143  return BytesWritten;
144 }
145 
146 template <>
147 size_t writeLoadCommandData<MachO::segment_command_64>(
148  MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
149  size_t BytesWritten = 0;
150  for (const auto &Sec : LC.Sections) {
151  auto TempSec = constructSection<MachO::section_64>(Sec);
152  TempSec.reserved3 = Sec.reserved3;
153  if (IsLittleEndian != sys::IsLittleEndianHost)
154  MachO::swapStruct(TempSec);
155  OS.write(reinterpret_cast<const char *>(&(TempSec)),
156  sizeof(MachO::section_64));
157  BytesWritten += sizeof(MachO::section_64);
158  }
159  return BytesWritten;
160 }
161 
162 size_t writePayloadString(MachOYAML::LoadCommand &LC, raw_ostream &OS) {
163  size_t BytesWritten = 0;
164  if (!LC.Content.empty()) {
165  OS.write(LC.Content.c_str(), LC.Content.length());
166  BytesWritten = LC.Content.length();
167  }
168  return BytesWritten;
169 }
170 
171 template <>
172 size_t writeLoadCommandData<MachO::dylib_command>(MachOYAML::LoadCommand &LC,
173  raw_ostream &OS,
174  bool IsLittleEndian) {
175  return writePayloadString(LC, OS);
176 }
177 
178 template <>
179 size_t writeLoadCommandData<MachO::dylinker_command>(MachOYAML::LoadCommand &LC,
180  raw_ostream &OS,
181  bool IsLittleEndian) {
182  return writePayloadString(LC, OS);
183 }
184 
185 template <>
186 size_t writeLoadCommandData<MachO::rpath_command>(MachOYAML::LoadCommand &LC,
187  raw_ostream &OS,
188  bool IsLittleEndian) {
189  return writePayloadString(LC, OS);
190 }
191 
192 template <>
193 size_t writeLoadCommandData<MachO::sub_framework_command>(
194  MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
195  return writePayloadString(LC, OS);
196 }
197 
198 template <>
199 size_t writeLoadCommandData<MachO::sub_umbrella_command>(
200  MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
201  return writePayloadString(LC, OS);
202 }
203 
204 template <>
205 size_t writeLoadCommandData<MachO::sub_client_command>(
206  MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
207  return writePayloadString(LC, OS);
208 }
209 
210 template <>
211 size_t writeLoadCommandData<MachO::sub_library_command>(
212  MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
213  return writePayloadString(LC, OS);
214 }
215 
216 template <>
217 size_t writeLoadCommandData<MachO::build_version_command>(
218  MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
219  size_t BytesWritten = 0;
220  for (const auto &T : LC.Tools) {
221  struct MachO::build_tool_version tool = T;
222  if (IsLittleEndian != sys::IsLittleEndianHost)
223  MachO::swapStruct(tool);
224  OS.write(reinterpret_cast<const char *>(&tool),
225  sizeof(MachO::build_tool_version));
226  BytesWritten += sizeof(MachO::build_tool_version);
227  }
228  return BytesWritten;
229 }
230 
231 void ZeroFillBytes(raw_ostream &OS, size_t Size) {
232  std::vector<uint8_t> FillData(Size, 0);
233  OS.write(reinterpret_cast<char *>(FillData.data()), Size);
234 }
235 
236 void Fill(raw_ostream &OS, size_t Size, uint32_t Data) {
237  std::vector<uint32_t> FillData((Size / 4) + 1, Data);
238  OS.write(reinterpret_cast<char *>(FillData.data()), Size);
239 }
240 
241 void MachOWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) {
242  auto currOffset = OS.tell() - fileStart;
243  if (currOffset < Offset)
244  ZeroFillBytes(OS, Offset - currOffset);
245 }
246 
247 void MachOWriter::writeLoadCommands(raw_ostream &OS) {
248  for (auto &LC : Obj.LoadCommands) {
249  size_t BytesWritten = 0;
251 
252 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
253  case MachO::LCName: \
254  if (Obj.IsLittleEndian != sys::IsLittleEndianHost) \
255  MachO::swapStruct(Data.LCStruct##_data); \
256  OS.write(reinterpret_cast<const char *>(&(Data.LCStruct##_data)), \
257  sizeof(MachO::LCStruct)); \
258  BytesWritten = sizeof(MachO::LCStruct); \
259  BytesWritten += \
260  writeLoadCommandData<MachO::LCStruct>(LC, OS, Obj.IsLittleEndian); \
261  break;
262 
263  switch (LC.Data.load_command_data.cmd) {
264  default:
266  MachO::swapStruct(Data.load_command_data);
267  OS.write(reinterpret_cast<const char *>(&(Data.load_command_data)),
268  sizeof(MachO::load_command));
269  BytesWritten = sizeof(MachO::load_command);
270  BytesWritten +=
271  writeLoadCommandData<MachO::load_command>(LC, OS, Obj.IsLittleEndian);
272  break;
273 #include "llvm/BinaryFormat/MachO.def"
274  }
275 
276  if (LC.PayloadBytes.size() > 0) {
277  OS.write(reinterpret_cast<const char *>(LC.PayloadBytes.data()),
278  LC.PayloadBytes.size());
279  BytesWritten += LC.PayloadBytes.size();
280  }
281 
282  if (LC.ZeroPadBytes > 0) {
283  ZeroFillBytes(OS, LC.ZeroPadBytes);
284  BytesWritten += LC.ZeroPadBytes;
285  }
286 
287  // Fill remaining bytes with 0. This will only get hit in partially
288  // specified test cases.
289  auto BytesRemaining = LC.Data.load_command_data.cmdsize - BytesWritten;
290  if (BytesRemaining > 0) {
291  ZeroFillBytes(OS, BytesRemaining);
292  }
293  }
294 }
295 
296 Error MachOWriter::writeSectionData(raw_ostream &OS) {
297  uint64_t LinkEditOff = 0;
298  for (auto &LC : Obj.LoadCommands) {
299  switch (LC.Data.load_command_data.cmd) {
300  case MachO::LC_SEGMENT:
301  case MachO::LC_SEGMENT_64:
302  uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff
303  : LC.Data.segment_command_data.fileoff;
304  if (0 ==
305  strncmp(&LC.Data.segment_command_data.segname[0], "__LINKEDIT", 16)) {
306  FoundLinkEditSeg = true;
307  LinkEditOff = segOff;
308  if (Obj.RawLinkEditSegment)
309  continue;
310  writeLinkEditData(OS);
311  }
312  for (auto &Sec : LC.Sections) {
313  ZeroToOffset(OS, Sec.offset);
314  // Zero Fill any data between the end of the last thing we wrote and the
315  // start of this section.
316  if (OS.tell() - fileStart > Sec.offset && Sec.offset != (uint32_t)0)
317  return createStringError(
320  "wrote too much data somewhere, section offsets in "
321  "section {0} for segment {1} don't line up: "
322  "[cursor={2:x}], [fileStart={3:x}], [sectionOffset={4:x}]",
323  Sec.sectname, Sec.segname, OS.tell(), fileStart,
324  Sec.offset.value));
325 
326  StringRef SectName(Sec.sectname,
327  strnlen(Sec.sectname, sizeof(Sec.sectname)));
328  // If the section's content is specified in the 'DWARF' entry, we will
329  // emit it regardless of the section's segname.
330  if (Obj.DWARF.getNonEmptySectionNames().count(SectName.substr(2))) {
331  if (Sec.content)
333  "cannot specify section '" + SectName +
334  "' contents in the 'DWARF' entry and "
335  "the 'content' at the same time");
336  auto EmitFunc = DWARFYAML::getDWARFEmitterByName(SectName.substr(2));
337  if (Error Err = EmitFunc(OS, Obj.DWARF))
338  return Err;
339  continue;
340  }
341 
342  // Skip if it's a virtual section.
344  continue;
345 
346  if (Sec.content) {
348  Content.writeAsBinary(OS);
349  ZeroFillBytes(OS, Sec.size - Content.binary_size());
350  } else {
351  // Fill section data with 0xDEADBEEF.
352  Fill(OS, Sec.size, 0xDEADBEEFu);
353  }
354  }
355  uint64_t segSize = is64Bit ? LC.Data.segment_command_64_data.filesize
356  : LC.Data.segment_command_data.filesize;
357  ZeroToOffset(OS, segOff + segSize);
358  break;
359  }
360  }
361 
362  if (Obj.RawLinkEditSegment) {
363  ZeroToOffset(OS, LinkEditOff);
364  if (OS.tell() - fileStart > LinkEditOff || !LinkEditOff)
366  "section offsets don't line up");
367  Obj.RawLinkEditSegment->writeAsBinary(OS);
368  }
369  return Error::success();
370 }
371 
372 // The implementation of makeRelocationInfo and makeScatteredRelocationInfo is
373 // consistent with how libObject parses MachO binary files. For the reference
374 // see getStruct, getRelocation, getPlainRelocationPCRel,
375 // getPlainRelocationLength and related methods in MachOObjectFile.cpp
377 makeRelocationInfo(const MachOYAML::Relocation &R, bool IsLE) {
378  assert(!R.is_scattered && "non-scattered relocation expected");
380  MRE.r_word0 = R.address;
381  if (IsLE)
382  MRE.r_word1 = ((unsigned)R.symbolnum << 0) | ((unsigned)R.is_pcrel << 24) |
383  ((unsigned)R.length << 25) | ((unsigned)R.is_extern << 27) |
384  ((unsigned)R.type << 28);
385  else
386  MRE.r_word1 = ((unsigned)R.symbolnum << 8) | ((unsigned)R.is_pcrel << 7) |
387  ((unsigned)R.length << 5) | ((unsigned)R.is_extern << 4) |
388  ((unsigned)R.type << 0);
389  return MRE;
390 }
391 
393 makeScatteredRelocationInfo(const MachOYAML::Relocation &R) {
394  assert(R.is_scattered && "scattered relocation expected");
396  MRE.r_word0 = (((unsigned)R.address << 0) | ((unsigned)R.type << 24) |
397  ((unsigned)R.length << 28) | ((unsigned)R.is_pcrel << 30) |
399  MRE.r_word1 = R.value;
400  return MRE;
401 }
402 
403 void MachOWriter::writeRelocations(raw_ostream &OS) {
404  for (const MachOYAML::LoadCommand &LC : Obj.LoadCommands) {
405  switch (LC.Data.load_command_data.cmd) {
406  case MachO::LC_SEGMENT:
407  case MachO::LC_SEGMENT_64:
408  for (const MachOYAML::Section &Sec : LC.Sections) {
409  if (Sec.relocations.empty())
410  continue;
411  ZeroToOffset(OS, Sec.reloff);
412  for (const MachOYAML::Relocation &R : Sec.relocations) {
414  R.is_scattered ? makeScatteredRelocationInfo(R)
415  : makeRelocationInfo(R, Obj.IsLittleEndian);
417  MachO::swapStruct(MRE);
418  OS.write(reinterpret_cast<const char *>(&MRE),
420  }
421  }
422  }
423  }
424 }
425 
426 void MachOWriter::writeBindOpcodes(
427  raw_ostream &OS, std::vector<MachOYAML::BindOpcode> &BindOpcodes) {
428 
429  for (auto Opcode : BindOpcodes) {
430  uint8_t OpByte = Opcode.Opcode | Opcode.Imm;
431  OS.write(reinterpret_cast<char *>(&OpByte), 1);
432  for (auto Data : Opcode.ULEBExtraData) {
433  encodeULEB128(Data, OS);
434  }
435  for (auto Data : Opcode.SLEBExtraData) {
436  encodeSLEB128(Data, OS);
437  }
438  if (!Opcode.Symbol.empty()) {
439  OS.write(Opcode.Symbol.data(), Opcode.Symbol.size());
440  OS.write('\0');
441  }
442  }
443 }
444 
445 void MachOWriter::dumpExportEntry(raw_ostream &OS,
446  MachOYAML::ExportEntry &Entry) {
447  encodeULEB128(Entry.TerminalSize, OS);
448  if (Entry.TerminalSize > 0) {
449  encodeULEB128(Entry.Flags, OS);
450  if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) {
451  encodeULEB128(Entry.Other, OS);
452  OS << Entry.ImportName;
453  OS.write('\0');
454  } else {
455  encodeULEB128(Entry.Address, OS);
457  encodeULEB128(Entry.Other, OS);
458  }
459  }
460  OS.write(static_cast<uint8_t>(Entry.Children.size()));
461  for (auto EE : Entry.Children) {
462  OS << EE.Name;
463  OS.write('\0');
464  encodeULEB128(EE.NodeOffset, OS);
465  }
466  for (auto EE : Entry.Children)
467  dumpExportEntry(OS, EE);
468 }
469 
470 void MachOWriter::writeExportTrie(raw_ostream &OS) {
471  dumpExportEntry(OS, Obj.LinkEdit.ExportTrie);
472 }
473 
474 template <typename NListType>
476  bool IsLittleEndian) {
477  NListType ListEntry;
478  ListEntry.n_strx = NLE.n_strx;
479  ListEntry.n_type = NLE.n_type;
480  ListEntry.n_sect = NLE.n_sect;
481  ListEntry.n_desc = NLE.n_desc;
482  ListEntry.n_value = NLE.n_value;
483 
484  if (IsLittleEndian != sys::IsLittleEndianHost)
485  MachO::swapStruct(ListEntry);
486  OS.write(reinterpret_cast<const char *>(&ListEntry), sizeof(NListType));
487 }
488 
489 void MachOWriter::writeLinkEditData(raw_ostream &OS) {
490  typedef void (MachOWriter::*writeHandler)(raw_ostream &);
491  typedef std::pair<uint64_t, writeHandler> writeOperation;
492  std::vector<writeOperation> WriteQueue;
493 
494  MachO::dyld_info_command *DyldInfoOnlyCmd = nullptr;
495  MachO::symtab_command *SymtabCmd = nullptr;
496  MachO::dysymtab_command *DSymtabCmd = nullptr;
497  MachO::linkedit_data_command *FunctionStartsCmd = nullptr;
498  MachO::linkedit_data_command *ChainedFixupsCmd = nullptr;
499  MachO::linkedit_data_command *DyldExportsTrieCmd = nullptr;
500  MachO::linkedit_data_command *DataInCodeCmd = nullptr;
501  for (auto &LC : Obj.LoadCommands) {
502  switch (LC.Data.load_command_data.cmd) {
503  case MachO::LC_SYMTAB:
504  SymtabCmd = &LC.Data.symtab_command_data;
505  WriteQueue.push_back(
506  std::make_pair(SymtabCmd->symoff, &MachOWriter::writeNameList));
507  WriteQueue.push_back(
508  std::make_pair(SymtabCmd->stroff, &MachOWriter::writeStringTable));
509  break;
510  case MachO::LC_DYLD_INFO_ONLY:
511  DyldInfoOnlyCmd = &LC.Data.dyld_info_command_data;
512  WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->rebase_off,
513  &MachOWriter::writeRebaseOpcodes));
514  WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->bind_off,
515  &MachOWriter::writeBasicBindOpcodes));
516  WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->weak_bind_off,
517  &MachOWriter::writeWeakBindOpcodes));
518  WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->lazy_bind_off,
519  &MachOWriter::writeLazyBindOpcodes));
520  WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->export_off,
521  &MachOWriter::writeExportTrie));
522  break;
523  case MachO::LC_DYSYMTAB:
524  DSymtabCmd = &LC.Data.dysymtab_command_data;
525  WriteQueue.push_back(std::make_pair(
526  DSymtabCmd->indirectsymoff, &MachOWriter::writeDynamicSymbolTable));
527  break;
528  case MachO::LC_FUNCTION_STARTS:
529  FunctionStartsCmd = &LC.Data.linkedit_data_command_data;
530  WriteQueue.push_back(std::make_pair(FunctionStartsCmd->dataoff,
531  &MachOWriter::writeFunctionStarts));
532  break;
533  case MachO::LC_DYLD_CHAINED_FIXUPS:
534  ChainedFixupsCmd = &LC.Data.linkedit_data_command_data;
535  WriteQueue.push_back(std::make_pair(ChainedFixupsCmd->dataoff,
536  &MachOWriter::writeChainedFixups));
537  break;
538  case MachO::LC_DYLD_EXPORTS_TRIE:
539  DyldExportsTrieCmd = &LC.Data.linkedit_data_command_data;
540  WriteQueue.push_back(std::make_pair(DyldExportsTrieCmd->dataoff,
541  &MachOWriter::writeDyldExportsTrie));
542  break;
543  case MachO::LC_DATA_IN_CODE:
544  DataInCodeCmd = &LC.Data.linkedit_data_command_data;
545  WriteQueue.push_back(std::make_pair(DataInCodeCmd->dataoff,
546  &MachOWriter::writeDataInCode));
547  break;
548  }
549  }
550 
551  llvm::sort(WriteQueue, llvm::less_first());
552 
553  for (auto writeOp : WriteQueue) {
554  ZeroToOffset(OS, writeOp.first);
555  (this->*writeOp.second)(OS);
556  }
557 }
558 
559 void MachOWriter::writeRebaseOpcodes(raw_ostream &OS) {
560  MachOYAML::LinkEditData &LinkEdit = Obj.LinkEdit;
561 
562  for (auto Opcode : LinkEdit.RebaseOpcodes) {
563  uint8_t OpByte = Opcode.Opcode | Opcode.Imm;
564  OS.write(reinterpret_cast<char *>(&OpByte), 1);
565  for (auto Data : Opcode.ExtraData)
566  encodeULEB128(Data, OS);
567  }
568 }
569 
570 void MachOWriter::writeBasicBindOpcodes(raw_ostream &OS) {
571  writeBindOpcodes(OS, Obj.LinkEdit.BindOpcodes);
572 }
573 
574 void MachOWriter::writeWeakBindOpcodes(raw_ostream &OS) {
575  writeBindOpcodes(OS, Obj.LinkEdit.WeakBindOpcodes);
576 }
577 
578 void MachOWriter::writeLazyBindOpcodes(raw_ostream &OS) {
579  writeBindOpcodes(OS, Obj.LinkEdit.LazyBindOpcodes);
580 }
581 
582 void MachOWriter::writeNameList(raw_ostream &OS) {
583  for (auto NLE : Obj.LinkEdit.NameList) {
584  if (is64Bit)
585  writeNListEntry<MachO::nlist_64>(NLE, OS, Obj.IsLittleEndian);
586  else
587  writeNListEntry<MachO::nlist>(NLE, OS, Obj.IsLittleEndian);
588  }
589 }
590 
592  for (auto Str : Obj.LinkEdit.StringTable) {
593  OS.write(Str.data(), Str.size());
594  OS.write('\0');
595  }
596 }
597 
598 void MachOWriter::writeDynamicSymbolTable(raw_ostream &OS) {
599  for (auto Data : Obj.LinkEdit.IndirectSymbols)
600  OS.write(reinterpret_cast<const char *>(&Data),
601  sizeof(yaml::Hex32::BaseType));
602 }
603 
604 void MachOWriter::writeFunctionStarts(raw_ostream &OS) {
605  uint64_t Addr = 0;
606  for (uint64_t NextAddr : Obj.LinkEdit.FunctionStarts) {
607  uint64_t Delta = NextAddr - Addr;
608  encodeULEB128(Delta, OS);
609  Addr = NextAddr;
610  }
611 
612  OS.write('\0');
613 }
614 
615 void MachOWriter::writeDataInCode(raw_ostream &OS) {
616  for (const auto &Entry : Obj.LinkEdit.DataInCode) {
617  MachO::data_in_code_entry DICE{Entry.Offset, Entry.Length, Entry.Kind};
619  MachO::swapStruct(DICE);
620  OS.write(reinterpret_cast<const char *>(&DICE),
621  sizeof(MachO::data_in_code_entry));
622  }
623 }
624 
625 void MachOWriter::writeChainedFixups(raw_ostream &OS) {
626  if (Obj.LinkEdit.ChainedFixups.size() > 0)
627  OS.write(reinterpret_cast<const char *>(Obj.LinkEdit.ChainedFixups.data()),
628  Obj.LinkEdit.ChainedFixups.size());
629 }
630 
631 void MachOWriter::writeDyldExportsTrie(raw_ostream &OS) {
632  dumpExportEntry(OS, Obj.LinkEdit.ExportTrie);
633 }
634 
635 class UniversalWriter {
636 public:
637  UniversalWriter(yaml::YamlObjectFile &ObjectFile)
638  : ObjectFile(ObjectFile), fileStart(0) {}
639 
640  Error writeMachO(raw_ostream &OS);
641 
642 private:
643  void writeFatHeader(raw_ostream &OS);
644  void writeFatArchs(raw_ostream &OS);
645 
646  void ZeroToOffset(raw_ostream &OS, size_t offset);
647 
649  uint64_t fileStart;
650 };
651 
652 Error UniversalWriter::writeMachO(raw_ostream &OS) {
653  fileStart = OS.tell();
654  if (ObjectFile.MachO) {
655  MachOWriter Writer(*ObjectFile.MachO);
656  return Writer.writeMachO(OS);
657  }
658 
659  writeFatHeader(OS);
660  writeFatArchs(OS);
661 
662  auto &FatFile = *ObjectFile.FatMachO;
663  if (FatFile.FatArchs.size() < FatFile.Slices.size())
664  return createStringError(
666  "cannot write 'Slices' if not described in 'FatArches'");
667 
668  for (size_t i = 0; i < FatFile.Slices.size(); i++) {
669  ZeroToOffset(OS, FatFile.FatArchs[i].offset);
670  MachOWriter Writer(FatFile.Slices[i]);
671  if (Error Err = Writer.writeMachO(OS))
672  return Err;
673 
674  auto SliceEnd = FatFile.FatArchs[i].offset + FatFile.FatArchs[i].size;
675  ZeroToOffset(OS, SliceEnd);
676  }
677 
678  return Error::success();
679 }
680 
681 void UniversalWriter::writeFatHeader(raw_ostream &OS) {
682  auto &FatFile = *ObjectFile.FatMachO;
683  MachO::fat_header header;
684  header.magic = FatFile.Header.magic;
685  header.nfat_arch = FatFile.Header.nfat_arch;
687  swapStruct(header);
688  OS.write(reinterpret_cast<const char *>(&header), sizeof(MachO::fat_header));
689 }
690 
691 template <typename FatArchType>
692 FatArchType constructFatArch(MachOYAML::FatArch &Arch) {
693  FatArchType FatArch;
694  FatArch.cputype = Arch.cputype;
695  FatArch.cpusubtype = Arch.cpusubtype;
696  FatArch.offset = Arch.offset;
697  FatArch.size = Arch.size;
698  FatArch.align = Arch.align;
699  return FatArch;
700 }
701 
702 template <typename StructType>
703 void writeFatArch(MachOYAML::FatArch &LC, raw_ostream &OS) {}
704 
705 template <>
706 void writeFatArch<MachO::fat_arch>(MachOYAML::FatArch &Arch, raw_ostream &OS) {
707  auto FatArch = constructFatArch<MachO::fat_arch>(Arch);
709  swapStruct(FatArch);
710  OS.write(reinterpret_cast<const char *>(&FatArch), sizeof(MachO::fat_arch));
711 }
712 
713 template <>
714 void writeFatArch<MachO::fat_arch_64>(MachOYAML::FatArch &Arch,
715  raw_ostream &OS) {
716  auto FatArch = constructFatArch<MachO::fat_arch_64>(Arch);
717  FatArch.reserved = Arch.reserved;
719  swapStruct(FatArch);
720  OS.write(reinterpret_cast<const char *>(&FatArch),
721  sizeof(MachO::fat_arch_64));
722 }
723 
724 void UniversalWriter::writeFatArchs(raw_ostream &OS) {
725  auto &FatFile = *ObjectFile.FatMachO;
726  bool is64Bit = FatFile.Header.magic == MachO::FAT_MAGIC_64;
727  for (auto Arch : FatFile.FatArchs) {
728  if (is64Bit)
729  writeFatArch<MachO::fat_arch_64>(Arch, OS);
730  else
731  writeFatArch<MachO::fat_arch>(Arch, OS);
732  }
733 }
734 
735 void UniversalWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) {
736  auto currOffset = OS.tell() - fileStart;
737  if (currOffset < Offset)
738  ZeroFillBytes(OS, Offset - currOffset);
739 }
740 
741 } // end anonymous namespace
742 
743 namespace llvm {
744 namespace yaml {
745 
747  UniversalWriter Writer(Doc);
748  if (Error Err = Writer.writeMachO(Out)) {
750  [&](const ErrorInfoBase &Err) { EH(Err.message()); });
751  return false;
752  }
753  return true;
754 }
755 
756 } // namespace yaml
757 } // namespace llvm
llvm::MachOYAML::ExportEntry
Definition: MachOYAML.h:106
llvm::MachOYAML::FatArch::offset
llvm::yaml::Hex64 offset
Definition: MachOYAML.h:157
i
i
Definition: README.txt:29
llvm::raw_ostream::tell
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:134
llvm::MachOYAML::LoadCommand::Sections
std::vector< Section > Sections
Definition: MachOYAML.h:77
llvm::errc::invalid_argument
@ invalid_argument
llvm::MachO::section
Definition: MachO.h:570
llvm::MachOYAML::NListEntry::n_desc
uint16_t n_desc
Definition: MachOYAML.h:88
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
ObjectYAML.h
llvm::MachO::any_relocation_info
Definition: MachO.h:996
llvm::MachOYAML::Object
Definition: MachOYAML.h:139
llvm::MachOYAML::Section
Definition: MachOYAML.h:45
llvm::MachOYAML::Section::segname
char segname[16]
Definition: MachOYAML.h:47
llvm::MachO::fat_header::nfat_arch
uint32_t nfat_arch
Definition: MachO.h:957
llvm::MachOYAML::LinkEditData::DataInCode
std::vector< DataInCodeEntry > DataInCode
Definition: MachOYAML.h:133
T
is64Bit
static bool is64Bit(const char *name)
Definition: X86Disassembler.cpp:1015
llvm::MachO::R_SCATTERED
@ R_SCATTERED
Definition: MachO.h:401
llvm::MachOYAML::LinkEditData::ExportTrie
MachOYAML::ExportEntry ExportTrie
Definition: MachOYAML.h:128
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:330
llvm::MachOYAML::LoadCommand::ZeroPadBytes
uint64_t ZeroPadBytes
Definition: MachOYAML.h:81
llvm::MachO::dysymtab_command::indirectsymoff
uint32_t indirectsymoff
Definition: MachO.h:724
Content
T Content
Definition: ELFObjHandler.cpp:89
Error.h
llvm::MachOYAML::Section::nreloc
uint32_t nreloc
Definition: MachOYAML.h:53
llvm::yaml::YamlObjectFile
Definition: ObjectYAML.h:29
Errc.h
llvm::MachO::SECTION_TYPE
@ SECTION_TYPE
Definition: MachO.h:114
llvm::MachO::symtab_command
Definition: MachO.h:700
llvm::MachOYAML::LinkEditData::LazyBindOpcodes
std::vector< MachOYAML::BindOpcode > LazyBindOpcodes
Definition: MachOYAML.h:127
llvm::MachOYAML::NListEntry
Definition: MachOYAML.h:84
llvm::MachOYAML::LoadCommand::PayloadBytes
std::vector< llvm::yaml::Hex8 > PayloadBytes
Definition: MachOYAML.h:79
llvm::MachO::isVirtualSection
bool isVirtualSection(uint8_t type)
Definition: MachO.h:599
T
#define T
Definition: Mips16ISelLowering.cpp:341
llvm::MachO::FAT_MAGIC_64
@ FAT_MAGIC_64
Definition: MachO.h:36
llvm::MachO::dyld_info_command::export_off
uint32_t export_off
Definition: MachO.h:889
llvm::MachOYAML::Object::DWARF
DWARFYAML::Data DWARF
Definition: MachOYAML.h:146
llvm::MachOYAML::Section::addr
llvm::yaml::Hex64 addr
Definition: MachOYAML.h:48
llvm::MachOYAML::LinkEditData::FunctionStarts
std::vector< yaml::Hex64 > FunctionStarts
Definition: MachOYAML.h:132
llvm::MachO::MH_MAGIC_64
@ MH_MAGIC_64
Definition: MachO.h:32
llvm::MachO::EXPORT_SYMBOL_FLAGS_REEXPORT
@ EXPORT_SYMBOL_FLAGS_REEXPORT
Definition: MachO.h:294
Format.h
llvm::MachOYAML::LinkEditData::RebaseOpcodes
std::vector< MachOYAML::RebaseOpcode > RebaseOpcodes
Definition: MachOYAML.h:124
llvm::Data
@ Data
Definition: SIMachineScheduler.h:55
llvm::RISCVFenceField::R
@ R
Definition: RISCVBaseInfo.h:275
llvm::MachOYAML::LoadCommand::Content
std::string Content
Definition: MachOYAML.h:80
llvm::MachOYAML::FileHeader::sizeofcmds
uint32_t sizeofcmds
Definition: MachOYAML.h:68
llvm::MachO::dyld_info_command
Definition: MachO.h:878
llvm::MachOYAML::LinkEditData::IndirectSymbols
std::vector< yaml::Hex32 > IndirectSymbols
Definition: MachOYAML.h:131
llvm::MachOYAML::Section::size
uint64_t size
Definition: MachOYAML.h:49
llvm::MachO::data_in_code_entry
Definition: MachO.h:812
llvm::formatv
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
Definition: FormatVariadic.h:251
llvm::yaml::yaml2macho
bool yaml2macho(YamlObjectFile &Doc, raw_ostream &Out, ErrorHandler EH)
Definition: MachOEmitter.cpp:746
llvm::MachO::fat_arch
Definition: MachO.h:960
llvm::MachOYAML::Section::sectname
char sectname[16]
Definition: MachOYAML.h:46
llvm::MachO::any_relocation_info::r_word1
uint32_t r_word1
Definition: MachO.h:997
llvm::encodeSLEB128
unsigned encodeSLEB128(int64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a SLEB128 value to an output stream.
Definition: LEB128.h:23
llvm::MachOYAML::Section::content
std::optional< llvm::yaml::BinaryRef > content
Definition: MachOYAML.h:58
llvm::less_first
Function object to check whether the first component of a std::pair compares less than the first comp...
Definition: STLExtras.h:1477
llvm::MachOYAML::FatArch::align
uint32_t align
Definition: MachOYAML.h:159
llvm::MachOYAML::NListEntry::n_value
uint64_t n_value
Definition: MachOYAML.h:89
llvm::MachOYAML::FatArch::cputype
llvm::yaml::Hex32 cputype
Definition: MachOYAML.h:155
llvm::MachO::fat_header::magic
uint32_t magic
Definition: MachO.h:956
llvm::MachO::linkedit_data_command
Definition: MachO.h:805
llvm::raw_ostream::write
raw_ostream & write(unsigned char C)
Definition: raw_ostream.cpp:218
llvm::MachOYAML::FileHeader::filetype
llvm::yaml::Hex32 filetype
Definition: MachOYAML.h:66
llvm::raw_ostream
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
llvm::object::writeStringTable
static void writeStringTable(std::vector< uint8_t > &B, ArrayRef< const std::string > Strings)
Definition: COFFImportFile.cpp:72
llvm::MachOYAML::LoadCommand::Data
llvm::MachO::macho_load_command Data
Definition: MachOYAML.h:76
llvm::MachOYAML::Section::relocations
std::vector< Relocation > relocations
Definition: MachOYAML.h:59
ZeroFillBytes
static void ZeroFillBytes(raw_ostream &OS, size_t Size)
Definition: DWARFEmitter.cpp:66
FormatVariadic.h
llvm::ErrorInfoBase
Base class for error info classes.
Definition: Error.h:47
llvm::MachOYAML::LoadCommand
Definition: MachOYAML.h:73
llvm::MachOYAML::Object::LinkEdit
LinkEditData LinkEdit
Definition: MachOYAML.h:144
llvm::MachOYAML::LinkEditData::NameList
std::vector< NListEntry > NameList
Definition: MachOYAML.h:129
llvm::MachOYAML::Object::LoadCommands
std::vector< LoadCommand > LoadCommands
Definition: MachOYAML.h:142
llvm::sort
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1683
llvm::function_ref
An efficient, type-erasing, non-owning reference to a callable.
Definition: STLFunctionalExtras.h:36
llvm::MachO::mach_header_64
Definition: MachO.h:526
llvm::DWARFYAML::Data::getNonEmptySectionNames
SetVector< StringRef > getNonEmptySectionNames() const
Definition: DWARFYAML.cpp:25
constructSection
Section constructSection(const MachO::section &Sec, uint32_t Index)
Definition: MachOReader.cpp:49
llvm::MachOYAML::FatArch::cpusubtype
llvm::yaml::Hex32 cpusubtype
Definition: MachOYAML.h:156
llvm::MachOYAML::FileHeader::reserved
llvm::yaml::Hex32 reserved
Definition: MachOYAML.h:70
BaseType
BaseType
A given derived pointer can have multiple base pointers through phi/selects.
Definition: SafepointIRVerifier.cpp:314
uint64_t
llvm::MachOYAML::Section::offset
llvm::yaml::Hex32 offset
Definition: MachOYAML.h:50
Addr
uint64_t Addr
Definition: ELFObjHandler.cpp:79
llvm::DWARFYAML::getDWARFEmitterByName
std::function< Error(raw_ostream &, const Data &)> getDWARFEmitterByName(StringRef SecName)
Definition: DWARFEmitter.h:47
llvm::MachOYAML::FileHeader::flags
llvm::yaml::Hex32 flags
Definition: MachOYAML.h:69
llvm::MachO::build_tool_version
Definition: MachO.h:857
llvm::MachO::any_relocation_info::r_word0
uint32_t r_word0
Definition: MachO.h:997
LEB128.h
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
@ EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
Definition: MachO.h:295
llvm::MachOYAML::NListEntry::n_sect
uint8_t n_sect
Definition: MachOYAML.h:87
llvm::MachO::dyld_info_command::lazy_bind_off
uint32_t lazy_bind_off
Definition: MachO.h:887
llvm::MachOYAML::FatArch::size
uint64_t size
Definition: MachOYAML.h:158
llvm::MachOYAML::LinkEditData::ChainedFixups
std::vector< yaml::Hex8 > ChainedFixups
Definition: MachOYAML.h:134
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::MachOYAML::NListEntry::n_type
llvm::yaml::Hex8 n_type
Definition: MachOYAML.h:86
memcpy
<%struct.s * > cast struct s *S to sbyte *< sbyte * > sbyte uint cast struct s *agg result to sbyte *< sbyte * > sbyte uint cast struct s *memtmp to sbyte *< sbyte * > sbyte uint ret void llc ends up issuing two memcpy or custom lower memcpy(of small size) to be ldmia/stmia. I think option 2 is better but the current register allocator cannot allocate a chunk of registers at a time. A feasible temporary solution is to use specific physical registers at the lowering time for small(<
llvm::codeview::CodeViewContainer::ObjectFile
@ ObjectFile
llvm::MachOYAML::Object::IsLittleEndian
bool IsLittleEndian
Definition: MachOYAML.h:140
llvm::MachOYAML::NListEntry::n_strx
uint32_t n_strx
Definition: MachOYAML.h:85
YAMLTraits.h
llvm::MachOYAML::LinkEditData
Definition: MachOYAML.h:123
llvm::MachO::load_command
Definition: MachO.h:537
yaml2obj.h
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
llvm::yaml::BinaryRef
Specialized YAMLIO scalar type for representing a binary blob.
Definition: YAML.h:63
llvm::Offset
@ Offset
Definition: DWP.cpp:406
llvm::MachOYAML::FileHeader::cputype
llvm::yaml::Hex32 cputype
Definition: MachOYAML.h:64
uint32_t
llvm::MachOYAML::LinkEditData::WeakBindOpcodes
std::vector< MachOYAML::BindOpcode > WeakBindOpcodes
Definition: MachOYAML.h:126
llvm::MachOYAML::FileHeader::magic
llvm::yaml::Hex32 magic
Definition: MachOYAML.h:63
llvm::MachO::NListType
NListType
Definition: MachO.h:313
llvm::MachO::dyld_info_command::weak_bind_off
uint32_t weak_bind_off
Definition: MachO.h:885
llvm::MachOYAML::Object::Header
FileHeader Header
Definition: MachOYAML.h:141
llvm::MachO::MH_CIGAM_64
@ MH_CIGAM_64
Definition: MachO.h:33
llvm::MachOYAML::LinkEditData::BindOpcodes
std::vector< MachOYAML::BindOpcode > BindOpcodes
Definition: MachOYAML.h:125
DWARFEmitter.h
llvm::MachO::dysymtab_command
Definition: MachO.h:709
llvm::MachOYAML::LoadCommand::Tools
std::vector< MachO::build_tool_version > Tools
Definition: MachOYAML.h:78
llvm::MachO::section_64
Definition: MachO.h:584
llvm::MachOYAML::FileHeader::cpusubtype
llvm::yaml::Hex32 cpusubtype
Definition: MachOYAML.h:65
llvm::createStringError
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1246
llvm::MachOYAML::Section::reserved3
llvm::yaml::Hex32 reserved3
Definition: MachOYAML.h:57
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
llvm::MachO::symtab_command::stroff
uint32_t stroff
Definition: MachO.h:705
llvm::MachOYAML::Object::RawLinkEditSegment
std::optional< llvm::yaml::BinaryRef > RawLinkEditSegment
Definition: MachOYAML.h:145
llvm::MachOYAML::FatArch
Definition: MachOYAML.h:154
llvm::MachO::mach_header
Definition: MachO.h:516
llvm::MachOYAML::FatArch::reserved
llvm::yaml::Hex32 reserved
Definition: MachOYAML.h:160
llvm::MachOYAML::Section::reserved1
llvm::yaml::Hex32 reserved1
Definition: MachOYAML.h:55
llvm::sys::IsLittleEndianHost
static const bool IsLittleEndianHost
Definition: SwapByteOrder.h:67
writeNListEntry
void writeNListEntry(const SymbolEntry &SE, bool IsLittleEndian, char *&Out, uint32_t Nstrx)
Definition: MachOWriter.cpp:272
llvm::MachOYAML::LinkEditData::StringTable
std::vector< StringRef > StringTable
Definition: MachOYAML.h:130
llvm::MachOYAML::Section::reserved2
llvm::yaml::Hex32 reserved2
Definition: MachOYAML.h:56
llvm::encodeULEB128
unsigned encodeULEB128(uint64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a ULEB128 value to an output stream.
Definition: LEB128.h:80
llvm::MachOYAML::FileHeader::ncmds
uint32_t ncmds
Definition: MachOYAML.h:67
llvm::MachO::fat_arch_64
Definition: MachO.h:968
llvm::MachO::symtab_command::symoff
uint32_t symoff
Definition: MachO.h:703
llvm::MachO::dyld_info_command::bind_off
uint32_t bind_off
Definition: MachO.h:883
llvm::MachO::dyld_info_command::rebase_off
uint32_t rebase_off
Definition: MachO.h:881
MachO.h
InlinePriorityMode::Size
@ Size
raw_ostream.h
llvm::MachO::linkedit_data_command::dataoff
uint32_t dataoff
Definition: MachO.h:808
llvm::MachO::swapStruct
void swapStruct(fat_header &mh)
Definition: MachO.h:1139
llvm::MachOYAML::Section::reloff
llvm::yaml::Hex32 reloff
Definition: MachOYAML.h:52
llvm::MachOYAML::Section::flags
llvm::yaml::Hex32 flags
Definition: MachOYAML.h:54
llvm::MachO::fat_header
Definition: MachO.h:955
llvm::handleAllErrors
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
Definition: Error.h:966
llvm::MachOYAML::Relocation
Definition: MachOYAML.h:31
llvm::MachO::SectionType
SectionType
These are the section type and attributes fields.
Definition: MachO.h:122
llvm::MachOYAML::Section::align
uint32_t align
Definition: MachOYAML.h:51
llvm::MachO::macho_load_command
Definition: MachO.h:2147