github.com/chenzhuoyu/iasm@v0.9.1/obj/macho.go (about)

     1  package obj
     2  
     3  import (
     4      `encoding/binary`
     5      `io`
     6      `unsafe`
     7  )
     8  
     9  type MachOHeader struct {
    10      Magic      uint32
    11      CPUType    uint32
    12      CPUSubType uint32
    13      FileType   uint32
    14      CmdCount   uint32
    15      CmdSize    uint32
    16      Flags      uint32
    17      _          uint32
    18  }
    19  
    20  type SegmentCommand struct {
    21      Cmd          uint32
    22      Size         uint32
    23      Name         [16]byte
    24      VMAddr       uint64
    25      VMSize       uint64
    26      FileOffset   uint64
    27      FileSize     uint64
    28      MaxProtect   uint32
    29      InitProtect  uint32
    30      SectionCount uint32
    31      Flags        uint32
    32  }
    33  
    34  type SegmentSection struct {
    35      Name      [16]byte
    36      SegName   [16]byte
    37      Addr      uint64
    38      Size      uint64
    39      Offset    uint32
    40      Align     uint32
    41      RelOffset uint32
    42      RelCount  uint32
    43      Flags     uint32
    44      _         [3]uint32
    45  }
    46  
    47  type Registers struct {
    48      RAX    uint64
    49      RBX    uint64
    50      RCX    uint64
    51      RDX    uint64
    52      RDI    uint64
    53      RSI    uint64
    54      RBP    uint64
    55      RSP    uint64
    56      R8     uint64
    57      R9     uint64
    58      R10    uint64
    59      R11    uint64
    60      R12    uint64
    61      R13    uint64
    62      R14    uint64
    63      R15    uint64
    64      RIP    uint64
    65      RFLAGS uint64
    66      CS     uint64
    67      FS     uint64
    68      GS     uint64
    69  }
    70  
    71  type UnixThreadCommand struct {
    72      Cmd    uint32
    73      Size   uint32
    74      Flavor uint32
    75      Count  uint32
    76      Regs   Registers
    77  }
    78  
    79  const (
    80      _MH_MAGIC_64 = 0xfeedfacf
    81      _MH_EXECUTE  = 0x02
    82      _MH_NOUNDEFS = 0x01
    83  )
    84  
    85  const (
    86      _CPU_TYPE_I386  = 0x00000007
    87      _CPU_ARCH_ABI64 = 0x01000000
    88  )
    89  
    90  const (
    91      _CPU_SUBTYPE_LIB64    = 0x80000000
    92      _CPU_SUBTYPE_I386_ALL = 0x00000003
    93  )
    94  
    95  const (
    96      _LC_SEGMENT_64 = 0x19
    97      _LC_UNIXTHREAD = 0x05
    98  )
    99  
   100  const (
   101      _VM_PROT_READ    = 0x01
   102      _VM_PROT_WRITE   = 0x02
   103      _VM_PROT_EXECUTE = 0x04
   104  )
   105  
   106  const (
   107      _S_ATTR_SOME_INSTRUCTIONS = 0x00000400
   108      _S_ATTR_PURE_INSTRUCTIONS = 0x80000000
   109  )
   110  
   111  const (
   112      _x86_THREAD_STATE64          = 0x04
   113      _x86_EXCEPTION_STATE64_COUNT = 42
   114  )
   115  
   116  const (
   117      _MACHO_SIZE      = uint32(unsafe.Sizeof(MachOHeader{}))
   118      _SEGMENT_SIZE    = uint32(unsafe.Sizeof(SegmentCommand{}))
   119      _SECTION_SIZE    = uint32(unsafe.Sizeof(SegmentSection{}))
   120      _UNIXTHREAD_SIZE = uint32(unsafe.Sizeof(UnixThreadCommand{}))
   121  )
   122  
   123  const (
   124      _IMAGE_SIZE = 4096
   125      _IMAGE_BASE = 0x04000000
   126  )
   127  
   128  const (
   129      _HDR_SIZE  = _MACHO_SIZE + _SEGMENT_SIZE * 2 + _SECTION_SIZE + _UNIXTHREAD_SIZE
   130      _ZERO_SIZE = (_IMAGE_SIZE - _HDR_SIZE %_IMAGE_SIZE) % _IMAGE_SIZE
   131  )
   132  
   133  var (
   134      zeroBytes = [_ZERO_SIZE]byte{}
   135  )
   136  
   137  func assembleMachO(w io.Writer, code []byte, base uint64, entry uint64) error {
   138      var p0name [16]byte
   139      var txname [16]byte
   140      var tsname [16]byte
   141  
   142      /* segment names */
   143      copy(tsname[:], "__text")
   144      copy(txname[:], "__TEXT")
   145      copy(p0name[:], "__PAGEZERO")
   146  
   147      /* calculate size of code */
   148      clen := uint64(len(code))
   149      hlen := uint64(_HDR_SIZE + _ZERO_SIZE)
   150  
   151      /* Mach-O does not allow image base at zero */
   152      if base == 0 {
   153          base = _IMAGE_BASE
   154          entry += _IMAGE_BASE
   155      }
   156  
   157      /* Page-0 Segment */
   158      p0 := SegmentCommand {
   159          Cmd    : _LC_SEGMENT_64,
   160          Size   : _SEGMENT_SIZE,
   161          Name   : p0name,
   162          VMSize : base,
   163      }
   164  
   165      /* TEXT Segment */
   166      text := SegmentCommand {
   167          Cmd          : _LC_SEGMENT_64,
   168          Size         : _SEGMENT_SIZE + _SECTION_SIZE,
   169          Name         : txname,
   170          VMAddr       : base,
   171          VMSize       : hlen + clen,
   172          FileSize     : hlen + clen,
   173          MaxProtect   : _VM_PROT_READ | _VM_PROT_WRITE | _VM_PROT_EXECUTE,
   174          InitProtect  : _VM_PROT_READ | _VM_PROT_EXECUTE,
   175          SectionCount : 1,
   176      }
   177  
   178      /* __TEXT.__text section */
   179      tsec := SegmentSection {
   180          Name    : tsname,
   181          SegName : txname,
   182          Addr    : base + hlen,
   183          Size    : clen,
   184          Offset  : uint32(hlen),
   185          Flags   : _S_ATTR_SOME_INSTRUCTIONS | _S_ATTR_PURE_INSTRUCTIONS,
   186      }
   187  
   188      /* UNIX Thread Metadata */
   189      unix := UnixThreadCommand {
   190          Cmd    : _LC_UNIXTHREAD,
   191          Size   : _UNIXTHREAD_SIZE,
   192          Flavor : _x86_THREAD_STATE64,
   193          Count  : _x86_EXCEPTION_STATE64_COUNT,
   194          Regs   : Registers { RIP: hlen + entry },
   195      }
   196  
   197      /* Mach-O Header */
   198      macho := MachOHeader {
   199          Magic      : _MH_MAGIC_64,
   200          CPUType    : _CPU_ARCH_ABI64 | _CPU_TYPE_I386,
   201          CPUSubType : _CPU_SUBTYPE_LIB64 | _CPU_SUBTYPE_I386_ALL,
   202          FileType   : _MH_EXECUTE,
   203          CmdCount   : 3,
   204          CmdSize    : _SEGMENT_SIZE * 2 + _SECTION_SIZE + _UNIXTHREAD_SIZE,
   205          Flags      : _MH_NOUNDEFS,
   206      }
   207  
   208      /* write the headers */
   209      if err := binary.Write(w, binary.LittleEndian, &macho)     ; err != nil { return err }
   210      if err := binary.Write(w, binary.LittleEndian, &p0)        ; err != nil { return err }
   211      if err := binary.Write(w, binary.LittleEndian, &text)      ; err != nil { return err }
   212      if err := binary.Write(w, binary.LittleEndian, &tsec)      ; err != nil { return err }
   213      if err := binary.Write(w, binary.LittleEndian, &unix)      ; err != nil { return err }
   214      if err := binary.Write(w, binary.LittleEndian, &zeroBytes) ; err != nil { return err }
   215  
   216      /* write the code */
   217      if n, err := w.Write(code); err != nil {
   218          return err
   219      } else if n != len(code) {
   220          return io.ErrShortWrite
   221      } else {
   222          return nil
   223      }
   224  }