[llvm] r273719 - [obj2yaml] [yaml2obj] Support for MachO Universal binaries
Chris Bieneman via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 24 13:42:29 PDT 2016
Author: cbieneman
Date: Fri Jun 24 15:42:28 2016
New Revision: 273719
URL: http://llvm.org/viewvc/llvm-project?rev=273719&view=rev
Log:
[obj2yaml] [yaml2obj] Support for MachO Universal binaries
This patch adds round-trip support for MachO Universal binaries to obj2yaml and yaml2obj. Universal binaries have a header and list of architecture structures, followed by a the individual object files at specified offsets.
Added:
llvm/trunk/test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml
Modified:
llvm/trunk/include/llvm/Object/MachOUniversal.h
llvm/trunk/include/llvm/ObjectYAML/MachOYAML.h
llvm/trunk/lib/ObjectYAML/MachOYAML.cpp
llvm/trunk/tools/obj2yaml/macho2yaml.cpp
llvm/trunk/tools/obj2yaml/obj2yaml.cpp
llvm/trunk/tools/obj2yaml/obj2yaml.h
llvm/trunk/tools/yaml2obj/yaml2macho.cpp
Modified: llvm/trunk/include/llvm/Object/MachOUniversal.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/MachOUniversal.h?rev=273719&r1=273718&r2=273719&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Object/MachOUniversal.h (original)
+++ llvm/trunk/include/llvm/Object/MachOUniversal.h Fri Jun 24 15:42:28 2016
@@ -84,6 +84,12 @@ public:
else // Parent->getMagic() == MachO::FAT_MAGIC_64
return Header64.align;
}
+ uint32_t getReserved() const {
+ if (Parent->getMagic() == MachO::FAT_MAGIC)
+ return 0;
+ else // Parent->getMagic() == MachO::FAT_MAGIC_64
+ return Header64.align;
+ }
std::string getArchTypeName() const {
if (Parent->getMagic() == MachO::FAT_MAGIC) {
Triple T =
Modified: llvm/trunk/include/llvm/ObjectYAML/MachOYAML.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ObjectYAML/MachOYAML.h?rev=273719&r1=273718&r2=273719&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ObjectYAML/MachOYAML.h (original)
+++ llvm/trunk/include/llvm/ObjectYAML/MachOYAML.h Fri Jun 24 15:42:28 2016
@@ -109,6 +109,32 @@ struct Object {
LinkEditData LinkEdit;
};
+struct FatHeader {
+ llvm::yaml::Hex32 magic;
+ uint32_t nfat_arch;
+};
+
+struct FatArch {
+ llvm::yaml::Hex32 cputype;
+ llvm::yaml::Hex32 cpusubtype;
+ llvm::yaml::Hex64 offset;
+ uint64_t size;
+ uint32_t align;
+ llvm::yaml::Hex32 reserved;
+};
+
+struct UniversalBinary {
+ FatHeader Header;
+ std::vector<FatArch> FatArchs;
+ std::vector<Object> Slices;
+};
+
+struct MachFile {
+ bool isFat;
+ UniversalBinary FatFile;
+ Object ThinFile;
+};
+
} // namespace llvm::MachOYAML
} // namespace llvm
@@ -122,6 +148,8 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachO
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::ExportEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::NListEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::StringRef)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Object)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::FatArch)
namespace llvm {
namespace yaml {
@@ -134,6 +162,22 @@ template <> struct MappingTraits<MachOYA
static void mapping(IO &IO, MachOYAML::Object &Object);
};
+template <> struct MappingTraits<MachOYAML::FatHeader> {
+ static void mapping(IO &IO, MachOYAML::FatHeader &FatHeader);
+};
+
+template <> struct MappingTraits<MachOYAML::FatArch> {
+ static void mapping(IO &IO, MachOYAML::FatArch &FatArch);
+};
+
+template <> struct MappingTraits<MachOYAML::UniversalBinary> {
+ static void mapping(IO &IO, MachOYAML::UniversalBinary &UniversalBinary);
+};
+
+template <> struct MappingTraits<MachOYAML::MachFile> {
+ static void mapping(IO &IO, MachOYAML::MachFile &MachFile);
+};
+
template <> struct MappingTraits<MachOYAML::LoadCommand> {
static void mapping(IO &IO, MachOYAML::LoadCommand &LoadCommand);
};
Modified: llvm/trunk/lib/ObjectYAML/MachOYAML.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ObjectYAML/MachOYAML.cpp?rev=273719&r1=273718&r2=273719&view=diff
==============================================================================
--- llvm/trunk/lib/ObjectYAML/MachOYAML.cpp (original)
+++ llvm/trunk/lib/ObjectYAML/MachOYAML.cpp Fri Jun 24 15:42:28 2016
@@ -96,7 +96,68 @@ void MappingTraits<MachOYAML::Object>::m
IO.mapRequired("FileHeader", Object.Header);
IO.mapOptional("LoadCommands", Object.LoadCommands);
IO.mapOptional("LinkEditData", Object.LinkEdit);
- IO.setContext(nullptr);
+
+ if (IO.getContext() == &Object)
+ IO.setContext(nullptr);
+}
+
+void MappingTraits<MachOYAML::FatHeader>::mapping(
+ IO &IO, MachOYAML::FatHeader &FatHeader) {
+ IO.mapRequired("magic", FatHeader.magic);
+ IO.mapRequired("nfat_arch", FatHeader.nfat_arch);
+}
+
+void MappingTraits<MachOYAML::FatArch>::mapping(IO &IO,
+ MachOYAML::FatArch &FatArch) {
+ IO.mapRequired("cputype", FatArch.cputype);
+ IO.mapRequired("cpusubtype", FatArch.cpusubtype);
+ IO.mapRequired("offset", FatArch.offset);
+ IO.mapRequired("size", FatArch.size);
+ IO.mapRequired("align", FatArch.align);
+ IO.mapOptional("reserved", FatArch.reserved,
+ static_cast<llvm::yaml::Hex32>(0));
+}
+
+void MappingTraits<MachOYAML::UniversalBinary>::mapping(
+ IO &IO, MachOYAML::UniversalBinary &UniversalBinary) {
+ if (!IO.getContext()) {
+ IO.setContext(&UniversalBinary);
+ IO.mapTag("!fat-mach-o", true);
+ }
+ IO.mapRequired("FatHeader", UniversalBinary.Header);
+ IO.mapRequired("FatArchs", UniversalBinary.FatArchs);
+ IO.mapRequired("Slices", UniversalBinary.Slices);
+
+ if (IO.getContext() == &UniversalBinary)
+ IO.setContext(nullptr);
+}
+
+void MappingTraits<MachOYAML::MachFile>::mapping(
+ IO &IO, MachOYAML::MachFile &MachFile) {
+ if (!IO.getContext()) {
+ IO.setContext(&MachFile);
+ }
+ if (IO.outputting()) {
+ if (MachFile.isFat) {
+ IO.mapTag("!fat-mach-o", true);
+ MappingTraits<MachOYAML::UniversalBinary>::mapping(IO, MachFile.FatFile);
+ } else {
+ IO.mapTag("!mach-o", true);
+ MappingTraits<MachOYAML::Object>::mapping(IO, MachFile.ThinFile);
+ }
+ } else {
+ if (IO.mapTag("!fat-mach-o")) {
+ MachFile.isFat = true;
+ MappingTraits<MachOYAML::UniversalBinary>::mapping(IO, MachFile.FatFile);
+ } else if (IO.mapTag("!mach-o")) {
+ MachFile.isFat = false;
+ MappingTraits<MachOYAML::Object>::mapping(IO, MachFile.ThinFile);
+ } else {
+ assert(false && "No tag found in YAML, cannot identify file type!");
+ }
+ }
+ if (IO.getContext() == &MachFile)
+ IO.setContext(nullptr);
}
void MappingTraits<MachOYAML::LinkEditData>::mapping(
Added: llvm/trunk/test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml?rev=273719&view=auto
==============================================================================
--- llvm/trunk/test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml (added)
+++ llvm/trunk/test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml Fri Jun 24 15:42:28 2016
@@ -0,0 +1,72 @@
+# RUN: yaml2obj -format=macho %s | obj2yaml | FileCheck %s
+
+--- !fat-mach-o
+FatHeader:
+ magic: 0xCAFEBABE
+ nfat_arch: 2
+FatArchs:
+ - cputype: 0x00000007
+ cpusubtype: 0x00000003
+ offset: 0x0000000000001000
+ size: 15244
+ align: 12
+ - cputype: 0x01000007
+ cpusubtype: 0x80000003
+ offset: 0x0000000000005000
+ size: 15380
+ align: 12
+Slices:
+ - FileHeader:
+ magic: 0xFEEDFACE
+ cputype: 0x00000007
+ cpusubtype: 0x00000003
+ filetype: 0x00000002
+ ncmds: 0
+ sizeofcmds: 0
+ flags: 0x01218085
+ - FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x01000007
+ cpusubtype: 0x80000003
+ filetype: 0x00000002
+ ncmds: 0
+ sizeofcmds: 0
+ flags: 0x00218085
+ reserved: 0x00000000
+...
+
+
+#CHECK: --- !fat-mach-o
+#CHECK: FatHeader:
+#CHECK: magic: 0xCAFEBABE
+#CHECK: nfat_arch: 2
+#CHECK: FatArchs:
+#CHECK: - cputype: 0x00000007
+#CHECK: cpusubtype: 0x00000003
+#CHECK: offset: 0x0000000000001000
+#CHECK: size: 15244
+#CHECK: align: 12
+#CHECK: - cputype: 0x01000007
+#CHECK: cpusubtype: 0x80000003
+#CHECK: offset: 0x0000000000005000
+#CHECK: size: 15380
+#CHECK: align: 12
+#CHECK: Slices:
+#CHECK: - FileHeader:
+#CHECK: magic: 0xFEEDFACE
+#CHECK: cputype: 0x00000007
+#CHECK: cpusubtype: 0x00000003
+#CHECK: filetype: 0x00000002
+#CHECK: ncmds: 0
+#CHECK: sizeofcmds: 0
+#CHECK: flags: 0x01218085
+#CHECK: - FileHeader:
+#CHECK: magic: 0xFEEDFACF
+#CHECK: cputype: 0x01000007
+#CHECK: cpusubtype: 0x80000003
+#CHECK: filetype: 0x00000002
+#CHECK: ncmds: 0
+#CHECK: sizeofcmds: 0
+#CHECK: flags: 0x00218085
+#CHECK: reserved: 0x00000000
+#CHECK: ...
Modified: llvm/trunk/tools/obj2yaml/macho2yaml.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/obj2yaml/macho2yaml.cpp?rev=273719&r1=273718&r2=273719&view=diff
==============================================================================
--- llvm/trunk/tools/obj2yaml/macho2yaml.cpp (original)
+++ llvm/trunk/tools/obj2yaml/macho2yaml.cpp Fri Jun 24 15:42:28 2016
@@ -473,23 +473,52 @@ Error macho2yaml(raw_ostream &Out, const
}
Error macho2yaml(raw_ostream &Out, const object::MachOUniversalBinary &Obj) {
- return make_error<Obj2YamlError>(obj2yaml_error::not_implemented);
+ MachOYAML::MachFile YAMLFile;
+ YAMLFile.isFat = true;
+ MachOYAML::UniversalBinary &YAML = YAMLFile.FatFile;
+ YAML.Header.magic = Obj.getMagic();
+ YAML.Header.nfat_arch = Obj.getNumberOfObjects();
+
+ for (auto Slice : Obj.objects()) {
+ MachOYAML::FatArch arch;
+ arch.cputype = Slice.getCPUType();
+ arch.cpusubtype = Slice.getCPUSubType();
+ arch.offset = Slice.getOffset();
+ arch.size = Slice.getSize();
+ arch.align = Slice.getAlign();
+ arch.reserved = Slice.getReserved();
+ YAML.FatArchs.push_back(arch);
+
+ auto SliceObj = Slice.getAsObjectFile();
+ if (!SliceObj)
+ return SliceObj.takeError();
+
+ MachODumper Dumper(*SliceObj.get());
+ Expected<std::unique_ptr<MachOYAML::Object>> YAMLObj = Dumper.dump();
+ if (!YAMLObj)
+ return YAMLObj.takeError();
+ YAML.Slices.push_back(*YAMLObj.get());
+ }
+
+ yaml::Output Yout(Out);
+ Yout << YAML;
+ return Error::success();
}
-std::error_code macho2yaml(raw_ostream &Out, const object::ObjectFile &Obj) {
- if (const auto *MachOObj = dyn_cast<object::MachOUniversalBinary>(&Obj)) {
+std::error_code macho2yaml(raw_ostream &Out, const object::Binary &Binary) {
+ if (const auto *MachOObj = dyn_cast<object::MachOUniversalBinary>(&Binary)) {
if (auto Err = macho2yaml(Out, *MachOObj)) {
return errorToErrorCode(std::move(Err));
}
return obj2yaml_error::success;
}
- if (const auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj)) {
+ if (const auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Binary)) {
if (auto Err = macho2yaml(Out, *MachOObj)) {
return errorToErrorCode(std::move(Err));
}
return obj2yaml_error::success;
}
-
+
return obj2yaml_error::unsupported_obj_file_format;
}
Modified: llvm/trunk/tools/obj2yaml/obj2yaml.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/obj2yaml/obj2yaml.cpp?rev=273719&r1=273718&r2=273719&view=diff
==============================================================================
--- llvm/trunk/tools/obj2yaml/obj2yaml.cpp (original)
+++ llvm/trunk/tools/obj2yaml/obj2yaml.cpp Fri Jun 24 15:42:28 2016
@@ -24,8 +24,6 @@ static std::error_code dumpObject(const
return coff2yaml(outs(), cast<COFFObjectFile>(Obj));
if (Obj.isELF())
return elf2yaml(outs(), Obj);
- if (Obj.isMachO() || Obj.isMachOUniversalBinary())
- return macho2yaml(outs(), Obj);
return obj2yaml_error::unsupported_obj_file_format;
}
@@ -36,6 +34,10 @@ static std::error_code dumpInput(StringR
return errorToErrorCode(BinaryOrErr.takeError());
Binary &Binary = *BinaryOrErr.get().getBinary();
+ // Universal MachO is not a subclass of ObjectFile, so it needs to be handled
+ // here with the other binary types.
+ if (Binary.isMachO() || Binary.isMachOUniversalBinary())
+ return macho2yaml(outs(), Binary);
// TODO: If this is an archive, then burst it and dump each entry
if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary))
return dumpObject(*Obj);
Modified: llvm/trunk/tools/obj2yaml/obj2yaml.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/obj2yaml/obj2yaml.h?rev=273719&r1=273718&r2=273719&view=diff
==============================================================================
--- llvm/trunk/tools/obj2yaml/obj2yaml.h (original)
+++ llvm/trunk/tools/obj2yaml/obj2yaml.h Fri Jun 24 15:42:28 2016
@@ -22,6 +22,6 @@ std::error_code coff2yaml(llvm::raw_ostr
std::error_code elf2yaml(llvm::raw_ostream &Out,
const llvm::object::ObjectFile &Obj);
std::error_code macho2yaml(llvm::raw_ostream &Out,
- const llvm::object::ObjectFile &Obj);
+ const llvm::object::Binary &Obj);
#endif
Modified: llvm/trunk/tools/yaml2obj/yaml2macho.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/yaml2obj/yaml2macho.cpp?rev=273719&r1=273718&r2=273719&view=diff
==============================================================================
--- llvm/trunk/tools/yaml2obj/yaml2macho.cpp (original)
+++ llvm/trunk/tools/yaml2obj/yaml2macho.cpp Fri Jun 24 15:42:28 2016
@@ -424,17 +424,120 @@ Error MachOWriter::writeStringTable(raw_
return Error::success();
}
+class UniversalWriter {
+public:
+ UniversalWriter(MachOYAML::MachFile &MachFile)
+ : MachFile(MachFile), fileStart(0) {}
+
+ Error writeMachO(raw_ostream &OS);
+
+private:
+ Error writeFatHeader(raw_ostream &OS);
+ Error writeFatArchs(raw_ostream &OS);
+
+ void ZeroToOffset(raw_ostream &OS, size_t offset);
+
+ MachOYAML::MachFile &MachFile;
+ uint64_t fileStart;
+};
+
+Error UniversalWriter::writeMachO(raw_ostream &OS) {
+ fileStart = OS.tell();
+ if (!MachFile.isFat) {
+ MachOWriter Writer(MachFile.ThinFile);
+ return Writer.writeMachO(OS);
+ }
+ if (auto Err = writeFatHeader(OS))
+ return Err;
+ if (auto Err = writeFatArchs(OS))
+ return Err;
+ auto &FatFile = MachFile.FatFile;
+ assert(FatFile.FatArchs.size() == FatFile.Slices.size());
+ for (size_t i = 0; i < FatFile.Slices.size(); i++) {
+ ZeroToOffset(OS, FatFile.FatArchs[i].offset);
+ MachOWriter Writer(FatFile.Slices[i]);
+ if (auto Err = Writer.writeMachO(OS))
+ return Err;
+ auto SliceEnd = FatFile.FatArchs[i].offset + FatFile.FatArchs[i].size;
+ ZeroToOffset(OS, SliceEnd);
+ }
+ return Error::success();
+}
+
+Error UniversalWriter::writeFatHeader(raw_ostream &OS) {
+ auto &FatFile = MachFile.FatFile;
+ 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));
+ return Error::success();
+}
+
+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));
+}
+
+Error UniversalWriter::writeFatArchs(raw_ostream &OS) {
+ auto &FatFile = MachFile.FatFile;
+ 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);
+ }
+
+ return Error::success();
+}
+
+void UniversalWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) {
+ auto currOffset = OS.tell() - fileStart;
+ if (currOffset < Offset)
+ ZeroFillBytes(OS, Offset - currOffset);
+}
+
} // end anonymous namespace
int yaml2macho(yaml::Input &YIn, raw_ostream &Out) {
- MachOYAML::Object Doc;
+ MachOYAML::MachFile Doc;
YIn >> Doc;
if (YIn.error()) {
errs() << "yaml2obj: Failed to parse YAML file!\n";
return 1;
}
- MachOWriter Writer(Doc);
+ UniversalWriter Writer(Doc);
if (auto Err = Writer.writeMachO(Out)) {
errs() << toString(std::move(Err));
return 1;
More information about the llvm-commits
mailing list