1// arm-darwin.macho-fold.S -- linkage to C code to process Mach-O binary 2// 3// This file is part of the UPX executable compressor. 4// 5// Copyright (C) 2000-2020 John F. Reiser 6// All Rights Reserved. 7// 8// UPX and the UCL library are free software; you can redistribute them 9// and/or modify them under the terms of the GNU General Public License as 10// published by the Free Software Foundation; either version 2 of 11// the License, or (at your option) any later version. 12// 13// This program is distributed in the hope that it will be useful, 14// but WITHOUT ANY WARRANTY; without even the implied warranty of 15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16// GNU General Public License for more details. 17// 18// You should have received a copy of the GNU General Public License 19// along with this program; see the file COPYING. 20// If not, write to the Free Software Foundation, Inc., 21// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22// 23// Markus F.X.J. Oberhumer Laszlo Molnar 24// <markus@oberhumer.com> <ezerotven+github@gmail.com> 25// 26// John F. Reiser 27// <jreiser@users.sourceforge.net> 28// 29 30#define SIMULATE_ON_LINUX_EABI4 0 31 32#if SIMULATE_ON_LINUX_EABI4 /*{*/ 33 #define LINUX_ARM_CACHEFLUSH 1 /* SIMULATE_ON_LINUX_EABI4 */ 34 #define ARMEL_EABI4 1 /* SIMULATE_ON_LINUX_EABI4 */ 35#else /*}{ USUAL case */ 36 #define DARWIN_ARM_CACHEFLUSH 1 37 #define ARMEL_DARWIN 1 38#endif /*}*/ 39 40#ifndef DEBUG //{ 41#define DEBUG 0 42#endif //} 43#define TRACE_REGS r0-r12,r14,r15 44 45NBPW= 4 46#include "arch/arm/v5a/macros.S" 47 48arg1 .req r0 49arg2 .req r1 50arg3 .req r2 51arg4 .req r3 52arg5 .req r4 53arg6 .req r5 54arg7 .req r6 55 56sz_l_info = 12 57sz_p_info = 12 58sz_b_info = 12 59 sz_unc= 0 60 sz_cpr= 4 61 b_method= 8 62 63#if SIMULATE_ON_LINUX_EABI4 /*{*/ 64__NR_brk = 45 + __NR_SYSCALL_BASE // 0x2d 65__NR_close = 6 + __NR_SYSCALL_BASE // 0x06 66__NR_exit = 1 + __NR_SYSCALL_BASE // ?? 67__NR_mmap = 192 + __NR_SYSCALL_BASE // 0xc0 68__NR_mprotect = 125 + __NR_SYSCALL_BASE // 0x7d 69__NR_munmap = 91 + __NR_SYSCALL_BASE // 0x5b 70__NR_open = 5 + __NR_SYSCALL_BASE // ?? 71__NR_openat = 322 + __NR_SYSCALL_BASE // 0x142 72__NR_pread = 180 + __NR_SYSCALL_BASE // 0xb4 73__NR_read = 3 + __NR_SYSCALL_BASE // 0x03 74__NR_write = 4 + __NR_SYSCALL_BASE // 0x04 75#else //}{ native darwin usual case 76__NR_brk = 45 + __NR_SYSCALL_BASE 77__NR_close = 6 + __NR_SYSCALL_BASE 78__NR_exit = 1 + __NR_SYSCALL_BASE 79__NR_mmap = 197 + __NR_SYSCALL_BASE 80__NR_mprotect = 74 + __NR_SYSCALL_BASE 81__NR_munmap = 73 + __NR_SYSCALL_BASE 82__NR_open = 5 + __NR_SYSCALL_BASE 83__NR_pread = 153 + __NR_SYSCALL_BASE 84__NR_read = 3 + __NR_SYSCALL_BASE 85__NR_write = 4 + __NR_SYSCALL_BASE 86#endif /*}*/ 87 88_start: .globl _start // ignored, but silence "cannot find entry symbol _start" from ld 89 90// control just falls through, after this part and compiled C code 91// are uncompressed. 92 93fold_begin: 94/* In: 95 r9= f_exp; r10= ADRX; r11= LENX 96 rsp/ fd,ADRU,LENU,%entry,&Mach_header 97*/ 98r_t0 .req r12 // scratch 99r_LENX .req r11 100r_ADRX .req r10 101r_EXP .req r9 102r_OSTK .req r8 103#if DEBUG /*{*/ 104 stmdb sp!,{TRACE_REGS}; mov r0,#0x11; bl trace 105#endif /*}*/ 106 107 ldr arg4,[r_ADRX,#sz_unc + sz_l_info + sz_p_info] // sz_unc of Mach_header 108 mov r_t0,#(1<<13) 109 cmp arg4,r_t0 110 movlo arg4,r_t0 // at least 8KiB 111 mov r_OSTK,sp // where to un-alloca 112 sub sp,sp,arg4 // alloca 113 mov arg3,sp // temp[sz_mhdr] 114 mov arg2,r_LENX 115 mov arg1,r_ADRX // &{l_info; p_info; b_info} 116 117 add arg7,r_OSTK,#4*NBPW // & &Mach_header 118 adr arg6,f_unfilter 119 mov arg5,r_EXP 120 stmdb sp!,{arg5,arg6,arg7} // ABI: only arg1,arg2,arg3,arg4 in registers 121#if DEBUG /*{*/ 122 stmdb sp!,{TRACE_REGS}; mov r0,#0x12; bl trace 123#endif /*}*/ 124// upx_main(r0=&l_info, r1=len_cpr, r2=temp[sz_mhdr], r3=sz_mhdr, r4=f_exp, r5=f_unf, r6=mhdr **) 125 bl upx_main // OUT: r0= &Mach_thread_state of dyld; will be in temp mhdr[] 126 127ARM_ts_pc= 14*NBPW 128 ldr r_ADRX,[r0,#ARM_ts_pc] // dyld.entry 129 ldr r_EXP, [r0,#0] // &hatch 130 mov sp,r_OSTK // un-alloc 131 132 ldr r0,[sp,#0*NBPW] // fd 133 bl close 134 135 ldr r0,[sp,#1*NBPW] // ADRU 136 ldr r1,[sp,#2*NBPW] // LENU 137 mov r7,#__NR_munmap 138 mov lr,r_ADRX // dyld.entry 139 add sp,sp,#4*NBPW // leave &Mach_header 140#if DEBUG /*{*/ 141 stmdb sp!,{TRACE_REGS}; mov r0,#0x13; bl trace 142#endif /*}*/ 143 bx r_EXP // goto hatch: syscall.munmap(ADRU,LENU); ret 144 145f_unfilter: // (char *ptr, uint len, uint cto, uint fid) 146 ptr .req r0 147 len .req r1 148 cto .req r2 // unused 149 fid .req r3 150 151 t1 .req r2 152 t2 .req r3 153 154#ifndef FILTER_ID /*{*/ 155#define FILTER_ID 0x50 /* little-endian */ 156#endif /*}*/ 157 and fid,fid,#0xff 158 cmp fid,#FILTER_ID // last use of fid 159 movne pc,lr // no-op if not filter 0x50 160 161 movs len,len,lsr #2 // word count 162 cmpne ptr,#0 163 moveq pc,lr // no-op if either len or ptr is 0 164 165top_unf: 166 sub len,len,#1 167 ldr t1,[ptr,len,lsl #2] 168 and t2,t1,#0x0f<<24 169 cmp t2, #0x0b<<24; bne tst_unf // not 'bl' subroutine call 170 and t2,t1,#0xff<<24 // all the non-displacement bits 171 sub t1,t1,len // convert to word-relative displacement 172 bic t1,t1,#0xff<<24 // restrict to displacement field 173 orr t1,t1,t2 // re-combine 174 str t1,[ptr,len,lsl #2] 175tst_unf: 176 cmp len,#0 177 bne top_unf 178 mov pc,lr 179 180 .unreq ptr 181 .unreq len 182 .unreq cto 183 .unreq fid 184 185#if DEBUG /*{*/ 186TRACE_BUFLEN=512 187trace: 188 str lr,[sp,#(-1+ 15)*4] @ return pc; [remember: sp is not stored] 189 mov r4,sp @ &saved_r0 190 sub sp,sp,#TRACE_BUFLEN 191 mov r2,sp @ output string 192 193 mov r1,#'\n'; bl trace_hex @ In: r0 as label 194 mov r1,#'>'; strb r1,[r2],#1 195 196 mov r5,#3 @ rows to print 197L600: @ each row 198 sub r0,r4,#TRACE_BUFLEN 199 sub r0,r0,sp 200 mov r0,r0,lsr #2; mov r1,#'\n'; bl trace_hex @ which block of 8 201 202 mov r6,#8 @ words per row 203L610: @ each word 204 ldr r0,[r4],#4; mov r1,#' '; bl trace_hex @ next word 205 subs r6,r6,#1; bgt L610 206 207 subs r5,r5,#1; bgt L600 208 209 mov r0,#'\n'; strb r0,[r2],#1 210 sub r2,r2,sp @ count 211 mov r1,sp @ buf 212 mov r0,#2 @ FD_STDERR 213#if defined(ARMEL_EABI4) /*{*/ 214 mov r7,#__NR_write 215 swi 0 216#else /*}{*/ 217 swi __NR_write 218#endif /*}*/ 219 add sp,sp,#TRACE_BUFLEN 220 ldmia sp!,{TRACE_REGS} 221 222trace_hex: // In: r0=val, r1=punctuation before, r2=ptr; Uses: r3, ip 223 strb r1,[r2],#1 @ punctuation 224 mov r3,#4*(8 -1) @ shift count 225 adr ip,hex 226L620: 227 mov r1,r0,lsr r3 228 and r1,r1,#0xf 229 ldrb r1,[ip, r1] 230 strb r1,[r2],#1 231 subs r3,r3,#4; bge L620 232 ret 233hex: 234 .ascii "0123456789abcdef" 235#endif /*}*/ 236spin: .globl spin 237 ret 238 239 .globl exit 240exit: 241 do_sys __NR_exit 242 243 .globl read 244read: 245 do_sys __NR_read; ret 246 247 .globl write 248write: 249 do_sys __NR_write; ret 250 251 .globl open 252open: 253 do_sys __NR_open; ret 254 255 .globl close 256close: 257 do_sys __NR_close; ret 258 259 .globl brk 260brk: 261 do_sys __NR_brk; ret 262 263 .globl munmap 264munmap: 265 do_sys __NR_munmap; ret 266 267 .globl mprotect 268mprotect: 269 do_sys __NR_mprotect; ret 270 271 .globl mmap 272mmap: 273#if SIMULATE_ON_LINUX_EABI4 /*{*/ 274 stmdb sp!,{r4,r5} 275 ldr r5,[sp,#3*4] // off_t 276 ldr r4,[sp,#2*4] // fd 277 movs r12,r5,lsl #(32-12); bne mmap_frag // lo 12 bits of offset 278 mov r5,r5,lsr #12 // convert to page number (avoid 64-bit argument) 279 do_sys __NR_mmap 280mmap_ret: 281 ldmia sp!,{r4,r5} 282 ret 283mmap_frag: 284EINVAL=22 285 mov r0,#-EINVAL // offset not a multiple of page size 286 b mmap_ret 287#else /*}{ USUAL case */ 288 mov ip,sp 289 stmdb sp!,{r4,r5,r6} 290 ldmia ip ,{r4,r5 /*,r6*/} 291 mov r6,#0 // XXX: convert 32-bit unsigned off_t to 64-bits 292 do_sys __NR_mmap 293 ldmia sp!,{r4,r5,r6} 294 ret 295#endif /*}*/ 296 297 .globl pread 298pread: 299#if SIMULATE_ON_LINUX_EABI4 /*{*/ 300 stmdb sp!,{r4,r5} // EABI4 wants 64-bit off_t in even,odd register pair 301 mov r4,r3 // 32-bit off_t 302 mov r5,#0 // hi bits of 64-bit off_t 303 do_sys __NR_pread 304 ldmia sp!,{r4,r5} 305 ret 306#else /*}{ USUAL case */ 307 str r4,[sp,#-4]! // PUSH r4 308 mov r4,#0 // convert 32-bit unsigned off_t in r3 to 64 bits in (r3,r4) 309 do_sys __NR_pread 310 ldr r4,[sp],#4 // POP r4 311 ret 312#endif /*}*/ 313 314 .globl bswap 315bswap: 316 mov ip, #0xff 317 orr ip,ip,#0xff<<16 // ip= 0x00ff00ff 318 b bswap9 319bswap0: 320 ldr r2,[r0] // r2= A B C D 321 and r3,ip,r2 // r3= 0 B 0 D 322 and r2,ip,r2,ror #24 // r2= 0 C 0 A 323 orr r2,r2,r3,ror # 8 // r2= D C B A 324 str r2,[r0],#4 325bswap9: 326 subs r1,r1,#4 327 bge bswap0 328 ret 329 330bad__udivsi3: 331 bkpt 332__udivsi3: .globl __udivsi3 333 cmp r1,#10 334 bne bad__udivsi3 335div10: .globl div10 336 mov ip,r0 @ extra copy used at end 337 sub r1,r1,r1 @ hi 338 339 mov r2,r0 @ copy lo 340 adds r0,r0,r0,lsl #3 @ 9*lo 341 adc r1,r1,r1,lsl #3 @ 9*hi + C 342 add r1,r1,r2,lsr #(32 - 3) @ bits shifted from lo to hi 343 344 mov r2,r0 @ copy lo 345 adds r0,r0,r0,lsl #4 346 adc r1,r1,r1,lsl #4 347 add r1,r1,r2,lsr #(32 - 4) @ * 0x99 348 349 mov r2,r0 @ copy lo 350 adds r0,r0,r0,lsl #8 351 adc r1,r1,r1,lsl #8 352 add r1,r1,r2,lsr #(32 - 8) @ * 0x9999 353 354 mov r2,r0 @ copy lo 355 adds r0,r0,r0,lsl #16 356 adc r1,r1,r1,lsl #16 357 add r1,r1,r2,lsr #(32 - 16) @ * 0x99999999 358 359 subs r0,r0,ip,lsl #(32 - 1) @ - * 0x80000000 360 sbc r1,r1,ip,lsr #1 @ * 0x19999999 361 362 adds r0,r0,ip 363 adc r0,r1,#0 @ * 0x0.1999999a 364 ret 365 366/* vim:set ts=8 sw=8 et: */ 367