From 062cef56d2516e972d6203828cdd28fdb825399a Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 13 May 2016 17:41:41 +0000 Subject: [PATCH] [obj2yaml] [yaml2obj] Basic support for MachO::load_command This patch adds basic support for MachO::load_command. Load command types and sizes are encoded in the YAML and expanded back into MachO. The YAML doesn't yet support load command structs, that is coming next. In the meantime as a temporary measure when writing MachO files the load commands are padded with zeros so that the generated binary is valid. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@269442 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/ObjectYAML/MachOYAML.h | 27 +++++++++++ lib/ObjectYAML/MachOYAML.cpp | 11 +++++ test/ObjectYAML/MachO/load_commands.yaml | 81 ++++++++++++++++++++++++++++++++ tools/obj2yaml/macho2yaml.cpp | 13 +++-- tools/yaml2obj/yaml2macho.cpp | 26 ++++++++-- 5 files changed, 152 insertions(+), 6 deletions(-) create mode 100644 test/ObjectYAML/MachO/load_commands.yaml diff --git a/include/llvm/ObjectYAML/MachOYAML.h b/include/llvm/ObjectYAML/MachOYAML.h index 00d7ab2d377..bfc6dcb4028 100644 --- a/include/llvm/ObjectYAML/MachOYAML.h +++ b/include/llvm/ObjectYAML/MachOYAML.h @@ -33,12 +33,23 @@ struct FileHeader { llvm::yaml::Hex32 reserved; }; +struct LoadCommand { + virtual ~LoadCommand(); + MachO::LoadCommandType cmd; + uint32_t cmdsize; +}; + struct Object { FileHeader Header; + std::vector> LoadCommands; }; } // namespace llvm::MachOYAML +} // namespace llvm +LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) + +namespace llvm { namespace yaml { template <> struct MappingTraits { @@ -49,6 +60,22 @@ template <> struct MappingTraits { static void mapping(IO &IO, MachOYAML::Object &Object); }; +template <> struct MappingTraits> { + static void mapping(IO &IO, + std::unique_ptr &LoadCommand); +}; + +#define HANDLE_LOAD_COMMAND(LoadCommandName, LoadCommandValue) \ + io.enumCase(value, #LoadCommandName, MachO::LoadCommandName); + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, MachO::LoadCommandType &value) { +#include "llvm/Support/MachO.def" + } +}; + +#undef HANDLE_LOAD_COMMAND + } // namespace llvm::yaml } // namespace llvm diff --git a/lib/ObjectYAML/MachOYAML.cpp b/lib/ObjectYAML/MachOYAML.cpp index d54140b6794..af80c1645a6 100644 --- a/lib/ObjectYAML/MachOYAML.cpp +++ b/lib/ObjectYAML/MachOYAML.cpp @@ -16,6 +16,8 @@ namespace llvm { +MachOYAML::LoadCommand::~LoadCommand() {} + namespace yaml { void MappingTraits::mapping( @@ -40,9 +42,18 @@ void MappingTraits::mapping(IO &IO, IO.mapTag("!mach-o", true); } IO.mapRequired("FileHeader", Object.Header); + IO.mapOptional("LoadCommands", Object.LoadCommands); IO.setContext(nullptr); } +void MappingTraits>::mapping( + IO &IO, std::unique_ptr &LoadCommand) { + if (!IO.outputting()) + LoadCommand.reset(new MachOYAML::LoadCommand()); + IO.mapRequired("cmd", LoadCommand->cmd); + IO.mapRequired("cmdsize", LoadCommand->cmdsize); +} + } // namespace llvm::yaml } // namespace llvm diff --git a/test/ObjectYAML/MachO/load_commands.yaml b/test/ObjectYAML/MachO/load_commands.yaml new file mode 100644 index 00000000000..246759da2cc --- /dev/null +++ b/test/ObjectYAML/MachO/load_commands.yaml @@ -0,0 +1,81 @@ +# RUN: yaml2obj -format=macho %s | obj2yaml | FileCheck %s + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x80000003 + filetype: 0x00000002 + ncmds: 16 + sizeofcmds: 1408 + flags: 0x00218085 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 72 + - cmd: LC_SEGMENT_64 + cmdsize: 552 + - cmd: LC_SEGMENT_64 + cmdsize: 312 + - cmd: LC_SEGMENT_64 + cmdsize: 72 + - cmd: LC_DYLD_INFO_ONLY + cmdsize: 48 + - cmd: LC_SYMTAB + cmdsize: 24 + - cmd: LC_DYSYMTAB + cmdsize: 80 + - cmd: LC_LOAD_DYLINKER + cmdsize: 32 + - cmd: LC_UUID + cmdsize: 24 + - cmd: LC_VERSION_MIN_MACOSX + cmdsize: 16 + - cmd: LC_SOURCE_VERSION + cmdsize: 16 + - cmd: LC_MAIN + cmdsize: 24 + - cmd: LC_LOAD_DYLIB + cmdsize: 48 + - cmd: LC_LOAD_DYLIB + cmdsize: 56 + - cmd: LC_FUNCTION_STARTS + cmdsize: 16 + - cmd: LC_DATA_IN_CODE + cmdsize: 16 +... + + +# CHECK: LoadCommands: +# CHECK: - cmd: LC_SEGMENT_64 +# CHECK: cmdsize: 72 +# CHECK: - cmd: LC_SEGMENT_64 +# CHECK: cmdsize: 552 +# CHECK: - cmd: LC_SEGMENT_64 +# CHECK: cmdsize: 312 +# CHECK: - cmd: LC_SEGMENT_64 +# CHECK: cmdsize: 72 +# CHECK: - cmd: LC_DYLD_INFO_ONLY +# CHECK: cmdsize: 48 +# CHECK: - cmd: LC_SYMTAB +# CHECK: cmdsize: 24 +# CHECK: - cmd: LC_DYSYMTAB +# CHECK: cmdsize: 80 +# CHECK: - cmd: LC_LOAD_DYLINKER +# CHECK: cmdsize: 32 +# CHECK: - cmd: LC_UUID +# CHECK: cmdsize: 24 +# CHECK: - cmd: LC_VERSION_MIN_MACOSX +# CHECK: cmdsize: 16 +# CHECK: - cmd: LC_SOURCE_VERSION +# CHECK: cmdsize: 16 +# CHECK: - cmd: LC_MAIN +# CHECK: cmdsize: 24 +# CHECK: - cmd: LC_LOAD_DYLIB +# CHECK: cmdsize: 48 +# CHECK: - cmd: LC_LOAD_DYLIB +# CHECK: cmdsize: 56 +# CHECK: - cmd: LC_FUNCTION_STARTS +# CHECK: cmdsize: 16 +# CHECK: - cmd: LC_DATA_IN_CODE +# CHECK: cmdsize: 16 diff --git a/tools/obj2yaml/macho2yaml.cpp b/tools/obj2yaml/macho2yaml.cpp index b787a3e0c24..e71f467e794 100644 --- a/tools/obj2yaml/macho2yaml.cpp +++ b/tools/obj2yaml/macho2yaml.cpp @@ -21,10 +21,10 @@ class MachODumper { public: MachODumper(const object::MachOObjectFile &O) : Obj(O) {} - Expected > dump(); + Expected> dump(); }; -Expected > MachODumper::dump() { +Expected> MachODumper::dump() { auto Y = make_unique(); Y->Header.magic = Obj.getHeader().magic; Y->Header.cputype = Obj.getHeader().cputype; @@ -34,12 +34,19 @@ Expected > MachODumper::dump() { Y->Header.sizeofcmds = Obj.getHeader().sizeofcmds; Y->Header.flags = Obj.getHeader().flags; + for (auto load_command : Obj.load_commands()) { + auto LC = make_unique(); + LC->cmd = static_cast(load_command.C.cmd); + LC->cmdsize = load_command.C.cmdsize; + Y->LoadCommands.push_back(std::move(LC)); + } + return std::move(Y); } Error macho2yaml(raw_ostream &Out, const object::MachOObjectFile &Obj) { MachODumper Dumper(Obj); - Expected > YAML = Dumper.dump(); + Expected> YAML = Dumper.dump(); if (!YAML) return YAML.takeError(); diff --git a/tools/yaml2obj/yaml2macho.cpp b/tools/yaml2obj/yaml2macho.cpp index 8437475a411..ed243a2cdd9 100644 --- a/tools/yaml2obj/yaml2macho.cpp +++ b/tools/yaml2obj/yaml2macho.cpp @@ -40,8 +40,9 @@ public: private: Error writeHeader(raw_ostream &OS); + Error writeLoadCommands(raw_ostream &OS); - MachOYAML::Object Obj; + MachOYAML::Object &Obj; bool is64Bit; union { @@ -53,6 +54,8 @@ private: Error MachOWriter::writeMachO(raw_ostream &OS) { if (auto Err = writeHeader(OS)) return Err; + if (auto Err = writeLoadCommands(OS)) + return Err; return Error::success(); } @@ -66,15 +69,32 @@ Error MachOWriter::writeHeader(raw_ostream &OS) { Header.flags = Obj.Header.flags; Header64.reserved = Obj.Header.reserved; - if (is64Bit) { + if (is64Bit) OS.write((const char *)&Header64, sizeof(MachO::mach_header_64)); - } else OS.write((const char *)&Header, sizeof(MachO::mach_header)); return Error::success(); } +Error MachOWriter::writeLoadCommands(raw_ostream &OS) { + for (auto &LC : Obj.LoadCommands) { + MachO::load_command LCTemp; + LCTemp.cmd = LC->cmd; + LCTemp.cmdsize = LC->cmdsize; + OS.write(reinterpret_cast(&LCTemp), + sizeof(MachO::load_command)); + auto remaining_size = LC->cmdsize - sizeof(MachO::load_command); + if (remaining_size > 0) { + // TODO: Replace all this once the load command data is present in yaml. + std::vector fill_data; + fill_data.insert(fill_data.begin(), remaining_size, 0); + OS.write(fill_data.data(), remaining_size); + } + } + return Error::success(); +} + } // end anonymous namespace int yaml2macho(yaml::Input &YIn, raw_ostream &Out) { -- 2.11.0