122 lines
3 KiB
Go
122 lines
3 KiB
Go
package macho
|
|
|
|
import (
|
|
"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.WriteSeeker, 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.Seek(int64(code.Padding), io.SeekCurrent)
|
|
writer.Write(code.Bytes)
|
|
writer.Seek(int64(data.Padding), io.SeekCurrent)
|
|
writer.Write(data.Bytes)
|
|
}
|