[llvm] r270724 - [obj2yaml] [yaml2obj] MachO support for rebase opcodes

Chris Bieneman via llvm-commits llvm-commits at lists.llvm.org
Wed May 25 10:09:08 PDT 2016


Author: cbieneman
Date: Wed May 25 12:09:07 2016
New Revision: 270724

URL: http://llvm.org/viewvc/llvm-project?rev=270724&view=rev
Log:
[obj2yaml] [yaml2obj] MachO support for rebase opcodes

This is the first bit of support for MachO __LINKEDIT segment data.

Added:
    llvm/trunk/test/ObjectYAML/MachO/rebase_opcode.yaml
Modified:
    llvm/trunk/include/llvm/ObjectYAML/MachOYAML.h
    llvm/trunk/lib/ObjectYAML/MachOYAML.cpp
    llvm/trunk/tools/obj2yaml/macho2yaml.cpp
    llvm/trunk/tools/yaml2obj/yaml2macho.cpp

Modified: llvm/trunk/include/llvm/ObjectYAML/MachOYAML.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ObjectYAML/MachOYAML.h?rev=270724&r1=270723&r2=270724&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ObjectYAML/MachOYAML.h (original)
+++ llvm/trunk/include/llvm/ObjectYAML/MachOYAML.h Wed May 25 12:09:07 2016
@@ -57,10 +57,21 @@ struct LoadCommand {
   uint64_t ZeroPadBytes;
 };
 
+struct RebaseOpcode {
+  MachO::RebaseOpcode Opcode;
+  uint8_t Imm;
+  std::vector<yaml::Hex64> ExtraData;
+};
+
+struct LinkEditData {
+  std::vector<MachOYAML::RebaseOpcode> RebaseOpcodes;
+};
+
 struct Object {
   FileHeader Header;
   std::vector<LoadCommand> LoadCommands;
   std::vector<Section> Sections;
+  LinkEditData LinkEdit;
 };
 
 } // namespace llvm::MachOYAML
@@ -69,6 +80,8 @@ struct Object {
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::LoadCommand)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Section)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::Hex8)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::Hex64)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::RebaseOpcode)
 
 namespace llvm {
 namespace yaml {
@@ -85,6 +98,14 @@ template <> struct MappingTraits<MachOYA
   static void mapping(IO &IO, MachOYAML::LoadCommand &LoadCommand);
 };
 
+template <> struct MappingTraits<MachOYAML::LinkEditData> {
+  static void mapping(IO &IO, MachOYAML::LinkEditData &LinkEditData);
+};
+
+template <> struct MappingTraits<MachOYAML::RebaseOpcode> {
+  static void mapping(IO &IO, MachOYAML::RebaseOpcode &RebaseOpcode);
+};
+
 template <> struct MappingTraits<MachOYAML::Section> {
   static void mapping(IO &IO, MachOYAML::Section &Section);
 };
@@ -99,6 +120,24 @@ template <> struct ScalarEnumerationTrai
   }
 };
 
+#define ENUM_CASE(Enum)                                                 \
+  io.enumCase(value, #Enum, MachO::Enum);
+
+template <> struct ScalarEnumerationTraits<MachO::RebaseOpcode> {
+  static void enumeration(IO &io, MachO::RebaseOpcode &value) {
+  ENUM_CASE(REBASE_OPCODE_DONE)
+  ENUM_CASE(REBASE_OPCODE_SET_TYPE_IMM)
+  ENUM_CASE(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB)
+  ENUM_CASE(REBASE_OPCODE_ADD_ADDR_ULEB)
+  ENUM_CASE(REBASE_OPCODE_ADD_ADDR_IMM_SCALED)
+  ENUM_CASE(REBASE_OPCODE_DO_REBASE_IMM_TIMES)
+  ENUM_CASE(REBASE_OPCODE_DO_REBASE_ULEB_TIMES)
+  ENUM_CASE(REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
+  ENUM_CASE(REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB)
+  io.enumFallback<Hex8>(value);
+  }
+};
+
 // This trait is used for 16-byte chars in Mach structures used for strings
 typedef char char_16[16];
 

Modified: llvm/trunk/lib/ObjectYAML/MachOYAML.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ObjectYAML/MachOYAML.cpp?rev=270724&r1=270723&r2=270724&view=diff
==============================================================================
--- llvm/trunk/lib/ObjectYAML/MachOYAML.cpp (original)
+++ llvm/trunk/lib/ObjectYAML/MachOYAML.cpp Wed May 25 12:09:07 2016
@@ -93,9 +93,22 @@ void MappingTraits<MachOYAML::Object>::m
   }
   IO.mapRequired("FileHeader", Object.Header);
   IO.mapOptional("LoadCommands", Object.LoadCommands);
+  IO.mapOptional("LinkEditData", Object.LinkEdit);
   IO.setContext(nullptr);
 }
 
