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 }