1/* arm64-darwin.macho-entry.S -- iPhone program entry point & decompressor (Elf binary)
2*
3*  This file is part of the UPX executable compressor.
4*
5*  Copyright (C) 1996-2020 Markus Franz Xaver Johannes Oberhumer
6*  Copyright (C) 1996-2020 Laszlo Molnar
7*  Copyright (C) 2000-2020 John F. Reiser
8*  All Rights Reserved.
9*
10*  UPX and the UCL library are free software; you can redistribute them
11*  and/or modify them under the terms of the GNU General Public License as
12*  published by the Free Software Foundation; either version 2 of
13*  the License, or (at your option) any later version.
14*
15*  This program is distributed in the hope that it will be useful,
16*  but WITHOUT ANY WARRANTY; without even the implied warranty of
17*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*  GNU General Public License for more details.
19*
20*  You should have received a copy of the GNU General Public License
21*  along with this program; see the file COPYING.
22*  If not, write to the Free Software Foundation, Inc.,
23*  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24*
25*  Markus F.X.J. Oberhumer              Laszlo Molnar
26*  <markus@oberhumer.com>               <ezerotven+github@gmail.com>
27*
28*  John F. Reiser
29*  <jreiser@users.sourceforge.net>
30*/
31
32#define SIMULATE_ON_LINUX_EABI4 0
33
34#if SIMULATE_ON_LINUX_EABI4  /*{*/
35  #define LINUX_ARM_CACHEFLUSH 1  /* SIMULATE_ON_LINUX_EABI4 */
36  #define ARMEL_EABI4 1           /* SIMULATE_ON_LINUX_EABI4 */
37#else  /*}{ USUAL case */
38  #define DARWIN_ARM_CACHEFLUSH 1
39  #define ARMEL_DARWIN 1
40#endif  /*}*/
41
42#ifndef DEBUG  //{
43#define DEBUG 0
44#define TRACE(arg) /*empty*/
45#else  //}{
46#define TRACE(arg) \
47        stp lr,x0,[sp,#-2*NBPW]!; mov x0,arg; bl trace; \
48        ldp lr,x0,[sp],#2*NBPW
49#endif  //}
50
51NBPW= 8
52#include "arch/arm64/v8/macros.S"
53
54sz_b_info= 12
55  sz_unc= 0
56  sz_cpr= 4
57  b_method= 8
58sz_l_info= 12
59sz_p_info= 12
60
61PROT_READ=  1
62PROT_WRITE= 2
63PROT_EXEC=  4
64
65MAP_PRIVATE= 2
66MAP_FIXED=     0x10
67MAP_ANONYMOUS= 0x20
68FD_ANON= -1
69
70PAGE_SHIFT= 12
71PAGE_SIZE = -(~0<<PAGE_SHIFT)
72
73__NR_SYSCALL_BASE = 0
74
75
76#if SIMULATE_ON_LINUX_EABI4  /*{*/
77__NR_mmap     = 0xde  // 222 __GI___mmap64
78__NR_munmap   = 0xd7  // 215
79__NR_mprotect = 0xe2  // 226
80__NR_openat   = 0x38  //  56
81__NR_pread    = 0x43  //  67
82__NR_write    = 0x40  //  64
83#else  //}{
84__NR_exit =      1 + __NR_SYSCALL_BASE
85__NR_write =     4 + __NR_SYSCALL_BASE
86__NR_open =      5 + __NR_SYSCALL_BASE
87__NR_mmap =    197 + __NR_SYSCALL_BASE
88__NR_mprotect=  74 + __NR_SYSCALL_BASE
89#endif  /*}*/
90
91FD_CWD = -100
92
93// DEBUG ONLY:
94__ARM_NR_BASE  = 0xf0000 + __NR_SYSCALL_BASE
95__ARM_NR_cacheflush =  2 + __ARM_NR_BASE
96
97        //.long sz_pack2  // placed there by ::pack3()
98//0:    .word 0b - &Mach64_header  // backwards distance to Mach64_header
99//0:    .word 0b - l_info  // backwards distance to l_info
100
101  section MACHMAINX
102_start: .globl _start
103        mov x2,sp  // &argc
104    TRACE(#0)
105        bl main
106L20:
107f_decompress:
108
109  section NRV_HEAD
110        // empty
111
112  section NRV2E
113#include "arch/arm64/v8/nrv2e_d32.S"
114
115  section NRV2D
116#include "arch/arm64/v8/nrv2d_d32.S"
117
118  section NRV2B
119#include "arch/arm64/v8/nrv2b_d32.S"
120
121  section NRV_TAIL
122        // empty
123
124#include "arch/arm64/v8/lzma_d.S"
125
126  section MACHMAINY
127end_decompress: .globl end_decompress
128
129        /* IDENTSTR goes here */
130
131r_RELOC .req x23  // same as r_MHDR
132r_MHDR  .req x22
133r_LENX  .req x21
134r_ADRX  .req x20
135r_FOLD  .req x19
136
137arg1 .req x0; arg1w .req w0
138arg2 .req x1; arg2w .req w1
139arg3 .req x2; arg3w .req w2
140arg4 .req x3; arg4w .req w3
141arg5 .req x4; arg5w .req w4
142arg6 .req x5; arg6w .req w5
143
144rdi .req x0
145//rsi .req x1
146rdx .req x2
147rcx .req x3
148
149rax .req x7; eax .req w7
150rbx .req x27
151r_EXP .req x28
152
153  section MACHMAINZ
154lsrc .req w1
155ldst .req w3
156ldstx .req x3
157
158unfold:  // lr= &b_info;  sp/ fd,%ADRU,%LENU,%entry,%&Mach_header,HOLE
159        mov rbx,lr  // &b_info:{sz_unc, sz_cpr, 4{byte}}, compressed_fold...}
160        ldr eax,[rbx,#sz_unc]  // LENU.dynamic
161        sub rdx,rbx,r_MHDR  // LENU.static
162        add rdx,rdx,eax,uxtw
163        str rdx,[sp,#2*NBPW]  // LENU
164
165// Reserve space for input file and unfolded stub.
166        mov arg2,rdx  // len
167        mov arg6w,#0  // offset
168        mov arg5w,#-1  // FD_ANON
169        mov arg4w,#MAP_PRIVATE|MAP_ANONYMOUS
170        mov arg3w,#PROT_READ|PROT_WRITE
171        mov arg1,#0  // kernel chooses addr
172        do_sys __NR_mmap
173        str x0,[sp,#1*NBPW]  // ADRU
174        sub r_ADRX,r_ADRX,r_MHDR  // offset(&l_info)
175        add r_ADRX,r_ADRX,x0  // new &l_info
176
177// Duplicate the input data.
178        mov arg6,#0  // offset
179        ldr arg5w,[sp,#0*NBPW]  // fd
180        mov arg4w,#MAP_PRIVATE|MAP_FIXED
181        mov arg3w,#PROT_READ|PROT_WRITE
182        sub arg2,rbx,r_MHDR  // len
183        // mov arg1,x0  // same address
184        do_sys __NR_mmap
185
186// Remember new f_exp region for PROT_EXEC.
187        ldr rdx,[sp,#2*NBPW]  // LENU
188        ldr rcx,[sp,#4*NBPW]  // &Mach_header
189        add rdx,rdx,x0  // new last of unfolded
190        sub r_RELOC,x0,rcx  // relocation constant = new - old
191        add rcx,r_EXP,r_RELOC
192        str rcx,[sp,#-4*NBPW]!  // P_10  new f_exp
193        and x0,rcx,#~0<<PAGE_SHIFT  // page boundary below new f_exp
194        str x0,[sp,#1*NBPW]  // P_11  address
195        sub rdx,rdx,x0
196        str rdx,[sp,#2*NBPW]  // P_12  length
197    TRACE(#1)
198
199// Unfold
200        ldr eax,[rbx,#sz_unc]  // dstlen
201        add arg4,sp,#3*NBPW  // P_13  &dstlen
202        str rax,[sp,#3*NBPW]
203        add arg3,rbx,r_RELOC  // dst= new unfold
204        mov r_FOLD,arg3  // execute here
205        ldr  eax,[rbx,#sz_cpr]  // srclen
206        ldr arg5w,[rbx,#b_method]
207        add arg1,rbx,#sz_b_info  // src
208        mov arg2,rax  // srclen
209        blr r_EXP  // old f_exp; new f_exp lacks PROT_EXEC
210
211// PROT_EXEC
212        ldr  arg2,[sp, #2*NBPW]  // P_12  length
213        ldr  arg1,[sp, #1*NBPW]  // P_11  addr
214        ldr r_EXP,[sp],#4*NBPW  // P_10  new f_exp
215        mov arg3w,#PROT_READ|PROT_EXEC
216    TRACE(#2)
217        do_sys __NR_mprotect
218
219// Use the copy.
220// x20=r_ADRX= ADRX = &l_info; x21=r_LENX= LENX; x28=r_EXP= f_exp
221// rsp/ fd,ADRU,LENU,%entry,&Mach_header,HOLE
222        br r_FOLD
223
224#if DEBUG  //{
225TRACE_BUFLEN=1024
226trace:  // preserves condition code (thank you, CBNZ) [if write() does!]
227        stp  x0, x1,[sp,#-32*NBPW]!
228        stp  x2, x3,[sp,# 2*NBPW]
229        stp  x4, x5,[sp,# 4*NBPW]
230        stp  x6, x7,[sp,# 6*NBPW]
231        stp  x8, x9,[sp,# 8*NBPW]
232        stp x10,x11,[sp,#10*NBPW]
233        stp x12,x13,[sp,#12*NBPW]
234        stp x14,x15,[sp,#14*NBPW]
235        stp x16,x17,[sp,#16*NBPW]
236        stp x18,x19,[sp,#18*NBPW]
237        stp x20,x21,[sp,#20*NBPW]
238        stp x22,x23,[sp,#22*NBPW]
239        stp x24,x25,[sp,#24*NBPW]
240        stp x26,x27,[sp,#26*NBPW]
241        stp x28,x29,[sp,#28*NBPW]
242        add  x1,lr,#4  // u_pc
243        add  x2,sp,     #32*NBPW + 2*NBPW  // u_sp
244        stp  x1, x2,[sp,#30*NBPW]
245
246        ldr x1,[sp,#(1+ 32)*NBPW]  // x1= u_x0
247        str x1,[sp]  // u_x0
248
249        mov x4,sp  // &u_x0
250        sub sp,sp,#TRACE_BUFLEN
251        mov x2,sp  // output string
252
253        mov w1,#'\n'; bl trace_hex  // In: r0 as label
254        mov w1,#'>';  strb w1,[x2],#1
255
256        mov w5,#10  // nrows to print
257L600:  // each row
258        add x1,sp,#TRACE_BUFLEN
259        sub x0,x4,x1
260        lsr x0,x0,#3; mov w1,#'\n'; bl trace_hex2  // which block of 4
261
262        mov w6,#4  // 64-bit words per row
263L610:  // each word
264        ldr x0,[x4],#8; mov w1,#(' '<<8)|' '; bl trace_hex  // next word
265        sub w6,w6,#1; cbnz w6,L610
266
267        sub w5,w5,#1; cbnz w5,L600
268
269        mov w0,#'\n'; strb w0,[x2],#1
270        mov x1,sp  // buf
271        sub x2,x2,x1  // count
272        mov w0,#2  // FD_STDERR
273        do_sys __NR_write
274        add sp,sp,#TRACE_BUFLEN
275
276        ldp x16,x17,[sp,#16*NBPW]
277        ldp x18,x19,[sp,#18*NBPW]
278        ldp x20,x21,[sp,#20*NBPW]
279        ldp x22,x23,[sp,#22*NBPW]
280        ldp x24,x25,[sp,#24*NBPW]
281        ldp x26,x27,[sp,#26*NBPW]
282        ldp x28,x29,[sp,#28*NBPW]
283        ldp x30, x0,[sp,#30*NBPW]
284        sub  lr, lr,#4  // our lr
285
286        ldp x14,x15,[sp,#14*NBPW]
287        ldp x12,x13,[sp,#12*NBPW]
288        ldp x10,x11,[sp,#10*NBPW]
289        ldp  x8, x9,[sp,# 8*NBPW]
290        ldp  x6, x7,[sp,# 6*NBPW]
291        ldp  x4, x5,[sp,# 4*NBPW]
292        ldp  x2, x3,[sp,# 2*NBPW]
293        ldp  x0, x1,[sp],#32*NBPW
294        ret
295
296trace_hex2:
297        mov w3,#2; b trace_hexwid
298trace_hex:  // In: x0=value, w1=punctuation before, x2=ptr; Uses: w3, x8
299        mov w3,#16  // ndigits
300trace_hexwid:  // In: x0= value; w1= punctuation; x2= ptr; w3= number of low-order digits
301        strb w1,[x2],#1; lsr w1,w1,#8; cbnz w1,trace_hexwid  // prefix punctuation
302        adr x8,hex
303L620:
304        sub w3,w3,#1  // number of less-significant digits
305        lsl w1,w3,#2  // 4 bits per hex digit
306        lsr x1,x0,x1  // right justify this digit
307        and x1,x1,#0xf
308        ldrb w1,[x8, x1]
309        strb w1,[x2],#1
310        sub w1,w3,#8; cbnz w1,0f; mov w1,#'_'; strb w1,[x2],#1  // 8-digit readability
3110:
312        cbnz w3,L620
313        ret
314hex:
315        .ascii "0123456789abcdef"
316#endif  //}
317
318execp:
319        .ascii "executable_path="  // 16 bytes
320L99:
321        brk #0
322
323main:  // IN: x2= &argc; lr= &f_exp
324        mov r_EXP,lr  // &f_decompress
3250:
326        ldr  x0,[x2],#NBPW
327        cbnz x0,0b  // past argv
3280:
329        ldr  x0,[x2],#NBPW
330        cbnz x0,0b  // past envp
331L30:
332        ldr x0,[x2],#NBPW  // x0= *apple++
333        cbz x0,L99
334        adr x1,execp; mov w3,#16
335L40:
336        ldrb w4,[x0],#1
337        ldrb w5,[x1],#1
338        sub w3,w3,#1
339        cmp w4,w5; bne L30  // mismatch ==> next apple[]
340        cbnz w3,L40  // not entire prefix
341
342#if SIMULATE_ON_LINUX_EABI4  //{
343        mov arg3,#0  // O_RDONLY
344        mov arg2,arg1  // path
345        mov arg1w,#FD_CWD
346        do_sys __NR_openat
347#else  //}{
348        mov arg2,#0  // O_RDONLY
349        //mov arg1,x0  // path
350        do_sys __NR_open
351#endif  //}
352        str x0,[sp,#-6*NBPW]!  // fd,%ADRU,%LENU,%entry,%&Mach_header,HOLE
353
354        adr x1,-2*4 + _start
355
356        mov r_MHDR,x1
357        ldr w0,[x1],#4
358        sub r_MHDR,r_MHDR,w0,uxtw // &Mach_header
359        str r_MHDR,[sp,#4*NBPW]
360
361        mov r_ADRX,x1
362        ldr w0,[x1],#4
363        sub r_ADRX,r_ADRX,w0,uxtw  // &l_info
364
365        sub r_LENX,x0,#2*4  // omit words before _start
366        bl unfold
367          /* { b_info={sz_unc, sz_cpr, {4 char}}, folded_loader...} */
368
369/* vim:set ts=8 sw=8 et: */
370