+void MappingTraits<MachOYAML::LinkEditData>::mapping(IO &IO,
+                                               MachOYAML::LinkEditData &LinkEditData) {
+  IO.mapOptional("RebaseOpcodes", LinkEditData.RebaseOpcodes);
+}
+
+void MappingTraits<MachOYAML::RebaseOpcode>::mapping(IO &IO,
+                                               MachOYAML::RebaseOpcode &RebaseOpcode) {
+  IO.mapRequired("Opcode", RebaseOpcode.Opcode);
+  IO.mapRequired("Imm", RebaseOpcode.Imm);
+  IO.mapOptional("ExtraData", RebaseOpcode.ExtraData);
+}
+
 template <typename StructType>
 void mapLoadCommandData(IO &IO, MachOYAML::LoadCommand &LoadCommand) {}
 

Added: llvm/trunk/test/ObjectYAML/MachO/rebase_opcode.yaml
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ObjectYAML/MachO/rebase_opcode.yaml?rev=270724&view=auto
==============================================================================
--- llvm/trunk/test/ObjectYAML/MachO/rebase_opcode.yaml (added)
+++ llvm/trunk/test/ObjectYAML/MachO/rebase_opcode.yaml Wed May 25 12:09:07 2016
@@ -0,0 +1,92 @@
+# RUN: yaml2obj -format=macho %s | obj2yaml | FileCheck %s
+
+--- !mach-o
+FileHeader:      
+  magic:           0xFEEDFACF
+  cputype:         0x01000007
+  cpusubtype:      0x80000003
+  filetype:        0x00000002
+  ncmds:           4
+  sizeofcmds:      224
+  flags:           0x00218085
+  reserved:        0x00000000
+LoadCommands:    
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         72
+    segname:         __LINKEDIT
+    vmaddr:          4294979584
+    vmsize:          4096
+    fileoff:         1024
+    filesize:        2508
+    maxprot:         7
+    initprot:        1
+    nsects:          0
+    flags:           0
+  - cmd:             LC_DYLD_INFO_ONLY
+    cmdsize:         48
+    rebase_off:      1024
+    rebase_size:     8
+    bind_off:        1032
+    bind_size:       96
+    weak_bind_off:   0
+    weak_bind_size:  0
+    lazy_bind_off:   1128
+    lazy_bind_size:  624
+    export_off:      1752
+    export_size:     48
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          1816
+    nsyms:           30
+    stroff:          2436
+    strsize:         1096
+  - cmd:             LC_DYSYMTAB
+    cmdsize:         80
+    ilocalsym:       0
+    nlocalsym:       9
+    iextdefsym:      9
+    nextdefsym:      2
+    iundefsym:       11
+    nundefsym:       19
+    tocoff:          0
+    ntoc:            0
+    modtaboff:       0
+    nmodtab:         0
+    extrefsymoff:    0
+    nextrefsyms:     0
+    indirectsymoff:  2296
+    nindirectsyms:   35
+    extreloff:       0
+    nextrel:         0
+    locreloff:       0
+    nlocrel:         0
+LinkEditData:    
+  RebaseOpcodes:   
+    - Opcode:          REBASE_OPCODE_SET_TYPE_IMM
+      Imm:             1
+    - Opcode:          REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+      Imm:             2
+      ExtraData:       
+        - 0x0000000000000028
+    - Opcode:          REBASE_OPCODE_DO_REBASE_ULEB_TIMES
+      Imm:             0
+      ExtraData:       
+        - 0x000000000000000F
+    - Opcode:          REBASE_OPCODE_DONE
+      Imm:             0
+...
+
+#CHECK: LinkEditData:    
+#CHECK:   RebaseOpcodes:   
+#CHECK:     - Opcode:          REBASE_OPCODE_SET_TYPE_IMM
+#CHECK:       Imm:             1
+#CHECK:     - Opcode:          REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+#CHECK:       Imm:             2
+#CHECK:       ExtraData:       
+#CHECK:         - 0x0000000000000028
+#CHECK:     - Opcode:          REBASE_OPCODE_DO_REBASE_ULEB_TIMES
+#CHECK:       Imm:             0
+#CHECK:       ExtraData:       
+#CHECK:         - 0x000000000000000F
+#CHECK:     - Opcode:          REBASE_OPCODE_DONE
+#CHECK:       Imm:             0

