package macho import ( "bytes" "encoding/binary" "io" "git.urbach.dev/cli/q/src/config" "git.urbach.dev/cli/q/src/exe" ) 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, codeBytes []byte, dataBytes []byte) { sections := exe.MakeSections(HeaderEnd, codeBytes, dataBytes) code := sections[0] data := sections[1] arch, microArch := cpu() m := &MachO{ Header: Header{ Magic: 0xFEEDFACF, Architecture: arch, MicroArchitecture: microArch, 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(code.MemoryOffset + len(code.Bytes)), Offset: 0, SizeInFile: uint64(code.FileOffset + len(code.Bytes)), 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 + data.MemoryOffset), SizeInMemory: uint64(len(data.Bytes)), Offset: uint64(data.FileOffset), SizeInFile: uint64(len(data.Bytes)), 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 + code.MemoryOffset), 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}, code.Padding)) writer.Write(code.Bytes) writer.Write(bytes.Repeat([]byte{0x00}, data.Padding)) writer.Write(data.Bytes) }