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