package macho import ( "bytes" "encoding/binary" "io" "git.akyoto.dev/cli/q/src/config" "git.akyoto.dev/cli/q/src/fs" ) const ( SizeCommands = Segment64Size*3 + ThreadSize HeaderEnd = HeaderSize + SizeCommands ) // MachO is the executable format used on MacOS. type MachO struct { Header PageZero Segment64 CodeHeader Segment64 DataHeader Segment64 UnixThread Thread } // Write writes the Mach-O format to the given writer. func Write(writer io.Writer, code []byte, data []byte) { var ( codeStart, codePadding = fs.Align(HeaderEnd, config.Align) dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align) ) m := &MachO{ Header: Header{ Magic: 0xFEEDFACF, Architecture: CPU_X86_64, MicroArchitecture: 3 | 0x80000000, Type: TypeExecute, NumCommands: 4, SizeCommands: SizeCommands, Flags: FlagNoUndefs | FlagNoHeapExecution, Reserved: 0, }, PageZero: Segment64{ LoadCommand: LcSegment64, Length: 72, Name: [16]byte{'_', '_', 'P', 'A', 'G', 'E', 'Z', 'E', 'R', 'O'}, Address: 0, SizeInMemory: config.BaseAddress, Offset: 0, SizeInFile: 0, NumSections: 0, Flag: 0, MaxProt: 0, InitProt: 0, }, CodeHeader: Segment64{ LoadCommand: LcSegment64, Length: Segment64Size, Name: [16]byte{'_', '_', 'T', 'E', 'X', 'T'}, Address: config.BaseAddress, SizeInMemory: uint64(codeStart + len(code)), Offset: 0, SizeInFile: uint64(codeStart + len(code)), NumSections: 0, Flag: 0, MaxProt: ProtReadable | ProtExecutable, InitProt: ProtReadable | ProtExecutable, }, DataHeader: Segment64{ LoadCommand: LcSegment64, Length: Segment64Size, Name: [16]byte{'_', '_', 'D', 'A', 'T', 'A'}, Address: uint64(config.BaseAddress + dataStart), SizeInMemory: uint64(len(data)), Offset: uint64(dataStart), SizeInFile: uint64(len(data)), NumSections: 0, Flag: 0, MaxProt: ProtReadable, InitProt: ProtReadable, }, UnixThread: Thread{ LoadCommand: LcUnixthread, Len: ThreadSize, Type: 0x4, Data: [43]uint32{ 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, uint32(config.BaseAddress + codeStart), 0, 0, 0, 0, 0, 0, 0, 0, 0, }, }, } binary.Write(writer, binary.LittleEndian, &m.Header) binary.Write(writer, binary.LittleEndian, &m.PageZero) binary.Write(writer, binary.LittleEndian, &m.CodeHeader) binary.Write(writer, binary.LittleEndian, &m.DataHeader) binary.Write(writer, binary.LittleEndian, &m.UnixThread) writer.Write(bytes.Repeat([]byte{0x00}, codePadding)) writer.Write(code) writer.Write(bytes.Repeat([]byte{0x00}, dataPadding)) writer.Write(data) }