Files
clang-p2996/llvm/lib/ObjectYAML/MachOEmitter.cpp
Adrian Prantl 8bd8dd16e2 Extend obj2yaml to optionally preserve raw __LINKEDIT/__DATA segments.
I am planning to upstream MachOObjectFile code to support Darwin
chained fixups. In order to test the new parser features we need a way
to produce correct (and incorrect) chained fixups. Right now the only
tool that can produce them is the Darwin linker. To avoid having to
check in binary files, this patch allows obj2yaml to print a hexdump
of the raw LINKEDIT and DATA segment, which both allows to
bootstrap the parser and enables us to easily create malformed inputs
to test error handling in the parser.

This patch adds two new options to obj2yaml:

  -raw-data-segment
  -raw-linkedit-segment

Differential Revision: https://reviews.llvm.org/D113234
2021-11-08 11:30:12 -08:00

682 lines
23 KiB
C++

//===- yaml2macho - Convert YAML to a Mach object file --------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// The Mach component of yaml2obj.
///
//===----------------------------------------------------------------------===//
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/ObjectYAML/DWARFEmitter.h"
#include "llvm/ObjectYAML/ObjectYAML.h"
#include "llvm/ObjectYAML/yaml2obj.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Format.h"
using namespace llvm;
namespace {
class MachOWriter {
public:
MachOWriter(MachOYAML::Object &Obj) : Obj(Obj), fileStart(0) {
is64Bit = Obj.Header.magic == MachO::MH_MAGIC_64 ||
Obj.Header.magic == MachO::MH_CIGAM_64;
memset(reinterpret_cast<void *>(&Header), 0, sizeof(MachO::mach_header_64));
}
Error writeMachO(raw_ostream &OS);
private:
void writeHeader(raw_ostream &OS);
void writeLoadCommands(raw_ostream &OS);
Error writeSectionData(raw_ostream &OS);
void writeRelocations(raw_ostream &OS);
void writeLinkEditData(raw_ostream &OS);
void writeBindOpcodes(raw_ostream &OS,
std::vector<MachOYAML::BindOpcode> &BindOpcodes);
// LinkEdit writers
void writeRebaseOpcodes(raw_ostream &OS);
void writeBasicBindOpcodes(raw_ostream &OS);
void writeWeakBindOpcodes(raw_ostream &OS);
void writeLazyBindOpcodes(raw_ostream &OS);
void writeNameList(raw_ostream &OS);
void writeStringTable(raw_ostream &OS);
void writeExportTrie(raw_ostream &OS);
void dumpExportEntry(raw_ostream &OS, MachOYAML::ExportEntry &Entry);
void ZeroToOffset(raw_ostream &OS, size_t offset);
MachOYAML::Object &Obj;
bool is64Bit;
uint64_t fileStart;
MachO::mach_header_64 Header;
// Old PPC Object Files didn't have __LINKEDIT segments, the data was just
// stuck at the end of the file.
bool FoundLinkEditSeg = false;
};
Error MachOWriter::writeMachO(raw_ostream &OS) {
fileStart = OS.tell();
writeHeader(OS);
writeLoadCommands(OS);
if (Error Err = writeSectionData(OS))
return Err;
writeRelocations(OS);
if (!FoundLinkEditSeg)
writeLinkEditData(OS);
return Error::success();
}
void MachOWriter::writeHeader(raw_ostream &OS) {
Header.magic = Obj.Header.magic;
Header.cputype = Obj.Header.cputype;
Header.cpusubtype = Obj.Header.cpusubtype;
Header.filetype = Obj.Header.filetype;
Header.ncmds = Obj.Header.ncmds;
Header.sizeofcmds = Obj.Header.sizeofcmds;
Header.flags = Obj.Header.flags;
Header.reserved = Obj.Header.reserved;
if (Obj.IsLittleEndian != sys::IsLittleEndianHost)
MachO::swapStruct(Header);
auto header_size =
is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
OS.write((const char *)&Header, header_size);
}
template <typename SectionType>
SectionType constructSection(MachOYAML::Section Sec) {
SectionType TempSec;
memcpy(reinterpret_cast<void *>(&TempSec.sectname[0]), &Sec.sectname[0], 16);
memcpy(reinterpret_cast<void *>(&TempSec.segname[0]), &Sec.segname[0], 16);
TempSec.addr = Sec.addr;
TempSec.size = Sec.size;
TempSec.offset = Sec.offset;
TempSec.align = Sec.align;
TempSec.reloff = Sec.reloff;
TempSec.nreloc = Sec.nreloc;
TempSec.flags = Sec.flags;
TempSec.reserved1 = Sec.reserved1;
TempSec.reserved2 = Sec.reserved2;
return TempSec;
}
template <typename StructType>
size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS,
bool IsLittleEndian) {
return 0;
}
template <>
size_t writeLoadCommandData<MachO::segment_command>(MachOYAML::LoadCommand &LC,
raw_ostream &OS,
bool IsLittleEndian) {
size_t BytesWritten = 0;
for (const auto &Sec : LC.Sections) {
auto TempSec = constructSection<MachO::section>(Sec);
if (IsLittleEndian != sys::IsLittleEndianHost)
MachO::swapStruct(TempSec);
OS.write(reinterpret_cast<const char *>(&(TempSec)),
sizeof(MachO::section));
BytesWritten += sizeof(MachO::section);
}
return BytesWritten;
}
template <>
size_t writeLoadCommandData<MachO::segment_command_64>(
MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
size_t BytesWritten = 0;
for (const auto &Sec : LC.Sections) {
auto TempSec = constructSection<MachO::section_64>(Sec);
TempSec.reserved3 = Sec.reserved3;
if (IsLittleEndian != sys::IsLittleEndianHost)
MachO::swapStruct(TempSec);
OS.write(reinterpret_cast<const char *>(&(TempSec)),
sizeof(MachO::section_64));
BytesWritten += sizeof(MachO::section_64);
}
return BytesWritten;
}
size_t writePayloadString(MachOYAML::LoadCommand &LC, raw_ostream &OS) {
size_t BytesWritten = 0;
if (!LC.Content.empty()) {
OS.write(LC.Content.c_str(), LC.Content.length());
BytesWritten = LC.Content.length();
}
return BytesWritten;
}
template <>
size_t writeLoadCommandData<MachO::dylib_command>(MachOYAML::LoadCommand &LC,
raw_ostream &OS,
bool IsLittleEndian) {
return writePayloadString(LC, OS);
}
template <>
size_t writeLoadCommandData<MachO::dylinker_command>(MachOYAML::LoadCommand &LC,
raw_ostream &OS,
bool IsLittleEndian) {
return writePayloadString(LC, OS);
}
template <>
size_t writeLoadCommandData<MachO::rpath_command>(MachOYAML::LoadCommand &LC,
raw_ostream &OS,
bool IsLittleEndian) {
return writePayloadString(LC, OS);
}
template <>
size_t writeLoadCommandData<MachO::sub_framework_command>(
MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
return writePayloadString(LC, OS);
}
template <>
size_t writeLoadCommandData<MachO::sub_umbrella_command>(
MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
return writePayloadString(LC, OS);
}
template <>
size_t writeLoadCommandData<MachO::sub_client_command>(
MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
return writePayloadString(LC, OS);
}
template <>
size_t writeLoadCommandData<MachO::sub_library_command>(
MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
return writePayloadString(LC, OS);
}
template <>
size_t writeLoadCommandData<MachO::build_version_command>(
MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
size_t BytesWritten = 0;
for (const auto &T : LC.Tools) {
struct MachO::build_tool_version tool = T;
if (IsLittleEndian != sys::IsLittleEndianHost)
MachO::swapStruct(tool);
OS.write(reinterpret_cast<const char *>(&tool),
sizeof(MachO::build_tool_version));
BytesWritten += sizeof(MachO::build_tool_version);
}
return BytesWritten;
}
void ZeroFillBytes(raw_ostream &OS, size_t Size) {
std::vector<uint8_t> FillData(Size, 0);
OS.write(reinterpret_cast<char *>(FillData.data()), Size);
}
void Fill(raw_ostream &OS, size_t Size, uint32_t Data) {
std::vector<uint32_t> FillData((Size / 4) + 1, Data);
OS.write(reinterpret_cast<char *>(FillData.data()), Size);
}
void MachOWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) {
auto currOffset = OS.tell() - fileStart;
if (currOffset < Offset)
ZeroFillBytes(OS, Offset - currOffset);
}
void MachOWriter::writeLoadCommands(raw_ostream &OS) {
for (auto &LC : Obj.LoadCommands) {
size_t BytesWritten = 0;
llvm::MachO::macho_load_command Data = LC.Data;
#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
case MachO::LCName: \
if (Obj.IsLittleEndian != sys::IsLittleEndianHost) \
MachO::swapStruct(Data.LCStruct##_data); \
OS.write(reinterpret_cast<const char *>(&(Data.LCStruct##_data)), \
sizeof(MachO::LCStruct)); \
BytesWritten = sizeof(MachO::LCStruct); \
BytesWritten += \
writeLoadCommandData<MachO::LCStruct>(LC, OS, Obj.IsLittleEndian); \
break;
switch (LC.Data.load_command_data.cmd) {
default:
if (Obj.IsLittleEndian != sys::IsLittleEndianHost)
MachO::swapStruct(Data.load_command_data);
OS.write(reinterpret_cast<const char *>(&(Data.load_command_data)),
sizeof(MachO::load_command));
BytesWritten = sizeof(MachO::load_command);
BytesWritten +=
writeLoadCommandData<MachO::load_command>(LC, OS, Obj.IsLittleEndian);
break;
#include "llvm/BinaryFormat/MachO.def"
}
if (LC.PayloadBytes.size() > 0) {
OS.write(reinterpret_cast<const char *>(LC.PayloadBytes.data()),
LC.PayloadBytes.size());
BytesWritten += LC.PayloadBytes.size();
}
if (LC.ZeroPadBytes > 0) {
ZeroFillBytes(OS, LC.ZeroPadBytes);
BytesWritten += LC.ZeroPadBytes;
}
// Fill remaining bytes with 0. This will only get hit in partially
// specified test cases.
auto BytesRemaining = LC.Data.load_command_data.cmdsize - BytesWritten;
if (BytesRemaining > 0) {
ZeroFillBytes(OS, BytesRemaining);
}
}
}
Error MachOWriter::writeSectionData(raw_ostream &OS) {
uint64_t LinkEditOff = 0;
for (auto &LC : Obj.LoadCommands) {
switch (LC.Data.load_command_data.cmd) {
case MachO::LC_SEGMENT:
case MachO::LC_SEGMENT_64:
uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff
: LC.Data.segment_command_data.fileoff;
if (0 ==
strncmp(&LC.Data.segment_command_data.segname[0], "__LINKEDIT", 16)) {
FoundLinkEditSeg = true;
LinkEditOff = segOff;
if (Obj.RawLinkEditSegment)
continue;
writeLinkEditData(OS);
}
for (auto &Sec : LC.Sections) {
ZeroToOffset(OS, Sec.offset);
// Zero Fill any data between the end of the last thing we wrote and the
// start of this section.
if (OS.tell() - fileStart > Sec.offset && Sec.offset != (uint32_t)0)
return createStringError(
errc::invalid_argument,
"wrote too much data somewhere, section offsets don't line up");
StringRef SectName(Sec.sectname,
strnlen(Sec.sectname, sizeof(Sec.sectname)));
// If the section's content is specified in the 'DWARF' entry, we will
// emit it regardless of the section's segname.
if (Obj.DWARF.getNonEmptySectionNames().count(SectName.substr(2))) {
if (Sec.content)
return createStringError(errc::invalid_argument,
"cannot specify section '" + SectName +
"' contents in the 'DWARF' entry and "
"the 'content' at the same time");
auto EmitFunc = DWARFYAML::getDWARFEmitterByName(SectName.substr(2));
if (Error Err = EmitFunc(OS, Obj.DWARF))
return Err;
continue;
}
// Skip if it's a virtual section.
if (MachO::isVirtualSection(Sec.flags & MachO::SECTION_TYPE))
continue;
if (Sec.content) {
yaml::BinaryRef Content = *Sec.content;
Content.writeAsBinary(OS);
ZeroFillBytes(OS, Sec.size - Content.binary_size());
} else {
// Fill section data with 0xDEADBEEF.
Fill(OS, Sec.size, 0xDEADBEEFu);
}
}
uint64_t segSize = is64Bit ? LC.Data.segment_command_64_data.filesize
: LC.Data.segment_command_data.filesize;
ZeroToOffset(OS, segOff + segSize);
break;
}
}
if (Obj.RawLinkEditSegment) {
ZeroToOffset(OS, LinkEditOff);
if (OS.tell() - fileStart > LinkEditOff || !LinkEditOff)
return createStringError(errc::invalid_argument,
"section offsets don't line up");
Obj.RawLinkEditSegment->writeAsBinary(OS);
}
return Error::success();
}
// The implementation of makeRelocationInfo and makeScatteredRelocationInfo is
// consistent with how libObject parses MachO binary files. For the reference
// see getStruct, getRelocation, getPlainRelocationPCRel,
// getPlainRelocationLength and related methods in MachOObjectFile.cpp
static MachO::any_relocation_info
makeRelocationInfo(const MachOYAML::Relocation &R, bool IsLE) {
assert(!R.is_scattered && "non-scattered relocation expected");
MachO::any_relocation_info MRE;
MRE.r_word0 = R.address;
if (IsLE)
MRE.r_word1 = ((unsigned)R.symbolnum << 0) | ((unsigned)R.is_pcrel << 24) |
((unsigned)R.length << 25) | ((unsigned)R.is_extern << 27) |
((unsigned)R.type << 28);
else
MRE.r_word1 = ((unsigned)R.symbolnum << 8) | ((unsigned)R.is_pcrel << 7) |
((unsigned)R.length << 5) | ((unsigned)R.is_extern << 4) |
((unsigned)R.type << 0);
return MRE;
}
static MachO::any_relocation_info
makeScatteredRelocationInfo(const MachOYAML::Relocation &R) {
assert(R.is_scattered && "scattered relocation expected");
MachO::any_relocation_info MRE;
MRE.r_word0 = (((unsigned)R.address << 0) | ((unsigned)R.type << 24) |
((unsigned)R.length << 28) | ((unsigned)R.is_pcrel << 30) |
MachO::R_SCATTERED);
MRE.r_word1 = R.value;
return MRE;
}
void MachOWriter::writeRelocations(raw_ostream &OS) {
for (const MachOYAML::LoadCommand &LC : Obj.LoadCommands) {
switch (LC.Data.load_command_data.cmd) {
case MachO::LC_SEGMENT:
case MachO::LC_SEGMENT_64:
for (const MachOYAML::Section &Sec : LC.Sections) {
if (Sec.relocations.empty())
continue;
ZeroToOffset(OS, Sec.reloff);
for (const MachOYAML::Relocation &R : Sec.relocations) {
MachO::any_relocation_info MRE =
R.is_scattered ? makeScatteredRelocationInfo(R)
: makeRelocationInfo(R, Obj.IsLittleEndian);
if (Obj.IsLittleEndian != sys::IsLittleEndianHost)
MachO::swapStruct(MRE);
OS.write(reinterpret_cast<const char *>(&MRE),
sizeof(MachO::any_relocation_info));
}
}
}
}
}
void MachOWriter::writeBindOpcodes(
raw_ostream &OS, std::vector<MachOYAML::BindOpcode> &BindOpcodes) {
for (auto Opcode : BindOpcodes) {
uint8_t OpByte = Opcode.Opcode | Opcode.Imm;
OS.write(reinterpret_cast<char *>(&OpByte), 1);
for (auto Data : Opcode.ULEBExtraData) {
encodeULEB128(Data, OS);
}
for (auto Data : Opcode.SLEBExtraData) {
encodeSLEB128(Data, OS);
}
if (!Opcode.Symbol.empty()) {
OS.write(Opcode.Symbol.data(), Opcode.Symbol.size());
OS.write('\0');
}
}
}
void MachOWriter::dumpExportEntry(raw_ostream &OS,
MachOYAML::ExportEntry &Entry) {
encodeSLEB128(Entry.TerminalSize, OS);
if (Entry.TerminalSize > 0) {
encodeSLEB128(Entry.Flags, OS);
if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) {
encodeSLEB128(Entry.Other, OS);
OS << Entry.ImportName;
OS.write('\0');
} else {
encodeSLEB128(Entry.Address, OS);
if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
encodeSLEB128(Entry.Other, OS);
}
}
OS.write(static_cast<uint8_t>(Entry.Children.size()));
for (auto EE : Entry.Children) {
OS << EE.Name;
OS.write('\0');
encodeSLEB128(EE.NodeOffset, OS);
}
for (auto EE : Entry.Children)
dumpExportEntry(OS, EE);
}
void MachOWriter::writeExportTrie(raw_ostream &OS) {
dumpExportEntry(OS, Obj.LinkEdit.ExportTrie);
}
template <typename NListType>
void writeNListEntry(MachOYAML::NListEntry &NLE, raw_ostream &OS,
bool IsLittleEndian) {
NListType ListEntry;
ListEntry.n_strx = NLE.n_strx;
ListEntry.n_type = NLE.n_type;
ListEntry.n_sect = NLE.n_sect;
ListEntry.n_desc = NLE.n_desc;
ListEntry.n_value = NLE.n_value;
if (IsLittleEndian != sys::IsLittleEndianHost)
MachO::swapStruct(ListEntry);
OS.write(reinterpret_cast<const char *>(&ListEntry), sizeof(NListType));
}
void MachOWriter::writeLinkEditData(raw_ostream &OS) {
typedef void (MachOWriter::*writeHandler)(raw_ostream &);
typedef std::pair<uint64_t, writeHandler> writeOperation;
std::vector<writeOperation> WriteQueue;
MachO::dyld_info_command *DyldInfoOnlyCmd = 0;
MachO::symtab_command *SymtabCmd = 0;
for (auto &LC : Obj.LoadCommands) {
switch (LC.Data.load_command_data.cmd) {
case MachO::LC_SYMTAB:
SymtabCmd = &LC.Data.symtab_command_data;
WriteQueue.push_back(
std::make_pair(SymtabCmd->symoff, &MachOWriter::writeNameList));
WriteQueue.push_back(
std::make_pair(SymtabCmd->stroff, &MachOWriter::writeStringTable));
break;
case MachO::LC_DYLD_INFO_ONLY:
DyldInfoOnlyCmd = &LC.Data.dyld_info_command_data;
WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->rebase_off,
&MachOWriter::writeRebaseOpcodes));
WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->bind_off,
&MachOWriter::writeBasicBindOpcodes));
WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->weak_bind_off,
&MachOWriter::writeWeakBindOpcodes));
WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->lazy_bind_off,
&MachOWriter::writeLazyBindOpcodes));
WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->export_off,
&MachOWriter::writeExportTrie));
break;
}
}
llvm::sort(WriteQueue, [](const writeOperation &a, const writeOperation &b) {
return a.first < b.first;
});
for (auto writeOp : WriteQueue) {
ZeroToOffset(OS, writeOp.first);
(this->*writeOp.second)(OS);
}
}
void MachOWriter::writeRebaseOpcodes(raw_ostream &OS) {
MachOYAML::LinkEditData &LinkEdit = Obj.LinkEdit;
for (auto Opcode : LinkEdit.RebaseOpcodes) {
uint8_t OpByte = Opcode.Opcode | Opcode.Imm;
OS.write(reinterpret_cast<char *>(&OpByte), 1);
for (auto Data : Opcode.ExtraData)
encodeULEB128(Data, OS);
}
}
void MachOWriter::writeBasicBindOpcodes(raw_ostream &OS) {
writeBindOpcodes(OS, Obj.LinkEdit.BindOpcodes);
}
void MachOWriter::writeWeakBindOpcodes(raw_ostream &OS) {
writeBindOpcodes(OS, Obj.LinkEdit.WeakBindOpcodes);
}
void MachOWriter::writeLazyBindOpcodes(raw_ostream &OS) {
writeBindOpcodes(OS, Obj.LinkEdit.LazyBindOpcodes);
}
void MachOWriter::writeNameList(raw_ostream &OS) {
for (auto NLE : Obj.LinkEdit.NameList) {
if (is64Bit)
writeNListEntry<MachO::nlist_64>(NLE, OS, Obj.IsLittleEndian);
else
writeNListEntry<MachO::nlist>(NLE, OS, Obj.IsLittleEndian);
}
}
void MachOWriter::writeStringTable(raw_ostream &OS) {
for (auto Str : Obj.LinkEdit.StringTable) {
OS.write(Str.data(), Str.size());
OS.write('\0');
}
}
class UniversalWriter {
public:
UniversalWriter(yaml::YamlObjectFile &ObjectFile)
: ObjectFile(ObjectFile), fileStart(0) {}
Error writeMachO(raw_ostream &OS);
private:
void writeFatHeader(raw_ostream &OS);
void writeFatArchs(raw_ostream &OS);
void ZeroToOffset(raw_ostream &OS, size_t offset);
yaml::YamlObjectFile &ObjectFile;
uint64_t fileStart;
};
Error UniversalWriter::writeMachO(raw_ostream &OS) {
fileStart = OS.tell();
if (ObjectFile.MachO) {
MachOWriter Writer(*ObjectFile.MachO);
return Writer.writeMachO(OS);
}
writeFatHeader(OS);
writeFatArchs(OS);
auto &FatFile = *ObjectFile.FatMachO;
if (FatFile.FatArchs.size() < FatFile.Slices.size())
return createStringError(
errc::invalid_argument,
"cannot write 'Slices' if not described in 'FatArches'");
for (size_t i = 0; i < FatFile.Slices.size(); i++) {
ZeroToOffset(OS, FatFile.FatArchs[i].offset);
MachOWriter Writer(FatFile.Slices[i]);
if (Error Err = Writer.writeMachO(OS))
return Err;
auto SliceEnd = FatFile.FatArchs[i].offset + FatFile.FatArchs[i].size;
ZeroToOffset(OS, SliceEnd);
}
return Error::success();
}
void UniversalWriter::writeFatHeader(raw_ostream &OS) {
auto &FatFile = *ObjectFile.FatMachO;
MachO::fat_header header;
header.magic = FatFile.Header.magic;
header.nfat_arch = FatFile.Header.nfat_arch;
if (sys::IsLittleEndianHost)
swapStruct(header);
OS.write(reinterpret_cast<const char *>(&header), sizeof(MachO::fat_header));
}
template <typename FatArchType>
FatArchType constructFatArch(MachOYAML::FatArch &Arch) {
FatArchType FatArch;
FatArch.cputype = Arch.cputype;
FatArch.cpusubtype = Arch.cpusubtype;
FatArch.offset = Arch.offset;
FatArch.size = Arch.size;
FatArch.align = Arch.align;
return FatArch;
}
template <typename StructType>
void writeFatArch(MachOYAML::FatArch &LC, raw_ostream &OS) {}
template <>
void writeFatArch<MachO::fat_arch>(MachOYAML::FatArch &Arch, raw_ostream &OS) {
auto FatArch = constructFatArch<MachO::fat_arch>(Arch);
if (sys::IsLittleEndianHost)
swapStruct(FatArch);
OS.write(reinterpret_cast<const char *>(&FatArch), sizeof(MachO::fat_arch));
}
template <>
void writeFatArch<MachO::fat_arch_64>(MachOYAML::FatArch &Arch,
raw_ostream &OS) {
auto FatArch = constructFatArch<MachO::fat_arch_64>(Arch);
FatArch.reserved = Arch.reserved;
if (sys::IsLittleEndianHost)
swapStruct(FatArch);
OS.write(reinterpret_cast<const char *>(&FatArch),
sizeof(MachO::fat_arch_64));
}
void UniversalWriter::writeFatArchs(raw_ostream &OS) {
auto &FatFile = *ObjectFile.FatMachO;
bool is64Bit = FatFile.Header.magic == MachO::FAT_MAGIC_64;
for (auto Arch : FatFile.FatArchs) {
if (is64Bit)
writeFatArch<MachO::fat_arch_64>(Arch, OS);
else
writeFatArch<MachO::fat_arch>(Arch, OS);
}
}
void UniversalWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) {
auto currOffset = OS.tell() - fileStart;
if (currOffset < Offset)
ZeroFillBytes(OS, Offset - currOffset);
}
} // end anonymous namespace
namespace llvm {
namespace yaml {
bool yaml2macho(YamlObjectFile &Doc, raw_ostream &Out, ErrorHandler EH) {
UniversalWriter Writer(Doc);
if (Error Err = Writer.writeMachO(Out)) {
handleAllErrors(std::move(Err),
[&](const ErrorInfoBase &Err) { EH(Err.message()); });
return false;
}
return true;
}
} // namespace yaml
} // namespace llvm