1187 lines
27 KiB
PHP
1187 lines
27 KiB
PHP
|
|
CPU_TYPE_ANY = -1
|
|
CPU_ARCH_ABI64 = 0x1000000
|
|
CPU_TYPE_VAX = 1
|
|
CPU_TYPE_ROMP = 2
|
|
CPU_TYPE_NS32032 = 4
|
|
CPU_TYPE_NS32332 = 5
|
|
CPU_TYPE_MC680x0 = 6
|
|
CPU_TYPE_I386 = 7
|
|
CPU_TYPE_X86_64 = CPU_TYPE_I386 or CPU_ARCH_ABI64
|
|
CPU_TYPE_MIPS = 8
|
|
CPU_TYPE_NS32532 = 9
|
|
CPU_TYPE_HPPA = 11
|
|
CPU_TYPE_ARM = 12
|
|
CPU_TYPE_MC88000 = 13
|
|
CPU_TYPE_SPARC = 14
|
|
CPU_TYPE_I860 = 15
|
|
CPU_TYPE_I860_LITTLE = 16
|
|
CPU_TYPE_RS6000 = 17
|
|
CPU_TYPE_MC98000 = 18
|
|
CPU_TYPE_POWERPC = 18
|
|
CPU_TYPE_POWERPC64 = CPU_TYPE_POWERPC or CPU_ARCH_ABI64
|
|
CPU_TYPE_VEO = 255
|
|
|
|
CPU_SUBTYPE_MASK = 0xff000000
|
|
CPU_SUBTYPE_LIB64 = 0x80000000
|
|
|
|
CPU_SUBTYPE_I386_ALL = 3
|
|
CPU_SUBTYPE_X86_64_ALL = CPU_SUBTYPE_I386_ALL
|
|
CPU_SUBTYPE_386 = 3
|
|
CPU_SUBTYPE_486 = 4
|
|
CPU_SUBTYPE_486SX = 4 + 128
|
|
CPU_SUBTYPE_586 = 5
|
|
CPU_SUBTYPE_PENT = 5 + 0 shl 4
|
|
CPU_SUBTYPE_PENTPRO = 6 + 1 shl 4
|
|
CPU_SUBTYPE_PENTII_M3 = 6 + 3 shl 4
|
|
CPU_SUBTYPE_PENTII_M5 = 6 + 5 shl 4
|
|
CPU_SUBTYPE_PENTIUM_4 = 10 + 0 shl 4
|
|
|
|
MH_OBJECT = 0x1
|
|
MH_EXECUTE = 0x2
|
|
MH_FVMLIB = 0x3
|
|
MH_CORE = 0x4
|
|
MH_PRELOAD = 0x5
|
|
MH_DYLIB = 0x6
|
|
MH_DYLINKER = 0x7
|
|
MH_BUNDLE = 0x8
|
|
MH_DYLIB_STUB = 0x9
|
|
MH_DSYM = 0xA
|
|
MH_KEXT_BUNDLE = 0xB
|
|
|
|
MH_NOUNDEFS = 0x1
|
|
MH_INCRLINK = 0x2
|
|
MH_DYLDLINK = 0x4
|
|
MH_BINDATLOAD = 0x8
|
|
MH_PREBOUND = 0x10
|
|
MH_SPLIT_SEGS = 0x20
|
|
MH_LAZY_INIT = 0x40
|
|
MH_TWOLEVEL = 0x80
|
|
MH_FORCE_FLAT = 0x100
|
|
MH_NOMULTIDEFS = 0x200
|
|
MH_NOFIXPREBINDING = 0x400
|
|
MH_PREBINDABLE = 0x800
|
|
MH_ALLMODSBOUND = 0x1000
|
|
MH_SUBSECTIONS_VIA_SYMBOLS = 0x2000
|
|
MH_CANONICAL = 0x4000
|
|
MH_WEAK_DEFINES = 0x8000
|
|
MH_BINDS_TO_WEAK = 0x10000
|
|
MH_ALLOW_STACK_EXECUTION = 0x20000
|
|
MH_ROOT_SAFE = 0x40000
|
|
MH_SETUID_SAFE = 0x80000
|
|
MH_NO_REEXPORTED_DYLIBS = 0x100000
|
|
MH_PIE = 0x200000
|
|
MH_DEAD_STRIPPABLE_DYLIB = 0x400000
|
|
MH_HAS_TLV_DESCRIPTORS = 0x800000
|
|
MH_NO_HEAP_EXECUTION = 0x1000000
|
|
MH_APP_EXTENSION_SAFE = 0x2000000
|
|
|
|
LC_REQ_DYLD = 0x80000000
|
|
LC_SEGMENT = 0x1
|
|
LC_SYMTAB = 0x2
|
|
LC_SYMSEG = 0x3
|
|
LC_THREAD = 0x4
|
|
LC_UNIXTHREAD = 0x5
|
|
LC_LOADFVMLIB = 0x6
|
|
LC_IDFVMLIB = 0x7
|
|
LC_IDENT = 0x8
|
|
LC_FVMFILE = 0x9
|
|
LC_PREPAGE = 0xa
|
|
LC_DYSYMTAB = 0xb
|
|
LC_LOAD_DYLIB = 0xc
|
|
LC_ID_DYLIB = 0xd
|
|
LC_LOAD_DYLINKER = 0xe
|
|
LC_ID_DYLINKER = 0xf
|
|
LC_PREBOUND_DYLIB = 0x10
|
|
LC_ROUTINES = 0x11
|
|
LC_SUB_FRAMEWORK = 0x12
|
|
LC_SUB_UMBRELLA = 0x13
|
|
LC_SUB_CLIENT = 0x14
|
|
LC_SUB_LIBRARY = 0x15
|
|
LC_TWOLEVEL_HINTS = 0x16
|
|
LC_PREBIND_CKSUM = 0x17
|
|
LC_LOAD_WEAK_DYLIB = 0x18
|
|
LC_SEGMENT_64 = 0x19
|
|
LC_ROUTINES_64 = 0x1a
|
|
LC_UUID = 0x1b
|
|
LC_RPATH = 0x1c + LC_REQ_DYLD
|
|
LC_CODE_SIGNATURE = 0x1d
|
|
LC_SEGMENT_SPLIT_INFO = 0x1e
|
|
LC_REEXPORT_DYLIB = 0x1f + LC_REQ_DYLD
|
|
LC_LAZY_LOAD_DYLIB = 0x20
|
|
LC_ENCRYPTION_INFO = 0x21
|
|
LC_DYLD_INFO = 0x22
|
|
LC_DYLD_INFO_ONLY = 0x22 + LC_REQ_DYLD
|
|
|
|
SG_HIGHVM = 0x1
|
|
SG_FVMLIB = 0x2
|
|
SG_NORELOC = 0x4
|
|
|
|
SECTION_TYPE = 0x000000ff
|
|
SECTION_ATTRIBUTES = 0xffffff00
|
|
|
|
S_REGULAR = 0x0
|
|
S_ZEROFILL = 0x1
|
|
S_CSTRING_LITERALS = 0x2
|
|
S_4BYTE_LITERALS = 0x3
|
|
S_8BYTE_LITERALS = 0x4
|
|
S_LITERAL_POINTERS = 0x5
|
|
S_NON_LAZY_SYMBOL_POINTERS = 0x6
|
|
S_LAZY_SYMBOL_POINTERS = 0x7
|
|
S_SYMBOL_STUBS = 0x8
|
|
S_MOD_INIT_FUNC_POINTERS = 0x9
|
|
S_MOD_TERM_FUNC_POINTERS = 0x0a
|
|
S_COALESCED = 0x0b
|
|
S_GB_ZEROFILL = 0x0c
|
|
S_INTERPOSING = 0x0d
|
|
S_16BYTE_LITERALS = 0x0e
|
|
S_DTRACE_DOF = 0x0f
|
|
S_LAZY_DYLIB_SYMBOL_POINTERS = 0x10
|
|
S_THREAD_LOCAL_REGULAR = 0x11
|
|
S_THREAD_LOCAL_ZEROFILL = 0x12
|
|
S_THREAD_LOCAL_VARIABLES = 0x13
|
|
S_THREAD_LOCAL_VARIABLE_POINTERS = 0x14
|
|
S_THREAD_LOCAL_INIT_FUNCTION_POINTERS = 0x15
|
|
|
|
SECTION_ATTRIBUTES_USR = 0xff000000
|
|
S_ATTR_PURE_INSTRUCTIONS = 0x80000000
|
|
S_ATTR_NO_TOC = 0x40000000
|
|
S_ATTR_STRIP_STATIC_SYMS = 0x20000000
|
|
S_ATTR_NO_DEAD_STRIP = 0x10000000
|
|
S_ATTR_LIVE_SUPPORT = 0x08000000
|
|
S_ATTR_SELF_MODIFYING_CODE = 0x04000000
|
|
S_ATTR_DEBUG = 0x02000000
|
|
|
|
SECTION_ATTRIBUTES_SYS = 0x00ffff00
|
|
S_ATTR_SOME_INSTRUCTIONS = 0x00000400
|
|
S_ATTR_EXT_RELOC = 0x00000200
|
|
S_ATTR_LOC_RELOC = 0x00000100
|
|
|
|
VM_PROT_NONE = 0x00
|
|
VM_PROT_READ = 0x01
|
|
VM_PROT_WRITE = 0x02
|
|
VM_PROT_EXECUTE = 0x04
|
|
VM_PROT_DEFAULT = VM_PROT_READ or VM_PROT_WRITE
|
|
VM_PROT_ALL = VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE
|
|
VM_PROT_NO_CHANGE = 0x08
|
|
VM_PROT_COPY = 0x10
|
|
VM_PROT_WANTS_COPY = 0x10
|
|
|
|
x86_THREAD_STATE32 = 1
|
|
x86_FLOAT_STATE32 = 2
|
|
x86_EXCEPTION_STATE32 = 3
|
|
x86_THREAD_STATE64 = 4
|
|
x86_FLOAT_STATE64 = 5
|
|
x86_EXCEPTION_STATE64 = 6
|
|
x86_THREAD_STATE = 7
|
|
x86_FLOAT_STATE = 8
|
|
x86_EXCEPTION_STATE = 9
|
|
x86_DEBUG_STATE32 = 10
|
|
x86_DEBUG_STATE64 = 11
|
|
x86_DEBUG_STATE = 12
|
|
THREAD_STATE_NONE = 13
|
|
|
|
N_STAB = 0xe0
|
|
N_PEXT = 0x10
|
|
N_TYPE = 0x0e
|
|
N_EXT = 0x01
|
|
N_UNDF = 0x0
|
|
N_ABS = 0x2
|
|
N_SECT = 0xe
|
|
N_PBUD = 0xc
|
|
N_INDR = 0xa
|
|
|
|
NO_SECT = 0
|
|
MAX_SECT = 255
|
|
|
|
REFERENCE_TYPE = 0xf
|
|
REFERENCE_FLAG_UNDEFINED_NON_LAZY = 0
|
|
REFERENCE_FLAG_UNDEFINED_LAZY = 1
|
|
REFERENCE_FLAG_DEFINED = 2
|
|
REFERENCE_FLAG_PRIVATE_DEFINED = 3
|
|
REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY = 4
|
|
REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY = 5
|
|
REFERENCED_DYNAMICALLY = 0x0010
|
|
|
|
GENERIC_RELOC_VANILLA = 0
|
|
GENERIC_RELOC_PAIR = 1
|
|
GENERIC_RELOC_SECTDIFF = 2
|
|
GENERIC_RELOC_PB_LA_PTR = 3
|
|
GENERIC_RELOC_LOCAL_SECTDIFF = 4
|
|
GENERIC_RELOC_TLV = 5
|
|
|
|
X86_64_RELOC_UNSIGNED = 0
|
|
X86_64_RELOC_SIGNED = 1
|
|
X86_64_RELOC_BRANCH = 2
|
|
X86_64_RELOC_GOT_LOAD = 3
|
|
X86_64_RELOC_GOT = 4
|
|
X86_64_RELOC_SUBTRACTOR = 5
|
|
X86_64_RELOC_SIGNED_1 = 6
|
|
X86_64_RELOC_SIGNED_2 = 7
|
|
X86_64_RELOC_SIGNED_4 = 8
|
|
X86_64_RELOC_TLV = 9
|
|
|
|
; Basic layer: command headers
|
|
|
|
MachO::
|
|
|
|
namespace MachO
|
|
|
|
if defined Settings.ProcessorType
|
|
CPUTYPE := Settings.ProcessorType
|
|
else
|
|
CPUTYPE := CPU_TYPE_I386
|
|
end if
|
|
|
|
if defined Settings.ProcessorSubtype
|
|
CPUSUBTYPE := Settings.ProcessorSubtype
|
|
else
|
|
if CPUTYPE and CPU_ARCH_ABI64
|
|
CPUSUBTYPE := CPU_SUBTYPE_I386_ALL + CPU_SUBTYPE_LIB64
|
|
else
|
|
CPUSUBTYPE := CPU_SUBTYPE_I386_ALL
|
|
end if
|
|
end if
|
|
|
|
if defined Settings.FileType
|
|
FILETYPE := Settings.FileType
|
|
else
|
|
FILETYPE := MH_EXECUTE
|
|
end if
|
|
|
|
if defined Settings.Flags
|
|
FLAGS := Settings.Flags
|
|
else if FILETYPE <> MH_OBJECT
|
|
FLAGS := MH_NOUNDEFS + MH_DYLDLINK
|
|
else
|
|
FLAGS := 0
|
|
end if
|
|
|
|
if defined Settings.SegmentAlignment
|
|
SEGMENT_ALIGNMENT := Settings.SegmentAlignment
|
|
else
|
|
SEGMENT_ALIGNMENT := 1000h
|
|
end if
|
|
|
|
if defined Settings.FileAlignment
|
|
FILE_ALIGNMENT := Settings.FileAlignment
|
|
else
|
|
FILE_ALIGNMENT := 1000h
|
|
end if
|
|
|
|
if defined Settings.HeaderPad
|
|
HEADER_PAD := Settings.HeaderPad
|
|
else
|
|
HEADER_PAD := 16
|
|
end if
|
|
|
|
if CPUTYPE and CPU_ARCH_ABI64
|
|
magic dd 0xFEEDFACF
|
|
else
|
|
magic dd 0xFEEDFACE
|
|
end if
|
|
cputype dd CPUTYPE
|
|
cpusubtype dd CPUSUBTYPE
|
|
filetype dd FILETYPE
|
|
ncmds dd NUMBER_OF_COMMANDS
|
|
sizeofcmds dd SIZE_OF_COMMANDS
|
|
flags dd FLAGS
|
|
if CPUTYPE and CPU_ARCH_ABI64
|
|
reserved dd ?
|
|
end if
|
|
|
|
COMMAND_NUMBER = 0
|
|
COMMAND_POSITION = $
|
|
|
|
commands db SIZE_OF_COMMANDS dup 0, HEADER_PAD dup ?
|
|
|
|
org $
|
|
|
|
macro command type
|
|
if MachO.COMMAND_POSITION > 0
|
|
virtual at MachO.COMMAND_POSITION
|
|
MachO.COMMAND_POSITION = 0
|
|
end if
|
|
match t, type
|
|
if MachO.COMMAND_NUMBER > 0
|
|
repeat 1, p:MachO.COMMAND_NUMBER
|
|
MachO.load#p.SIZE := $ - MachO.load#p.cmd
|
|
end repeat
|
|
end if
|
|
MachO.COMMAND_NUMBER = MachO.COMMAND_NUMBER + 1
|
|
MachO.COMMAND = $
|
|
repeat 1, n:MachO.COMMAND_NUMBER
|
|
namespace MachO.load#n
|
|
cmd dd t
|
|
cmdsize dd SIZE
|
|
end namespace
|
|
end repeat
|
|
end match
|
|
end macro
|
|
|
|
macro text
|
|
if MachO.COMMAND_POSITION = 0
|
|
MachO.COMMAND_POSITION = $
|
|
load MachO.COMMAND_DATA:$-$$ from $$
|
|
store MachO.COMMAND_DATA:$-$$ at MachO:$$
|
|
end virtual
|
|
end if
|
|
end macro
|
|
|
|
end namespace
|
|
|
|
calminstruction align? boundary,value:?
|
|
compute boundary, (boundary-1)-($+boundary-1) mod boundary
|
|
arrange value, =db boundary =dup value
|
|
assemble value
|
|
end calminstruction
|
|
|
|
postpone
|
|
MachO.text
|
|
namespace MachO
|
|
if COMMAND_NUMBER > 0
|
|
repeat 1, p:COMMAND_NUMBER
|
|
load#p.SIZE := COMMAND_POSITION - MachO.load#p.cmd
|
|
end repeat
|
|
end if
|
|
NUMBER_OF_COMMANDS := COMMAND_NUMBER
|
|
SIZE_OF_COMMANDS := COMMAND_POSITION - commands
|
|
end namespace
|
|
end postpone
|
|
|
|
; Intermediate layer: segments and sections
|
|
|
|
namespace MachO
|
|
|
|
if defined Settings.BaseAddress
|
|
|
|
VM_ADDRESS = Settings.BaseAddress
|
|
|
|
if CPUTYPE and CPU_ARCH_ABI64
|
|
MachO.command LC_SEGMENT_64
|
|
else
|
|
MachO.command LC_SEGMENT
|
|
end if
|
|
namespace MachO.segment1
|
|
segname emit 16: '__PAGEZERO'
|
|
if CPUTYPE and CPU_ARCH_ABI64
|
|
vmaddr dq 0
|
|
vmsize dq VM_ADDRESS
|
|
fileoff dq 0
|
|
filesize dq 0
|
|
else
|
|
vmaddr dd 0
|
|
vmsize dd VM_ADDRESS
|
|
fileoff dd 0
|
|
filesize dd 0
|
|
end if
|
|
maxprot dd 0
|
|
initprot dd 0
|
|
nsects dd 0
|
|
flags dd 0
|
|
end namespace
|
|
|
|
SEGMENT_NUMBER = 1
|
|
else
|
|
VM_ADDRESS = 0
|
|
SEGMENT_NUMBER = 0
|
|
end if
|
|
|
|
GLOBAL_SECTION_NUMBER = 0
|
|
TEXT_OFFSET = $%
|
|
|
|
end namespace
|
|
|
|
macro MachO.segment declaration
|
|
MachO.close_segment
|
|
|
|
local NAME,VMADDR,VMSIZE,FILEOFF,FILESIZE,MAXPROT,INITPROT,NSECTS
|
|
|
|
INITPROT = VM_PROT_NONE
|
|
MAXPROT = VM_PROT_ALL
|
|
match name attributes, declaration
|
|
NAME = name
|
|
local sequence
|
|
define sequence attributes:
|
|
while 1
|
|
match attribute tail, sequence
|
|
match =readable?, attribute
|
|
INITPROT = INITPROT or VM_PROT_READ
|
|
MAXPROT = MAXPROT or VM_PROT_READ
|
|
else match =notreadable?, attribute
|
|
INITPROT = INITPROT and not VM_PROT_READ
|
|
MAXPROT = MAXPROT and not VM_PROT_READ
|
|
else match =writeable?, attribute
|
|
INITPROT = INITPROT or VM_PROT_WRITE
|
|
MAXPROT = MAXPROT or VM_PROT_WRITE
|
|
else match =writable?, attribute
|
|
INITPROT = INITPROT or VM_PROT_WRITE
|
|
MAXPROT = MAXPROT or VM_PROT_WRITE
|
|
else match =notwriteable?, attribute
|
|
INITPROT = INITPROT and not VM_PROT_WRITE
|
|
MAXPROT = MAXPROT and not VM_PROT_WRITE
|
|
else match =notwritable?, attribute
|
|
INITPROT = INITPROT and not VM_PROT_WRITE
|
|
MAXPROT = MAXPROT and not VM_PROT_WRITE
|
|
else match =executable?, attribute
|
|
INITPROT = INITPROT or VM_PROT_EXECUTE
|
|
MAXPROT = MAXPROT or VM_PROT_EXECUTE
|
|
else match =notexecutable?, attribute
|
|
INITPROT = INITPROT and not VM_PROT_EXECUTE
|
|
MAXPROT = MAXPROT and not VM_PROT_EXECUTE
|
|
else
|
|
err 'unknown attribute "',`attribute,'"'
|
|
end match
|
|
redefine sequence tail
|
|
else
|
|
break
|
|
end match
|
|
end while
|
|
else
|
|
NAME = definition
|
|
end match
|
|
if NAME eqtype '' & lengthof NAME > 16
|
|
err 'name too long'
|
|
end if
|
|
|
|
VMADDR := MachO.VM_ADDRESS
|
|
|
|
if $% = MachO.TEXT_OFFSET & FILESIZE > 0 & MachO.FILETYPE <> MH_OBJECT
|
|
MachO.FILE_OFFSET = 0
|
|
else
|
|
MachO.FILE_OFFSET = $%
|
|
end if
|
|
|
|
if FILESIZE
|
|
FILEOFF := MachO.FILE_OFFSET
|
|
else
|
|
FILEOFF := 0
|
|
end if
|
|
|
|
MachO.SEGMENT_NUMBER = MachO.SEGMENT_NUMBER + 1
|
|
if MachO.CPUTYPE and CPU_ARCH_ABI64
|
|
MachO.command LC_SEGMENT_64
|
|
else
|
|
MachO.command LC_SEGMENT
|
|
end if
|
|
repeat 1, s:MachO.SEGMENT_NUMBER
|
|
namespace MachO.segment#s
|
|
segname emit 16: NAME
|
|
if MachO.CPUTYPE and CPU_ARCH_ABI64
|
|
vmaddr dq VMADDR
|
|
vmsize dq VMSIZE
|
|
fileoff dq FILEOFF
|
|
filesize dq FILESIZE
|
|
else
|
|
vmaddr dd VMADDR
|
|
vmsize dd VMSIZE
|
|
fileoff dd FILEOFF
|
|
filesize dd FILESIZE
|
|
end if
|
|
maxprot dd MAXPROT
|
|
initprot dd INITPROT
|
|
nsects dd NSECTS
|
|
flags dd 0
|
|
end namespace
|
|
repeat NSECTS
|
|
namespace MachO.segment#s#_section#%
|
|
sectname emit 16: ?
|
|
segname emit 16: ?
|
|
if MachO.CPUTYPE and CPU_ARCH_ABI64
|
|
addr dq ?
|
|
size dq ?
|
|
else
|
|
addr dd ?
|
|
size dd ?
|
|
end if
|
|
offset dd ?
|
|
?align dd ?
|
|
reloff dd ?
|
|
nreloc dd ?
|
|
flags dd ?
|
|
reserved1 dd ?
|
|
reserved2 dd ?
|
|
if MachO.CPUTYPE and CPU_ARCH_ABI64
|
|
dd ?
|
|
end if
|
|
end namespace
|
|
end repeat
|
|
end repeat
|
|
|
|
macro MachO.close_segment
|
|
MachO.close_section
|
|
local OFFSET,NEXT,TOP,FILL
|
|
TOP = $%
|
|
NSECTS := MachO.SECTION_NUMBER
|
|
if MachO.FILE_OFFSET >= $%%
|
|
FILL = MachO.FILE_OFFSET
|
|
else
|
|
FILL = $%%
|
|
end if
|
|
repeat 1, s:MachO.SEGMENT_NUMBER
|
|
repeat NSECTS, n:2
|
|
if % = 1
|
|
load OFFSET from MachO:MachO.segment#s#_section#%.offset
|
|
else
|
|
OFFSET = NEXT
|
|
end if
|
|
if % < %%
|
|
load NEXT from MachO:MachO.segment#s#_section#n.offset
|
|
else
|
|
NEXT = TOP
|
|
end if
|
|
if OFFSET >= $%%
|
|
store S_ZEROFILL at MachO:MachO.segment#s#_section#%.flags
|
|
store 0 at MachO:MachO.segment#s#_section#%.size
|
|
else if OFFSET
|
|
FILL = NEXT
|
|
end if
|
|
end repeat
|
|
end repeat
|
|
FILESIZE := FILL - MachO.FILE_OFFSET
|
|
FILL = FILL - $%%
|
|
MachO.SECTION_BYPASS = 1
|
|
section MachO.VM_ADDRESS + FILESIZE - FILL
|
|
restore MachO.SECTION_BYPASS
|
|
db FILL dup 0
|
|
if FILESIZE
|
|
rb (MachO.FILE_ALIGNMENT-$%) and (MachO.FILE_ALIGNMENT-1)
|
|
end if
|
|
MachO.VM_ADDRESS = MachO.VM_ADDRESS + TOP - MachO.FILE_OFFSET
|
|
MachO.VM_ADDRESS = MachO.VM_ADDRESS + (MachO.SEGMENT_ALIGNMENT-MachO.VM_ADDRESS) and (MachO.SEGMENT_ALIGNMENT-1)
|
|
VMSIZE := MachO.VM_ADDRESS - VMADDR
|
|
purge MachO.close_segment
|
|
end macro
|
|
|
|
MachO.text
|
|
org VMADDR + $% - MachO.FILE_OFFSET
|
|
MachO.SECTION_NUMBER = 0
|
|
|
|
end macro
|
|
|
|
macro MachO.section declaration
|
|
if MachO.SEGMENT_NUMBER = 0
|
|
MachO.segment '__TEXT' readable writable executable
|
|
end if
|
|
MachO.close_section
|
|
|
|
local SECTNAME,SEGNAME,FLAGS,ALIGN,RESERVED1,RESERVED2
|
|
|
|
FLAGS = S_REGULAR
|
|
ALIGN = 0
|
|
RESERVED1 = 0
|
|
RESERVED2 = 0
|
|
|
|
local sequence
|
|
match segname:sectname tail, declaration:
|
|
SECTNAME = sectname
|
|
SEGNAME = segname
|
|
define sequence tail
|
|
else match name tail, declaration:
|
|
SECTNAME = name
|
|
repeat 1, s:MachO.SEGMENT_NUMBER
|
|
load SEGNAME from MachO:MachO.segment#s.segname
|
|
end repeat
|
|
define sequence tail
|
|
end match
|
|
|
|
while 1
|
|
match :, sequence
|
|
break
|
|
else match =align? boundary tail, sequence
|
|
ALIGN = bsf boundary
|
|
if bsf boundary <> bsr boundary
|
|
err 'invalid alignment value'
|
|
end if
|
|
redefine sequence tail
|
|
else match =flags?(value) tail, sequence
|
|
FLAGS = value
|
|
redefine sequence tail
|
|
else match =reserved1?(value) tail, sequence
|
|
RESERVED1 = value
|
|
redefine sequence tail
|
|
else match =reserved2?(value) tail, sequence
|
|
RESERVED2 = value
|
|
redefine sequence tail
|
|
else
|
|
err 'invalid arguments'
|
|
end match
|
|
end while
|
|
|
|
MachO.text
|
|
if ALIGN
|
|
align 1 shl ALIGN
|
|
end if
|
|
|
|
MachO.SECTION_ALIGN = 1 shl ALIGN
|
|
|
|
MachO.SECTION_NUMBER = MachO.SECTION_NUMBER + 1
|
|
MachO.GLOBAL_SECTION_NUMBER = MachO.GLOBAL_SECTION_NUMBER + 1
|
|
|
|
repeat 1, s:MachO.SEGMENT_NUMBER, t:MachO.SECTION_NUMBER
|
|
if ~ defined MachO.segment#s#_section#t.sectname
|
|
MachO.command
|
|
namespace MachO.segment#s#_section#t
|
|
sectname emit 16: ?
|
|
segname emit 16: ?
|
|
if MachO.CPUTYPE and CPU_ARCH_ABI64
|
|
addr dq ?
|
|
size dq ?
|
|
else
|
|
addr dd ?
|
|
size dd ?
|
|
end if
|
|
offset dd ?
|
|
?align dd ?
|
|
reloff dd ?
|
|
nreloc dd ?
|
|
flags dd ?
|
|
reserved1 dd ?
|
|
reserved2 dd ?
|
|
if MachO.CPUTYPE and CPU_ARCH_ABI64
|
|
dd ?
|
|
end if
|
|
end namespace
|
|
MachO.text
|
|
end if
|
|
store SECTNAME at MachO:MachO.segment#s#_section#t.sectname
|
|
store SEGNAME at MachO:MachO.segment#s#_section#t.segname
|
|
store $ at MachO:MachO.segment#s#_section#t.addr
|
|
store $% at MachO:MachO.segment#s#_section#t.offset
|
|
store FLAGS at MachO:MachO.segment#s#_section#t.flags
|
|
store ALIGN at MachO:MachO.segment#s#_section#t.align
|
|
store RESERVED1 at MachO:MachO.segment#s#_section#t.reserved1
|
|
store RESERVED2 at MachO:MachO.segment#s#_section#t.reserved2
|
|
end repeat
|
|
|
|
end macro
|
|
|
|
macro MachO.close_section
|
|
MachO.text
|
|
if MachO.SECTION_NUMBER
|
|
local SIZE
|
|
repeat 1, s:MachO.SEGMENT_NUMBER, t:MachO.SECTION_NUMBER
|
|
load OFFSET from MachO:MachO.segment#s#_section#t.offset
|
|
store $%-OFFSET at MachO:MachO.segment#s#_section#t.size
|
|
end repeat
|
|
end if
|
|
end macro
|
|
|
|
macro MachO.close_segment
|
|
end macro
|
|
|
|
postpone
|
|
MachO.close_segment
|
|
if MachO.FILETYPE <> MH_OBJECT & $%% < 1000h
|
|
store 0:byte at $-1 ; enforce minimum file size for OS X 10.10.5 and higher
|
|
end if
|
|
end postpone
|
|
|
|
macro segment? args&
|
|
MachO.segment args
|
|
end macro
|
|
|
|
macro section? args&
|
|
if defined MachO.SECTION_BYPASS
|
|
section args
|
|
else
|
|
MachO.section args
|
|
end if
|
|
end macro
|
|
|
|
macro entry? regs&
|
|
iterate reg, regs
|
|
match name:value, reg
|
|
MachO.thread.name? := value
|
|
else if MachO.CPUTYPE = CPU_TYPE_I386
|
|
MachO.thread.eip? := reg
|
|
else if MachO.CPUTYPE = CPU_TYPE_X86_64
|
|
MachO.thread.rip? := reg
|
|
end if
|
|
end iterate
|
|
MachO.command LC_UNIXTHREAD
|
|
if MachO.CPUTYPE = CPU_TYPE_I386
|
|
MachO.thread.flavor dd x86_THREAD_STATE32
|
|
iterate name, eax,ebx,ecx,edx,edi,esi,ebp,esp,ss,eflags,eip,cs,ds,es,fs,gs
|
|
if % = 1
|
|
MachO.thread.count dd %%
|
|
end if
|
|
if defined MachO.thread.name?
|
|
dd MachO.thread.name?
|
|
else
|
|
dd ?
|
|
end if
|
|
end iterate
|
|
else if MachO.CPUTYPE = CPU_TYPE_X86_64
|
|
MachO.thread.flavor dd x86_THREAD_STATE64
|
|
iterate name, rax,rbx,rcx,rdx,rdi,rsi,rbp,rsp,r8,r9,r10,r11,r12,r13,r14,r15,rip,rflags,cs,fs,gs
|
|
if % = 1
|
|
MachO.thread.count dd %%*2
|
|
end if
|
|
if defined MachO.thread.name?
|
|
dq MachO.thread.name?
|
|
else
|
|
dq ?
|
|
end if
|
|
end iterate
|
|
else
|
|
err 'CPU not supported'
|
|
end if
|
|
MachO.text
|
|
end macro
|
|
|
|
; Upper layer: symbol tables
|
|
|
|
define macroBuilder?
|
|
|
|
macro macroBuilder? declaration&
|
|
macro macroBuilder?.definition
|
|
esc macro declaration
|
|
end macro
|
|
end macro
|
|
|
|
macro macroBuilder?.line? content&
|
|
macro macroBuilder?.definition
|
|
macroBuilder?.definition
|
|
content
|
|
end macro
|
|
end macro
|
|
|
|
macro macroBuilder?.end?
|
|
macroBuilder?.definition
|
|
esc end macro
|
|
end macro
|
|
|
|
if MachO.FILETYPE <> MH_OBJECT
|
|
|
|
namespace MachO
|
|
NSYMS = 0
|
|
LIB_NUMBER = 0
|
|
end namespace
|
|
|
|
macro interpreter? path
|
|
MachO.command LC_LOAD_DYLINKER
|
|
namespace MachO.dylinker_command
|
|
lc_str dd dylinker-MachO.COMMAND
|
|
dylinker db path,0
|
|
if MachO.CPUTYPE and CPU_ARCH_ABI64
|
|
align 8
|
|
else
|
|
align 4
|
|
end if
|
|
end namespace
|
|
end macro
|
|
|
|
macro uses? lib&
|
|
MachO.LIB_NUMBER = MachO.LIB_NUMBER + 1
|
|
MachO.command LC_LOAD_DYLIB
|
|
repeat 1, l:MachO.LIB_NUMBER
|
|
namespace MachO.dylib#l#_command
|
|
lc_str dd dylib-MachO.COMMAND
|
|
timestamp dd 2
|
|
match path (a.b.c=,x.y.z), lib
|
|
current_version dd (x and 0FFFFh) shl 16 + y shl 8 + z
|
|
compatibility_version dd (a and 0FFFFh) shl 16 + b shl 8 + c
|
|
dylib db path,0
|
|
else
|
|
current_version dd 10000h
|
|
compatibility_version dd 10000h
|
|
dylib db lib,0
|
|
end match
|
|
if MachO.CPUTYPE and CPU_ARCH_ABI64
|
|
align 8
|
|
else
|
|
align 4
|
|
end if
|
|
end namespace
|
|
end repeat
|
|
end macro
|
|
|
|
macro import? definitions&
|
|
iterate <name,string>, definitions
|
|
MachO.NSYMS = MachO.NSYMS + 1
|
|
define MachO.nlist name
|
|
name.imported := 1
|
|
name.type := N_EXT
|
|
name.desc := REFERENCE_FLAG_UNDEFINED_NON_LAZY
|
|
define name.str string
|
|
end iterate
|
|
end macro
|
|
|
|
MachO.__TEXT = 0
|
|
MachO.__DATA = 0
|
|
|
|
macro segment? args&
|
|
MachO.segment args
|
|
if MachO.NSYMS
|
|
repeat 1, s:MachO.SEGMENT_NUMBER
|
|
load MachO.SEGNAME from MachO:MachO.segment#s.segname
|
|
end repeat
|
|
if ~MachO.__TEXT & MachO.SEGNAME = '__TEXT'
|
|
MachO.__TEXT = 1
|
|
MachO.__stubs
|
|
else if ~MachO.__DATA & MachO.SEGNAME = '__DATA'
|
|
MachO.__DATA = 1
|
|
MachO.__nl_symbol_ptr
|
|
end if
|
|
end if
|
|
end macro
|
|
|
|
postpone
|
|
if MachO.NSYMS
|
|
|
|
macroBuilder MachO.__stubs
|
|
|
|
macroBuilder.line section '__stubs' flags(S_SYMBOL_STUBS+S_ATTR_SOME_INSTRUCTIONS+S_ATTR_PURE_INSTRUCTIONS) reserved1(0) reserved2(MachO.JUMP_SIZE) align 16
|
|
|
|
irpv sym, MachO.nlist
|
|
if sym.imported
|
|
macroBuilder.line sym: jmp [sym.ptr]
|
|
if % = 1
|
|
macroBuilder.line MachO.JUMP_SIZE := $ - sym
|
|
end if
|
|
end if
|
|
end irpv
|
|
|
|
macroBuilder.end
|
|
|
|
macroBuilder MachO.__nl_symbol_ptr
|
|
|
|
if MachO.CPUTYPE and CPU_ARCH_ABI64
|
|
macroBuilder.line section '__nl_symbol_ptr' flags(S_NON_LAZY_SYMBOL_POINTERS) reserved1(0) align 8
|
|
else
|
|
macroBuilder.line section '__nl_symbol_ptr' flags(S_NON_LAZY_SYMBOL_POINTERS) reserved1(0) align 4
|
|
end if
|
|
|
|
irpv sym, MachO.nlist
|
|
if sym.imported
|
|
if MachO.CPUTYPE and CPU_ARCH_ABI64
|
|
macroBuilder.line sym.ptr dq 0
|
|
else
|
|
macroBuilder.line sym.ptr dd 0
|
|
end if
|
|
end if
|
|
end irpv
|
|
|
|
macroBuilder.end
|
|
|
|
if ~MachO.__TEXT
|
|
segment '__TEXT' readable executable
|
|
end if
|
|
|
|
if ~MachO.__DATA
|
|
segment '__DATA' readable writable
|
|
end if
|
|
|
|
segment '__LINKEDIT' readable
|
|
|
|
MachO.SYMOFF := $%
|
|
irpv sym, MachO.nlist
|
|
namespace MachO.nlist#%
|
|
n_strx dd sym.strx
|
|
n_type db sym.type
|
|
n_sect db 0
|
|
n_desc dw sym.desc
|
|
if MachO.CPUTYPE and CPU_ARCH_ABI64
|
|
n_value dq sym
|
|
else
|
|
n_value dd sym
|
|
end if
|
|
end namespace
|
|
end irpv
|
|
|
|
MachO.INDIRECTSYMOFF := $%
|
|
irpv sym, MachO.nlist
|
|
if sym.imported
|
|
dd %-1
|
|
end if
|
|
end irpv
|
|
|
|
MachO.STROFF := $%
|
|
db 20h,0
|
|
irpv sym, MachO.nlist
|
|
sym.strx := $% - MachO.STROFF
|
|
db string sym.str, 0
|
|
end irpv
|
|
MachO.STRSIZE := $% - MachO.STROFF
|
|
|
|
MachO.command LC_SYMTAB
|
|
namespace MachO.symtab_command
|
|
symoff dd SYMOFF
|
|
nsyms dd NSYMS
|
|
stroff dd STROFF
|
|
strsize dd STRSIZE
|
|
end namespace
|
|
|
|
MachO.command LC_DYSYMTAB
|
|
namespace MachO.dysymtab_command
|
|
ilocalsym dd 0
|
|
nlocalsym dd 0
|
|
iextdefsym dd 0
|
|
nextdefsym dd 0
|
|
iundefsym dd 0
|
|
nundefsym dd NSYMS
|
|
tocoff dd 0
|
|
ntoc dd 0
|
|
modtaboff dd 0
|
|
nmodtab dd 0
|
|
extrefsymoff dd 0
|
|
nextrefsyms dd 0
|
|
indirectsymoff dd INDIRECTSYMOFF
|
|
nindirectsyms dd NSYMS
|
|
extreloff dd 0
|
|
nextrel dd 0
|
|
locreloff dd 0
|
|
nlocrel dd 0
|
|
end namespace
|
|
|
|
end if
|
|
end postpone
|
|
|
|
else
|
|
|
|
namespace MachO
|
|
|
|
element MachO.section?
|
|
element MachO.symbol?
|
|
|
|
VM_ADDRESS = 0
|
|
|
|
define nlist null
|
|
null.value := 0
|
|
null.type := 0
|
|
null.sect := 0
|
|
null.desc := 0
|
|
null.str := ''
|
|
|
|
NSYMS = 1
|
|
NRELOC = 0
|
|
|
|
end namespace
|
|
|
|
segment 0 readable writable executable
|
|
|
|
macro MachO.section declaration
|
|
if MachO.SECTION_NUMBER
|
|
org 0 scaleof (1 metadataof $) + 0 scaleof $
|
|
end if
|
|
MachO.section declaration
|
|
local sym
|
|
element sym : MachO.GLOBAL_SECTION_NUMBER * MachO.section + $
|
|
org sym
|
|
MachO.SECTION_OFFSET = $%
|
|
MachO.SECTION_REL_INDEX = MachO.NRELOC
|
|
repeat 1, s:MachO.SEGMENT_NUMBER, t:MachO.SECTION_NUMBER
|
|
store MachO.RELOFF+MachO.SECTION_REL_INDEX*8 at MachO:MachO.segment#s#_section#t.reloff
|
|
end repeat
|
|
end macro
|
|
|
|
macro MachO.close_section
|
|
MachO.close_section
|
|
if MachO.SECTION_NUMBER
|
|
repeat 1, s:MachO.SEGMENT_NUMBER, t:MachO.SECTION_NUMBER
|
|
store MachO.NRELOC-MachO.SECTION_REL_INDEX at MachO:MachO.segment#s#_section#t.nreloc
|
|
end repeat
|
|
end if
|
|
end macro
|
|
|
|
macro public? declaration*
|
|
local name
|
|
define MachO.nlist name
|
|
match value =as? namestr, declaration
|
|
name = value
|
|
define name.str string namestr
|
|
else
|
|
name = declaration
|
|
define name.str `declaration
|
|
end match
|
|
if name relativeto 1 elementof name & 1 elementof (1 metadataof name) eq MachO.section
|
|
name.value := 0 scaleof (1 metadataof name) + 0 scaleof name
|
|
name.type := N_SECT + N_EXT
|
|
name.sect := 1 scaleof (1 metadataof name)
|
|
else
|
|
name.value := name
|
|
name.type := N_ABS
|
|
name.sect := 0
|
|
end if
|
|
name.desc := REFERENCE_FLAG_DEFINED
|
|
MachO.NSYMS = MachO.NSYMS + 1
|
|
end macro
|
|
|
|
macro extrn? declaration*
|
|
match namestr =as? sym, declaration
|
|
define MachO.nlist sym
|
|
define sym.str string namestr
|
|
else
|
|
define MachO.nlist declaration
|
|
define declaration.str `declaration
|
|
end match
|
|
match sym, MachO.nlist
|
|
element sym : MachO.NSYMS * MachO.symbol
|
|
sym.type := N_EXT
|
|
sym.sect := 0
|
|
sym.desc := 0
|
|
sym.value := 0
|
|
end match
|
|
MachO.NSYMS = MachO.NSYMS + 1
|
|
end macro
|
|
|
|
MachO.reloc.stack equ MachO.reloc
|
|
|
|
calminstruction dword? v*
|
|
compute v, v
|
|
check ~ v relativeto 0 & v relativeto 1 elementof v & (1 elementof (1 metadataof v) eq MachO.section | 1 elementof (1 metadataof v) eq MachO.symbol)
|
|
jyes dir
|
|
check ~ v relativeto 0 & (v + $) relativeto 1 elementof (v + $) & (1 elementof (1 metadataof (v + $)) eq MachO.section | 1 elementof (1 metadataof (v + $)) eq MachO.symbol)
|
|
jyes rel
|
|
emit 4, v
|
|
exit
|
|
|
|
local r, o
|
|
dir:
|
|
compute r, $% - MachO.SECTION_OFFSET + (1 scaleof (1 metadataof v)) shl 32 + 2 shl 57 + GENERIC_RELOC_VANILLA shl 60
|
|
check 1 elementof (1 metadataof v) eq MachO.symbol
|
|
jno dir_ready
|
|
compute r, r + 1 shl 59
|
|
dir_ready:
|
|
compute o, $%
|
|
emit 4, 0 scaleof (1 metadataof v) + 0 scaleof v
|
|
check $% > o
|
|
jyes record
|
|
exit
|
|
|
|
rel:
|
|
check MachO.CPUTYPE = CPU_TYPE_X86_64
|
|
jyes rel_x64
|
|
compute v, v + 0 scaleof (1 metadataof v) - 0 scaleof (1 metadataof $)
|
|
compute r, $% - MachO.SECTION_OFFSET + (1 scaleof (1 metadataof (v + $))) shl 32 + 1 shl 56 + 2 shl 57 + GENERIC_RELOC_VANILLA shl 60
|
|
jump rel_prepared
|
|
rel_x64:
|
|
check 1 elementof (1 metadataof (v + $)) eq MachO.symbol
|
|
jyes rel_x64_symbol
|
|
compute v, v + 0 scaleof (1 metadataof v) - 0 scaleof (1 metadataof $)
|
|
jump rel_x64_prepare
|
|
rel_x64_symbol:
|
|
compute v, v + $ + 4
|
|
rel_x64_prepare:
|
|
compute r, $% - MachO.SECTION_OFFSET + (1 scaleof (1 metadataof (v + $))) shl 32 + 1 shl 56 + 2 shl 57 + X86_64_RELOC_SIGNED_4 shl 60
|
|
rel_prepared:
|
|
check 1 elementof (1 metadataof (v + $)) eq MachO.symbol
|
|
jno rel_ready
|
|
compute r, r + 1 shl 59
|
|
rel_ready:
|
|
compute o, $%
|
|
emit 4, 0 scaleof v
|
|
check $% > o
|
|
jyes record
|
|
exit
|
|
|
|
record:
|
|
publish :MachO.reloc.stack, r
|
|
compute MachO.NRELOC, MachO.NRELOC + 1
|
|
|
|
end calminstruction
|
|
|
|
postpone
|
|
if MachO.NSYMS
|
|
|
|
MachO.close_section
|
|
macro MachO.close_section
|
|
MachO.text
|
|
end macro
|
|
|
|
rb (-$%) and 11b
|
|
|
|
MachO.RELOFF := $%
|
|
irpv rel, MachO.reloc
|
|
dq rel
|
|
end irpv
|
|
|
|
MachO.SYMOFF := $%
|
|
irpv sym, MachO.nlist
|
|
namespace MachO.nlist#%
|
|
n_strx dd sym.strx
|
|
n_type db sym.type
|
|
n_sect db sym.sect
|
|
n_desc dw sym.desc
|
|
if MachO.CPUTYPE and CPU_ARCH_ABI64
|
|
n_value dq sym.value
|
|
else
|
|
n_value dd sym.value
|
|
end if
|
|
end namespace
|
|
end irpv
|
|
|
|
MachO.STROFF := $%
|
|
irpv sym, MachO.nlist
|
|
sym.strx := $% - MachO.STROFF
|
|
db string sym.str, 0
|
|
end irpv
|
|
MachO.STRSIZE := $% - MachO.STROFF
|
|
|
|
MachO.command LC_SYMTAB
|
|
namespace MachO.symtab_command
|
|
symoff dd SYMOFF
|
|
nsyms dd NSYMS
|
|
stroff dd STROFF
|
|
strsize dd STRSIZE
|
|
end namespace
|
|
|
|
end if
|
|
end postpone
|
|
|
|
calminstruction align? boundary,value:?
|
|
check $ relativeto 0 | MachO.SECTION_ALIGN mod (boundary) = 0
|
|
jyes allowed
|
|
err 'section not aligned enough'
|
|
exit
|
|
allowed:
|
|
compute boundary, (boundary-1)-(0 scaleof $+boundary-1) mod boundary
|
|
arrange value, =db boundary =dup value
|
|
assemble value
|
|
end calminstruction
|
|
|
|
calminstruction dd? definitions&
|
|
local value, n
|
|
start:
|
|
match value=,definitions, definitions, ()
|
|
jyes recognize
|
|
match value, definitions
|
|
arrange definitions,
|
|
recognize:
|
|
match n =dup? value, value, ()
|
|
jyes duplicate
|
|
match ?, value
|
|
jyes reserve
|
|
call dword, value
|
|
next:
|
|
match , definitions
|
|
jno start
|
|
take , definitions
|
|
take definitions, definitions
|
|
jyes next
|
|
exit
|
|
reserve:
|
|
emit dword
|
|
jump next
|
|
duplicate:
|
|
match (value), value
|
|
stack:
|
|
check n
|
|
jno next
|
|
take definitions, value
|
|
arrange value, definitions
|
|
compute n, n - 1
|
|
jump stack
|
|
end calminstruction
|
|
|
|
calminstruction (label) dd? definitions&
|
|
local cmd
|
|
arrange cmd, =label label : =dword
|
|
assemble cmd
|
|
arrange cmd, =dd definitions
|
|
assemble cmd
|
|
end calminstruction
|
|
|
|
end if
|