OSDN Git Service

[obj2yaml] [yaml2obj] Basic support for MachO::load_command
authorChris Bieneman <beanz@apple.com>
Fri, 13 May 2016 17:41:41 +0000 (17:41 +0000)
committerChris Bieneman <beanz@apple.com>
Fri, 13 May 2016 17:41:41 +0000 (17:41 +0000)
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
lib/ObjectYAML/MachOYAML.cpp
test/ObjectYAML/MachO/load_commands.yaml [new file with mode: 0644]
tools/obj2yaml/macho2yaml.cpp
tools/yaml2obj/yaml2macho.cpp

index 00d7ab2..bfc6dcb 100644 (file)
@@ -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<std::unique_ptr<LoadCommand>> LoadCommands;
 };
 
 } // namespace llvm::MachOYAML
+} // namespace llvm
 
+LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::MachOYAML::LoadCommand>)
+
+namespace llvm {
 namespace yaml {
 
 template <> struct MappingTraits<MachOYAML::FileHeader> {
@@ -49,6 +60,22 @@ template <> struct MappingTraits<MachOYAML::Object> {
   static void mapping(IO &IO, MachOYAML::Object &Object);
 };
 
+template <> struct MappingTraits<std::unique_ptr<MachOYAML::LoadCommand>> {
+  static void mapping(IO &IO,
+                      std::unique_ptr<MachOYAML::LoadCommand> &LoadCommand);
+};
+
+#define HANDLE_LOAD_COMMAND(LoadCommandName, LoadCommandValue)                 \
+  io.enumCase(value, #LoadCommandName, MachO::LoadCommandName);
+
+template <> struct ScalarEnumerationTraits<MachO::LoadCommandType> {
+  static void enumeration(IO &io, MachO::LoadCommandType &value) {
+#include "llvm/Support/MachO.def"
+  }
+};
+
+#undef HANDLE_LOAD_COMMAND
+
 } // namespace llvm::yaml
 
 } // namespace llvm
index d54140b..af80c16 100644 (file)
@@ -16,6 +16,8 @@
 
 namespace llvm {
 
+MachOYAML::LoadCommand::~LoadCommand() {}
+
 namespace yaml {
 
 void MappingTraits<MachOYAML::FileHeader>::mapping(
@@ -40,9 +42,18 @@ void MappingTraits<MachOYAML::Object>::mapping(IO &IO,
     IO.mapTag("!mach-o", true);
   }
   IO.mapRequired("FileHeader", Object.Header);
+  IO.mapOptional("LoadCommands", Object.LoadCommands);
   IO.setContext(nullptr);
 }
 
+void MappingTraits<std::unique_ptr<MachOYAML::LoadCommand>>::mapping(
+    IO &IO, std::unique_ptr<MachOYAML::LoadCommand> &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 (file)
index 0000000..246759d
--- /dev/null
@@ -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
index b787a3e..e71f467 100644 (file)
@@ -21,10 +21,10 @@ class MachODumper {
 
 public:
   MachODumper(const object::MachOObjectFile &O) : Obj(O) {}
-  Expected<std::unique_ptr<MachOYAML::Object> > dump();
+  Expected<std::unique_ptr<MachOYAML::Object>> dump();
 };
 
-Expected<std::unique_ptr<MachOYAML::Object> > MachODumper::dump() {
+Expected<std::unique_ptr<MachOYAML::Object>> MachODumper::dump() {
   auto Y = make_unique<MachOYAML::Object>();
   Y->Header.magic = Obj.getHeader().magic;
   Y->Header.cputype = Obj.getHeader().cputype;
@@ -34,12 +34,19 @@ Expected<std::unique_ptr<MachOYAML::Object> > 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<MachOYAML::LoadCommand>();
+    LC->cmd = static_cast<MachO::LoadCommandType>(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<std::unique_ptr<MachOYAML::Object> > YAML = Dumper.dump();
+  Expected<std::unique_ptr<MachOYAML::Object>> YAML = Dumper.dump();
   if (!YAML)
     return YAML.takeError();
 
index 8437475..ed243a2 100644 (file)
@@ -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<const char *>(&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<char> 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) {