Flattened package hierarchy
This commit is contained in:
60
src/macho/Constants.go
Normal file
60
src/macho/Constants.go
Normal file
@ -0,0 +1,60 @@
|
||||
package macho
|
||||
|
||||
type CPU uint32
|
||||
|
||||
const (
|
||||
CPU_X86 CPU = 7
|
||||
CPU_X86_64 CPU = CPU_X86 | 0x01000000
|
||||
CPU_ARM CPU = 12
|
||||
CPU_ARM_64 CPU = CPU_ARM | 0x01000000
|
||||
)
|
||||
|
||||
type Prot uint32
|
||||
|
||||
const (
|
||||
ProtReadable Prot = 0x1
|
||||
ProtWritable Prot = 0x2
|
||||
ProtExecutable Prot = 0x4
|
||||
)
|
||||
|
||||
type HeaderFlags uint32
|
||||
|
||||
const (
|
||||
FlagNoUndefs HeaderFlags = 0x1
|
||||
FlagIncrLink HeaderFlags = 0x2
|
||||
FlagDyldLink HeaderFlags = 0x4
|
||||
FlagBindAtLoad HeaderFlags = 0x8
|
||||
FlagPrebound HeaderFlags = 0x10
|
||||
FlagSplitSegs HeaderFlags = 0x20
|
||||
FlagLazyInit HeaderFlags = 0x40
|
||||
FlagTwoLevel HeaderFlags = 0x80
|
||||
FlagForceFlat HeaderFlags = 0x100
|
||||
FlagNoMultiDefs HeaderFlags = 0x200
|
||||
FlagNoFixPrebinding HeaderFlags = 0x400
|
||||
FlagPrebindable HeaderFlags = 0x800
|
||||
FlagAllModsBound HeaderFlags = 0x1000
|
||||
FlagSubsectionsViaSymbols HeaderFlags = 0x2000
|
||||
FlagCanonical HeaderFlags = 0x4000
|
||||
FlagWeakDefines HeaderFlags = 0x8000
|
||||
FlagBindsToWeak HeaderFlags = 0x10000
|
||||
FlagAllowStackExecution HeaderFlags = 0x20000
|
||||
FlagRootSafe HeaderFlags = 0x40000
|
||||
FlagSetuidSafe HeaderFlags = 0x80000
|
||||
FlagNoReexportedDylibs HeaderFlags = 0x100000
|
||||
FlagPIE HeaderFlags = 0x200000
|
||||
FlagDeadStrippableDylib HeaderFlags = 0x400000
|
||||
FlagHasTLVDescriptors HeaderFlags = 0x800000
|
||||
FlagNoHeapExecution HeaderFlags = 0x1000000
|
||||
FlagAppExtensionSafe HeaderFlags = 0x2000000
|
||||
)
|
||||
|
||||
type HeaderType uint32
|
||||
|
||||
const (
|
||||
TypeObject HeaderType = 0x1
|
||||
TypeExecute HeaderType = 0x2
|
||||
TypeCore HeaderType = 0x4
|
||||
TypeDylib HeaderType = 0x6
|
||||
TypeBundle HeaderType = 0x8
|
||||
TypeDsym HeaderType = 0xA
|
||||
)
|
15
src/macho/Header.go
Normal file
15
src/macho/Header.go
Normal file
@ -0,0 +1,15 @@
|
||||
package macho
|
||||
|
||||
const HeaderSize = 32
|
||||
|
||||
// Header contains general information.
|
||||
type Header struct {
|
||||
Magic uint32
|
||||
Architecture CPU
|
||||
MicroArchitecture uint32
|
||||
Type HeaderType
|
||||
NumCommands uint32
|
||||
SizeCommands uint32
|
||||
Flags HeaderFlags
|
||||
Reserved uint32
|
||||
}
|
34
src/macho/LoadCommand.go
Normal file
34
src/macho/LoadCommand.go
Normal file
@ -0,0 +1,34 @@
|
||||
package macho
|
||||
|
||||
type LoadCommand uint32
|
||||
|
||||
const (
|
||||
LcSegment LoadCommand = 0x1
|
||||
LcSymtab LoadCommand = 0x2
|
||||
LcThread LoadCommand = 0x4
|
||||
LcUnixthread LoadCommand = 0x5
|
||||
LcDysymtab LoadCommand = 0xB
|
||||
LcDylib LoadCommand = 0xC
|
||||
LcIdDylib LoadCommand = 0xD
|
||||
LcLoadDylinker LoadCommand = 0xE
|
||||
LcIdDylinker LoadCommand = 0xF
|
||||
LcSegment64 LoadCommand = 0x19
|
||||
LcUuid LoadCommand = 0x1B
|
||||
LcCodeSignature LoadCommand = 0x1D
|
||||
LcSegmentSplitInfo LoadCommand = 0x1E
|
||||
LcRpath LoadCommand = 0x8000001C
|
||||
LcEncryptionInfo LoadCommand = 0x21
|
||||
LcDyldInfo LoadCommand = 0x22
|
||||
LcDyldInfoOnly LoadCommand = 0x80000022
|
||||
LcVersionMinMacosx LoadCommand = 0x24
|
||||
LcVersionMinIphoneos LoadCommand = 0x25
|
||||
LcFunctionStarts LoadCommand = 0x26
|
||||
LcDyldEnvironment LoadCommand = 0x27
|
||||
LcMain LoadCommand = 0x80000028
|
||||
LcDataInCode LoadCommand = 0x29
|
||||
LcSourceVersion LoadCommand = 0x2A
|
||||
LcDylibCodeSignDrs LoadCommand = 0x2B
|
||||
LcEncryptionInfo64 LoadCommand = 0x2C
|
||||
LcVersionMinTvos LoadCommand = 0x2F
|
||||
LcVersionMinWatchos LoadCommand = 0x30
|
||||
)
|
124
src/macho/MachO.go
Normal file
124
src/macho/MachO.go
Normal file
@ -0,0 +1,124 @@
|
||||
package macho
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/config"
|
||||
"git.akyoto.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.Writer, code []byte, data []byte) {
|
||||
const (
|
||||
SizeCommands = Segment64Size*3 + ThreadSize
|
||||
HeaderEnd = HeaderSize + SizeCommands
|
||||
)
|
||||
|
||||
var (
|
||||
codeStart, codePadding = exe.Align(HeaderEnd, config.Align)
|
||||
dataStart, dataPadding = exe.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,
|
||||
config.BaseAddress + config.CodeOffset, 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}, int(codePadding)))
|
||||
writer.Write(code)
|
||||
writer.Write(bytes.Repeat([]byte{0x00}, int(dataPadding)))
|
||||
writer.Write(data)
|
||||
}
|
12
src/macho/MachO_test.go
Normal file
12
src/macho/MachO_test.go
Normal file
@ -0,0 +1,12 @@
|
||||
package macho_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/macho"
|
||||
)
|
||||
|
||||
func TestWrite(t *testing.T) {
|
||||
macho.Write(io.Discard, nil, nil)
|
||||
}
|
18
src/macho/Segment64.go
Normal file
18
src/macho/Segment64.go
Normal file
@ -0,0 +1,18 @@
|
||||
package macho
|
||||
|
||||
const Segment64Size = 72
|
||||
|
||||
// Segment64 is a segment load command.
|
||||
type Segment64 struct {
|
||||
LoadCommand
|
||||
Length uint32
|
||||
Name [16]byte
|
||||
Address uint64
|
||||
SizeInMemory uint64
|
||||
Offset uint64
|
||||
SizeInFile uint64
|
||||
MaxProt Prot
|
||||
InitProt Prot
|
||||
NumSections uint32
|
||||
Flag uint32
|
||||
}
|
11
src/macho/Thread.go
Normal file
11
src/macho/Thread.go
Normal file
@ -0,0 +1,11 @@
|
||||
package macho
|
||||
|
||||
const ThreadSize = 184
|
||||
|
||||
// Thread is a thread state load command.
|
||||
type Thread struct {
|
||||
LoadCommand
|
||||
Len uint32
|
||||
Type uint32
|
||||
Data [43]uint32
|
||||
}
|
16
src/macho/macho.md
Normal file
16
src/macho/macho.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Mach-O
|
||||
|
||||
## Notes
|
||||
|
||||
MacOS is the only operating system that requires loading the headers
|
||||
explicitly with both readable and executable permissions.
|
||||
|
||||
## Loader
|
||||
|
||||
https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h
|
||||
|
||||
## Links
|
||||
|
||||
- https://en.wikipedia.org/wiki/Mach-O
|
||||
- https://github.com/aidansteele/osx-abi-macho-file-format-reference
|
||||
- https://stackoverflow.com/questions/39863112/what-is-required-for-a-mach-o-executable-to-load
|
Reference in New Issue
Block a user