Modified: llvm/trunk/tools/obj2yaml/macho2yaml.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/obj2yaml/macho2yaml.cpp?rev=270724&r1=270723&r2=270724&view=diff
==============================================================================
--- llvm/trunk/tools/obj2yaml/macho2yaml.cpp (original)
+++ llvm/trunk/tools/obj2yaml/macho2yaml.cpp Wed May 25 12:09:07 2016
@@ -12,6 +12,7 @@
 #include "llvm/Object/MachOUniversal.h"
 #include "llvm/ObjectYAML/MachOYAML.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/LEB128.h"
 
 #include <string.h> // for memcpy
 
@@ -25,6 +26,9 @@ class MachODumper {
       const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd);
 
   const object::MachOObjectFile &Obj;
+  void dumpHeader(std::unique_ptr<MachOYAML::Object> &Y);
+  void dumpLoadCommands(std::unique_ptr<MachOYAML::Object> &Y);
+  void dumpLinkEdit(std::unique_ptr<MachOYAML::Object> &Y);
 
 public:
   MachODumper(const object::MachOObjectFile &O) : Obj(O) {}
@@ -144,6 +148,13 @@ const char *MachODumper::processLoadComm
 
 Expected<std::unique_ptr<MachOYAML::Object>> MachODumper::dump() {
   auto Y = make_unique<MachOYAML::Object>();
+  dumpHeader(Y);
+  dumpLoadCommands(Y);
+  dumpLinkEdit(Y);
+  return std::move(Y);
+}
+
+void MachODumper::dumpHeader(std::unique_ptr<MachOYAML::Object> &Y) {
   Y->Header.magic = Obj.getHeader().magic;
   Y->Header.cputype = Obj.getHeader().cputype;
   Y->Header.cpusubtype = Obj.getHeader().cpusubtype;
@@ -152,7 +163,9 @@ Expected<std::unique_ptr<MachOYAML::Obje
   Y->Header.sizeofcmds = Obj.getHeader().sizeofcmds;
   Y->Header.flags = Obj.getHeader().flags;
   Y->Header.reserved = 0;
+}
 
+void MachODumper::dumpLoadCommands(std::unique_ptr<MachOYAML::Object> &Y) {
   for (auto LoadCmd : Obj.load_commands()) {
     MachOYAML::LoadCommand LC;
     const char *EndPtr = LoadCmd.Ptr;
@@ -176,8 +189,47 @@ Expected<std::unique_ptr<MachOYAML::Obje
     LC.ZeroPadBytes = RemainingBytes;
     Y->LoadCommands.push_back(std::move(LC));
   }
+}
 
