forked from min-lang/min
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.ma
214 lines (192 loc) · 13 KB
/
main.ma
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# mach object file format for mac executables
# https://en.wikipedia.org/wiki/Mach-O
@File
0feedfacf # uint32_t magic, mach magic number identifier = MH_CIGAM_64 0xCFFAEDFE, Constant for the magic field of the mach_header_64 (64-bit architectures)
2 01000007 # cpu_type_t cputype = CPU_TYPE_X86_64 = CPU_TYPE_X86 | CPU_ARCH_ABI64
2 080000003 # cpu_subtype_t cpusubtype = CPU_SUBTYPE_X86_64_ALL | CPU_SUBTYPE_LIB64 0x80000000
2 2 # uint32_t filetype = MH_EXECUTE, demand paged executable file
2 9 # uint32_t ncmds, number of load commands HARDCODED - @Seg_zero @Seg_code @Thread @Seg_data @Dyld_info @Linker @Lib @Dysymtab (todo @Symtab)
2 Command,Command_end # uint32_t sizeofcmds, the size of all the load commands
2 085 # NOUNDEFS DYLDLINK TWOLEVEL # no PIE, otool -htdVflvIG /usr/bin/true | head
2 0 # uint32_t reserved
@Command
@Seg_zero # required by OSX 10.10 enforce_hard_pagezero = TRUE in xnu-2782.1.97/bsd/kern/mach_loader.c
2 019 # uint32_t cmd, LC_SEGMENT_64 0x19, 64-bit segment of this file to be mapped
2 Seg_zero,Seg_zero_end # uint32_t cmdsize, includes sizeof section_64 structs, 048
16 '__PAGEZERO' # char segname[16], segment name, /ref/xnu-2050.18.24/bsd/kern/mach_loader.c - vm_map_has_hard_pagezero(map, 0x1000) == FALSE
3 0 # uint64_t vmaddr, memory address of this segment
3 01000 # uint64_t vmsize, memory size of this segment. always one page = 01000
3 0 # uint64_t fileoff, file offset of this segment, page-aligned
3 0 # uint64_t filesize, amount to map from the file
2 0 # vm_prot_t maxprot, none
2 0 # vm_prot_t initprot, none
2 0 # uint32_t nsects, number of sections in segment
2 0 # uint32_t flags, flags
@Seg_zero_end
# since mac os x 10.12 sierra, /ref/dyld-433.5/src/ImageLoaderMachO.cpp checks dyld - malformed mach-o image: __LINKEDIT has fileoff==0 which overlaps mach_header
# LC_COMMAND index=1 must be __LINKEDIT for @Bind below: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x01, 0x00000000)
@Seg_link # required by OSX 10.10 enforce_hard_pagezero = TRUE in xnu-2782.1.97/bsd/kern/mach_loader.c
2 019 # uint32_t cmd, LC_SEGMENT_64 0x19, 64-bit segment of this file to be mapped
2 Seg_link,Seg_link_end # uint32_t cmdsize, includes sizeof section_64 structs, 048
16 '__LINKEDIT' # char segname[16], segment name, /ref/xnu-2050.18.24/bsd/kern/mach_loader.c - vm_map_has_hard_pagezero(map, 0x1000) == FALSE
3 Code_vmend # uint64_t vmaddr, memory address of this segment
3 01000 # uint64_t vmsize, memory size of this segment. always one page = 01000
3 Code_end # uint64_t fileoff, file offset of this segment, page-aligned
3 010 # uint64_t filesize, amount to map from the file. # 16 bytes per nlist_64 in /ref/xnu/EXTERNAL_HEADERS/mach-o/nlist.h
2 7 # vm_prot_t maxprot, none
2 7 # vm_prot_t initprot, none
2 0 # uint32_t nsects, number of sections in segment
2 0 # uint32_t flags, flags
@Seg_link_end
@Seg_code
2 019 # uint32_t cmd, LC_SEGMENT_64 0x19, 64-bit segment of this file to be mapped
2 Seg_code,Seg_code_end # uint32_t cmdsize, includes sizeof section_64 structs, 098
16 '__TEXT' # usually __TEXT, char segname[16], segment name
3 01000 # uint64_t vmaddr, memory address of this segment, after Seg_zero = 0x1000
3 File,Code_end # uint64_t vmsize, memory size of this segment - see Code_end in Asm.steps_binary_out
3 File # uint64_t fileoff, file offset of this segment, page-aligned, 0
3 File,Code_end # uint64_t filesize, amount to map from the file
2 7 # vm_prot_t maxprot, maximum VM protection = x_r, w for dldy updating @Dl_sym
2 7 # vm_prot_t initprot, initial VM protection = x_r
2 1 # uint32_t nsects, number of sections in segment
2 0 # uint32_t flags, flags
16 '' # usually __text, char sectname[16], name of this section
16 '' # usually __TEXT, char segname[16], segment this section goes in
3 0 # uint64_t addr, memory address of this section
3 0 # uint64_t size, size in bytes of this section
2 0 # uint32_t offset, file offset of this section
2 0 # uint32_t align, section alignment (power of 2)
2 0 # uint32_t reloff, file offset of relocation entries
2 0 # uint32_t nreloc, number of relocation entries
2 0 # optional, can be 0 - uint32_t flags, flags (section type and attributes), S_ATTR_PURE_INSTRUCTIONS
2 0 # uint32_t reserved1, reserved (for offset or index)
2 0 # uint32_t reserved2, reserved (for count or sizeof)
2 0 # uint32_t reserved3, reserved
@Seg_code_end
@Thread
2 5 # uint32_t cmd, LC_UNIXTHREAD, todo for Mountain Lion: LC_MAIN
2 Thread,Thread_end # uint32_t cmdsize, 184
2 4 # /ref/xnu/osfmk/mach/i386/thread_status.h x86_THREAD_STATE64
2 42 # sizeof _STRUCT_X86_THREAD_STATE64 / sizeof uint32_t
3 0 # # /ref/xnu/osfmk/mach/i386/_structs.h rax eax ax ah al
# dyld seems to ignore registers other than rip: /ref/dyld/src/ImageLoaderMachO.cpp void* entry = (void*)(registers->rip + fSlide);
3 0 # rbx
3 0 # rcx
3 0 # rdx
3 0 # rdi
3 0 # rsi
3 0 # rbp
3 0 # rsp
3 0 # r8
3 0 # r9
3 0 # r10
3 0 # r11
3 0 # r12
3 0 # r13
3 0 # r14
3 0 # r15
3 01000+Code # rip Code_vmaddr+Code
3 0 # rflags
3 0 # cs
3 0 # fs
3 0 # gs
@Thread_end
@Seg_data
2 019 # uint32_t cmd, LC_SEGMENT_64 0x19, 64-bit segment of this file to be mapped
2 Seg_data,Seg_data_end # uint32_t cmdsize, includes sizeof section_64 structs
16 '__DATA' # usually __data, char segname[16], segment name
3 Data_vmaddr # uint64_t vmaddr, memory address of this segment, 02000 in post-min.m
3 0400000000 # uint64_t vmsize, memory size of this segment, 16GB - FIXME - small data model allows only +/-2GB for mov reg/mem
3 Code_end # uint64_t fileoff, file offset of this segment
3 Data_size # uint64_t filesize, amount to map from the file
2 7 # vm_prot_t maxprot, maximum VM protection = xwr for Fun_1/Fun_2, else: Bus error: 10
2 7 # vm_prot_t initprot, initial VM protection = xwr
2 1 # uint32_t nsects, number of sections in segment
2 0 # uint32_t flags, flags
16 '' # usually __data, char sectname[16], name of this section
16 '' # usually __Data, char segname[16], segment this section goes in
3 0 # uint64_t addr, memory address of this section
3 0 # uint64_t size, size in bytes of this section, 1GB
2 0 # uint32_t offset, file offset of this section
2 0 # uint32_t align, section alignment (power of 2)
2 0 # uint32_t reloff, file offset of relocation entries
2 0 # uint32_t nreloc, number of relocation entries
2 0 # uint32_t flags, flags (section type and attributes), S_REGULAR
2 0 # uint32_t reserved1, reserved (for offset or index)
2 0 # uint32_t reserved2, reserved (for count or sizeof)
2 0 # uint32_t reserved3, reserved
@Seg_data_end
@Dyld_info
2 022 #define LC_DYLD_INFO 0x22 /* compressed dyld information */
2 Dyld_info,Dyld_info_end # cmdsize
2 0
2 0
2 Bind # bind_off relative to _LINKEDIT
2 Bind,Bind_end # bind_size
2 0
2 0
2 0
2 0
2 0
2 0
@Dyld_info_end
@Linker
2 0e # /ref/xnu/EXTERNAL_HEADERS/mach-o/loader.h #define LC_LOAD_DYLINKER 0xe /* load a dynamic linker */
2 Linker,Linker_end # uint32_t cmdsize, includes sizeof section_64 structs
2 Linker,Linker_name
@Linker_name
'/usr/lib/dyld'; 0
6 '' # otool -l min: objdump: 'min': truncated or malformed object (load command 6 cmdsize not a multiple of 8)
@Linker_end
# /usr/include/mach-o/loader.h: struct dylib
@Lib
2 0c # #define LC_LOAD_DYLIB 0xc /* load a dynamically linked shared library */
2 Lib,Lib_end # uint32_t cmdsize, includes sizeof section_64 structs, 048
2 Lib,Lib_name
2 0 # timestamp, time stamp 0 Wed Dec 31 16:00:02 1969
2 0 # current_version
2 0 # compatibility_version
@Lib_name
'/usr/lib/libSystem.B.dylib'; 0
5 ''
@Lib_end
# else, /ref/dyld-433.5/src/ImageLoaderMachO.cpp dyld - malformed mach-o image: missing LC_DYSYMTAB
@Dysymtab
2 0b # #define LC_DYSYMTAB 0xb /* dynamic link-edit symbol table info */
2 80
72 ''
@Dysymtab_end
# todo: else, otool -l min: objdump: 'min': truncated or malformed object (contains LC_DYSYMTAB load command without a LC_SYMTAB load command)
# /ref/xnu/EXTERNAL_HEADERS/mach-o/nlist.h
@Command_end
# @Bind before @Code or @Data since the latter two are appended outside this file. Use a fixed location for the vm
# address 0x1000 (0x00000000 of segment index 01 = Seg_code) for dlsym's function address. See Dl.sym.
@Bind
# $ dyldinfo -bind -opcodes min
# bind information:
# segment section address type addend dylib symbol
# __LINKEDIT ?? 0x000C0000 pointer 0 libSystem _dlsym
# no compressed rebase info
# binding opcodes:
# 0x0000 BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(1) dylib 1 = /usr/lib/libSystem.B.dylib
# 0x0001 BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x00, _dlsym)
# 0x0009 BIND_OPCODE_SET_TYPE_IMM(1) segment 1 = Seg_link
# 0x000A BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x01, 0x00000000)
# 0x000C BIND_OPCODE_DO_BIND()
# otool -l min | grep ' bind_off'
# bind_off 876
# tail -c +876 min | hexdump | head -1
# 0000000 00 11 40 5f 64 6c 73 79 6d 00 51 71 00 90 48 b8
0'11 40 5f 64 6c 73 79 6d 00 51 71 00 90'
@Bind_end
# http://x86-64.org/documentation/abi.pdf System V Application Binary Interface AMD64 Architecture Processor Supplement
# 3.4.1 Initial Stack and Register State - Stack State
# extern int main ( int argc , char *argv[ ] , char* envp[ ] );
# Figure 3.9: Initial Process Stack
@Code
mov a Data_vmend
mov a 0 a
add a 0 16 # 8 = Mem.last, 8 = Job.multi
push sp
call Main.main
# Asm.steps_binary_out appends the rest of @Code segment and the @Data segment.