Added macho package
All checks were successful
/ test (push) Successful in 15s

This commit is contained in:
Eduard Urbach 2025-06-30 20:31:07 +02:00
parent 436691ae40
commit dbc865ee67
Signed by: akyoto
GPG key ID: 49226B848C78F6C8
14 changed files with 317 additions and 0 deletions

119
src/macho/MachO.go Normal file
View file

@ -0,0 +1,119 @@
package macho
import (
"encoding/binary"
"io"
"git.urbach.dev/cli/q/src/build"
"git.urbach.dev/cli/q/src/exe"
)
// 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, b *build.Build, codeBytes []byte, dataBytes []byte) {
x := exe.New(HeaderEnd, b.FileAlign, b.MemoryAlign)
x.InitSections(codeBytes, dataBytes)
code := x.Sections[0]
data := x.Sections[1]
arch, microArch := Arch(b.Arch)
entryPoint := BaseAddress + code.MemoryOffset
m := &MachO{
Header: Header{
Magic: 0xFEEDFACF,
Architecture: arch,
MicroArchitecture: microArch,
Type: TypeExecute,
NumCommands: 4,
SizeCommands: SizeCommands,
Flags: FlagNoUndefs | FlagPIE | FlagNoHeapExecution,
Reserved: 0,
},
PageZero: Segment64{
LoadCommand: LcSegment64,
Length: 72,
Name: [16]byte{'_', '_', 'P', 'A', 'G', 'E', 'Z', 'E', 'R', 'O'},
Address: 0,
SizeInMemory: uint64(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: uint64(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(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(entryPoint), 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)
}