-  return std::move(Y);
+void MachODumper::dumpLinkEdit(std::unique_ptr<MachOYAML::Object> &Y) {
+  MachOYAML::LinkEditData &LEData = Y->LinkEdit;
+
+  auto RebaseOpcodes = Obj.getDyldInfoRebaseOpcodes();
+  for (auto OpCode = RebaseOpcodes.begin(); OpCode != RebaseOpcodes.end();
+       ++OpCode) {
+    MachOYAML::RebaseOpcode RebaseOp;
+    RebaseOp.Opcode =
+        static_cast<MachO::RebaseOpcode>(*OpCode & MachO::REBASE_OPCODE_MASK);
+    RebaseOp.Imm = *OpCode & MachO::REBASE_IMMEDIATE_MASK;
+
+    unsigned Count;
+    uint64_t ULEB = 0;
+
+    switch (RebaseOp.Opcode) {
+    case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+
+      ULEB = decodeULEB128(OpCode + 1, &Count);
+      RebaseOp.ExtraData.push_back(ULEB);
+      OpCode += Count;
+    // Intentionally no break here -- This opcode has two ULEB values
+    case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+    case MachO::REBASE_OPCODE_ADD_ADDR_ULEB:
+    case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+    case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+
+      ULEB = decodeULEB128(OpCode + 1, &Count);
+      RebaseOp.ExtraData.push_back(ULEB);
+      OpCode += Count;
+      break;
+    default:
+      break;
+    }
+
+    LEData.RebaseOpcodes.push_back(RebaseOp);
+
+    if (RebaseOp.Opcode == MachO::REBASE_OPCODE_DONE)
+      break;
+  }
 }
 
 Error macho2yaml(raw_ostream &Out, const object::MachOObjectFile &Obj) {

Modified: llvm/trunk/tools/yaml2obj/yaml2macho.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/yaml2obj/yaml2macho.cpp?rev=270724&r1=270723&r2=270724&view=diff
==============================================================================
--- llvm/trunk/tools/yaml2obj/yaml2macho.cpp (original)
+++ llvm/trunk/tools/yaml2obj/yaml2macho.cpp Wed May 25 12:09:07 2016
@@ -15,10 +15,13 @@
 #include "yaml2obj.h"
 #include "llvm/ObjectYAML/MachOYAML.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/LEB128.h"
 #include "llvm/Support/MachO.h"
 #include "llvm/Support/YAMLTraits.h"
 #include "llvm/Support/raw_ostream.h"
 
+#include "llvm/Support/Format.h"
+
 using namespace llvm;
 
 namespace {
@@ -42,6 +45,9 @@ private:
   Error writeHeader(raw_ostream &OS);
   Error writeLoadCommands(raw_ostream &OS);
   Error writeSectionData(raw_ostream &OS);
+  Error writeLinkEditData(raw_ostream &OS);
+
+  void ZeroToOffset(raw_ostream &OS, size_t offset);
 
   MachOYAML::Object &Obj;
   bool is64Bit;
@@ -165,6 +171,12 @@ void Fill(raw_ostream &OS, size_t Size,
   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);
+}
+
 Error MachOWriter::writeLoadCommands(raw_ostream &OS) {
   for (auto &LC : Obj.LoadCommands) {
     size_t BytesWritten = 0;
@@ -212,39 +224,74 @@ Error MachOWriter::writeSectionData(raw_
     switch (LC.Data.load_command_data.cmd) {
     case MachO::LC_SEGMENT:
     case MachO::LC_SEGMENT_64:
+      auto currOffset = OS.tell() - fileStart;
+      auto segname = LC.Data.segment_command_data.segname;
       uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff
                                 : LC.Data.segment_command_data.fileoff;
 
-      // Zero Fill any data between the end of the last thing we wrote and the
-      // start of this section.
-      auto currOffset = OS.tell() - fileStart;
-      if (currOffset < segOff) {
-        ZeroFillBytes(OS, segOff - currOffset);
-      }
-
-      for (auto &Sec : LC.Sections) {
+      if (0 == strncmp(&segname[0], "__LINKEDIT", 16)) {
+        if (auto Err = writeLinkEditData(OS))
+          return Err;
+      } else {
         // Zero Fill any data between the end of the last thing we wrote and the
         // start of this section.
-        assert(OS.tell() - fileStart <= Sec.offset &&
-               "Wrote too much data somewhere, section offsets don't line up.");
-        currOffset = OS.tell() - fileStart;
-        if (currOffset < Sec.offset) {
-          ZeroFillBytes(OS, Sec.offset - currOffset);
+        if (currOffset < segOff) {
+          ZeroFillBytes(OS, segOff - currOffset);
         }
 
-        // Fills section data with 0xDEADBEEF
-        Fill(OS, Sec.size, 0xDEADBEEFu);
+        for (auto &Sec : LC.Sections) {
+          // Zero Fill any data between the end of the last thing we wrote and
+          // the
+          // start of this section.
+          assert(
+              OS.tell() - fileStart <= Sec.offset &&
+              "Wrote too much data somewhere, section offsets don't line up.");
+          currOffset = OS.tell() - fileStart;
+          if (currOffset < Sec.offset) {
+            ZeroFillBytes(OS, Sec.offset - currOffset);
+          }
+
+          // Fills 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;
-      currOffset = OS.tell() - fileStart;
-      if (currOffset < segOff + segSize) {
-        // Fills segment data not covered by a section with 0xBAADDA7A
-        Fill(OS, (segOff + segSize) - currOffset, 0xBAADDA7Au);
-      }
+      ZeroToOffset(OS, segOff + segSize);
+      break;
+    }
+  }
+  return Error::success();
+}
+
+Error MachOWriter::writeLinkEditData(raw_ostream &OS) {
+  MachOYAML::LinkEditData &LinkEdit = Obj.LinkEdit;
+  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;
+      break;
+    case MachO::LC_DYLD_INFO_ONLY:
+      DyldInfoOnlyCmd = &LC.Data.dyld_info_command_data;
       break;
     }
   }
+
+  ZeroToOffset(OS, DyldInfoOnlyCmd->rebase_off);
+
+  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);
+    }
+  }
+
+  // Fill to the end of the string table
+  ZeroToOffset(OS, SymtabCmd->stroff + SymtabCmd->strsize);
+
   return Error::success();
 }
 




More information about the llvm-commits mailing list