建项目运行中断调试,lldb中显示寄存器看到有rax-r15, stm0-stm7, xmm0-xmm15, ymm0-ymm15,即为x64体系支持sse4。
再在lldb中查看寄存器别名得到以下对应:
rax | |
rbx | |
rcx | arg4 |
rdx | arg3 |
rdi | arg1 |
rsi | arg2 |
rbp | fp |
rsp | sp |
r8 | arg5 |
r9 | arg6 |
r10 | |
r11 | |
r12 | |
r13 | |
r14 | |
r15 | |
rip | pc |
rflags | flags |
cs | |
fs | |
gs |
函数传参数的方式一清二楚,不是以前ia32时代传到街知巷闻的参数从右往左依次压栈的方式(系统调用和__fastcall以及汇编函数除外),函数传参数依次使用rdi,rsi,rdx,rcx,r8,r9。除此之外还用上xmm0-xmm7寄存器。
请看下面代码:
///////////////////////////////////////////////////////////////////// // // SaveRegisters // // Pushes a stack frame and saves all registers that might contain // parameter values. // // On entry: // stack = ret // // On exit: // %rsp is 16-byte aligned // ///////////////////////////////////////////////////////////////////// .macro SaveRegisters push %rbp .cfi_def_cfa_offset 16 .cfi_offset rbp, -16 mov %rsp, %rbp .cfi_def_cfa_register rbp sub $$0x80+8, %rsp // +8 for alignment movdqa %xmm0, -0x80(%rbp) push %rax // might be xmm parameter count movdqa %xmm1, -0x70(%rbp) push %a1 movdqa %xmm2, -0x60(%rbp) push %a2 movdqa %xmm3, -0x50(%rbp) push %a3 movdqa %xmm4, -0x40(%rbp) push %a4 movdqa %xmm5, -0x30(%rbp) push %a5 movdqa %xmm6, -0x20(%rbp) push %a6 movdqa %xmm7, -0x10(%rbp) .endmacro
除了上面提到的寄存器外,r12-r15和rbx的用途能用下面几处反汇编就明白了。
然后翻看调用栈下几个栈的反汇编:
14 - CFRunLoopRunSpecific
15 - -[UIApplication _run]
16 - UIApplicationMain
UIKit`UIApplicationMain: 0x10f0c1bf6 <+0>: pushq %rbp 0x10f0c1bf7 <+1>: movq %rsp, %rbp 0x10f0c1bfa <+4>: pushq %r15 0x10f0c1bfc <+6>: pushq %r14 0x10f0c1bfe <+8>: pushq %r13 0x10f0c1c00 <+10>: pushq %r12 0x10f0c1c02 <+12>: pushq %rbx 0x10f0c1c03 <+13>: pushq %rax 0x10f0c1c04 <+14>: movq %rcx, %rbx 0x10f0c1c07 <+17>: movq %rsi, %r15 0x10f0c1c0a <+20>: movl %edi, %r12d
UIKit`-[UIApplication _run]: 0x10f0bce26 <+0>: pushq %rbp 0x10f0bce27 <+1>: movq %rsp, %rbp 0x10f0bce2a <+4>: pushq %r15 0x10f0bce2c <+6>: pushq %r14 0x10f0bce2e <+8>: pushq %r12 0x10f0bce30 <+10>: pushq %rbx 0x10f0bce31 <+11>: movq %rdi, %rbx 0x10f0bce34 <+14>: callq 0x10fb23e34 ; symbol stub for: objc_autoreleasePoolPush 0x10f0bce39 <+19>: movq %rax, %r14 0x10f0bce3c <+22>: xorl %eax, %eax 0x10f0bce3e <+24>: callq 0x10f4c6d50 ; _UIAccessibilityInitialize 0x10f0bce43 <+29>: movq 0xc68766(%rip), %rsi ; "_registerForUserDefaultsChanges" 0x10f0bce4a <+36>: movq 0xce632f(%rip), %r15 ; (void *)0x000000010e344800: objc_msgSend 0x10f0bce51 <+43>: movq %rbx, %rdi
CoreFoundation`CFRunLoopRunSpecific: 0x10e7d7c40 <+0>: pushq %rbp 0x10e7d7c41 <+1>: movq %rsp, %rbp 0x10e7d7c44 <+4>: pushq %r15 0x10e7d7c46 <+6>: pushq %r14 0x10e7d7c48 <+8>: pushq %r13 0x10e7d7c4a <+10>: pushq %r12 0x10e7d7c4c <+12>: pushq %rbx 0x10e7d7c4d <+13>: subq $0xe8, %rsp 0x10e7d7c54 <+20>: movl %edx, -0xec(%rbp) 0x10e7d7c5a <+26>: movsd %xmm0, -0xe8(%rbp) 0x10e7d7c62 <+34>: movq %rsi, %r14 0x10e7d7c65 <+37>: movq %rdi, %r12 0x10e7d7c68 <+40>: movq 0x311459(%rip), %rax ; (void *)0x00000001114c0070: __stack_chk_guard 0x10e7d7c6f <+47>: movq (%rax), %rax 0x10e7d7c72 <+50>: movq %rax, -0x30(%rbp)
代码的共通点都是在函数开始运算之前将r12-r15以及rbx压入栈,r12-r15以及rbx主要用于函数局部变量或临变量。在UIApplicationMain函数中一开始入栈保存后,马上将输入参数传送到rbx,r15,r12进行运算。
已经约模弄清楚了一条路了,下面就开始反汇编逆向分析,但我的平台是simulator x64。
ps:后面还会介绍objc其它传参方式, 以及windows和linux(也就是vc与gcc)在x64平台的传参方式。