1、棧
棧:是一種具有特殊的訪問方式的存儲空間(后進先出, Last In Out Firt,LIFO)
1.1、SP和FP寄存器
sp寄存器在任意時刻會保存我們棧頂?shù)牡刂?
fp寄存器也稱為x29寄存器屬于通用寄存器,但是在某些時刻我們利用它保存棧底的地址!
注意:ARM64開始,取消32位的 LDM,STM,PUSH,POP指令! 取而代之的是ldr\ldp str\stp
ARM64里面 對棧的操作是16字節(jié)對齊的!!
1.2、函數(shù)調(diào)用棧
常見的函數(shù)調(diào)用開辟和恢復(fù)的棧空間
sub sp, sp, #0x40 ; 拉伸0x40(64字節(jié))空間
stp x29, x30, [sp, #0x30] ;x29\x30 寄存器入棧保護
add x29, sp, #0x30 ; x29指向棧幀的底部
...
ldp x29, x30, [sp, #0x30] ;恢復(fù)x29/x30 寄存器的值
add sp, sp, #0x40 ; 棧平衡
ret

1.3、關(guān)于內(nèi)存讀寫指令
注意:讀/寫 數(shù)據(jù)是都是往高地址讀/寫
1、str(store register)指令
將數(shù)據(jù)從寄存器中讀出來,存到內(nèi)存中.
2、ldr(load register)指令
將數(shù)據(jù)從內(nèi)存中讀出來,存到寄存器中
此ldr 和 str 的變種ldp 和 stp 還可以操作2個寄存器.
1.4、bl和ret指令
1、bl標號
- 將下一條指令的地址放入lr(x30)寄存器
- 轉(zhuǎn)到標號處執(zhí)行指令
2、ret
默認使用lr(x30)寄存器的值,通過底層指令提示CPU此處作為下條指令地址!
ARM64平臺的特色指令,它面向硬件做了優(yōu)化處理的
3、x30寄存器
x30寄存器存放的是函數(shù)的返回地址.當ret指令執(zhí)行時刻,會尋找x30寄存器保存的地址值!
注意:在函數(shù)嵌套調(diào)用的時候.需要講x30入棧!
2、函數(shù)的參數(shù)和返回值
ARM64下,函數(shù)的參數(shù)是存放在X0到X7(W0到W7)這8個寄存器里面的.如果超過8個參數(shù),就會入棧.
函數(shù)的返回值是放在X0 寄存器里面的.
因此函數(shù)的參數(shù)最好不要超過8個
2.1、實現(xiàn)test函數(shù)超過8個參數(shù)調(diào)用
int test(int a,int b,int c,int d,int e,int f,int g,int h,int i){
return a+b+c+d+e+f+g+h+i;
}
- (void)viewDidLoad {
[super viewDidLoad];
test(1, 2, 3, 4, 5, 6, 7, 8, 9);
}
ViewDidLoad匯編實現(xiàn)
001--Demo`-[ViewController viewDidLoad]:
// 拉伸棧空間
0x10400a3a0 <+0>: sub sp, sp, #0x40 ; =0x40
0x10400a3a4 <+4>: stp x29, x30, [sp, #0x30]
0x10400a3a8 <+8>: add x29, sp, #0x30 ; =0x30
0x10400a3ac <+12>: stur x0, [x29, #-0x8]
0x10400a3b0 <+16>: stur x1, [x29, #-0x10]
0x10400a3b4 <+20>: ldur x8, [x29, #-0x8]
0x10400a3b8 <+24>: add x0, sp, #0x10 ; =0x10
0x10400a3bc <+28>: str x8, [sp, #0x10]
0x10400a3c0 <+32>: adrp x8, 6
0x10400a3c4 <+36>: ldr x8, [x8, #0xc58]
0x10400a3c8 <+40>: str x8, [sp, #0x18]
0x10400a3cc <+44>: adrp x8, 6
0x10400a3d0 <+48>: ldr x1, [x8, #0xc40]
0x10400a3d4 <+52>: bl 0x10400a7c4 ; symbol stub for: objc_msgSendSuper2
0x10400a3d8 <+56>: mov w0, #0x1
0x10400a3dc <+60>: mov w1, #0x2
0x10400a3e0 <+64>: mov w2, #0x3
0x10400a3e4 <+68>: mov w3, #0x4
0x10400a3e8 <+72>: mov w4, #0x5
0x10400a3ec <+76>: mov w5, #0x6
0x10400a3f0 <+80>: mov w6, #0x7
0x10400a3f4 <+84>: mov w7, #0x8
-> 0x10400a3f8 <+88>: mov x9, sp
0x10400a3fc <+92>: mov w8, #0x9
// 將W8的值保存在上一個??臻g中
0x10400a400 <+96>: str w8, [x9]
0x10400a404 <+100>: bl 0x10400a328 ; test at ViewController.m:17
0x10400a408 <+104>: ldp x29, x30, [sp, #0x30]
0x10400a40c <+108>: add sp, sp, #0x40 ; =0x40
0x10400a410 <+112>: ret

test函數(shù)的執(zhí)行
001--Demo`test:
0x10400a328 <+0>: sub sp, sp, #0x30 ; =0x30
// 從上一個??臻g從內(nèi)存讀參數(shù)到寄存器
-> 0x10400a32c <+4>: ldr w8, [sp, #0x30]
0x10400a330 <+8>: str w0, [sp, #0x2c]
0x10400a334 <+12>: str w1, [sp, #0x28]
0x10400a338 <+16>: str w2, [sp, #0x24]
0x10400a33c <+20>: str w3, [sp, #0x20]
0x10400a340 <+24>: str w4, [sp, #0x1c]
0x10400a344 <+28>: str w5, [sp, #0x18]
0x10400a348 <+32>: str w6, [sp, #0x14]
0x10400a34c <+36>: str w7, [sp, #0x10]
0x10400a350 <+40>: str w8, [sp, #0xc]
0x10400a354 <+44>: ldr w8, [sp, #0x2c]
0x10400a358 <+48>: ldr w9, [sp, #0x28]
0x10400a35c <+52>: add w8, w8, w9
0x10400a360 <+56>: ldr w9, [sp, #0x24]
0x10400a364 <+60>: add w8, w8, w9
0x10400a368 <+64>: ldr w9, [sp, #0x20]
0x10400a36c <+68>: add w8, w8, w9
0x10400a370 <+72>: ldr w9, [sp, #0x1c]
0x10400a374 <+76>: add w8, w8, w9
0x10400a378 <+80>: ldr w9, [sp, #0x18]
0x10400a37c <+84>: add w8, w8, w9
0x10400a380 <+88>: ldr w9, [sp, #0x14]
0x10400a384 <+92>: add w8, w8, w9
0x10400a388 <+96>: ldr w9, [sp, #0x10]
0x10400a38c <+100>: add w8, w8, w9
0x10400a390 <+104>: ldr w9, [sp, #0xc]
0x10400a394 <+108>: add w0, w8, w9
0x10400a398 <+112>: add sp, sp, #0x30 ; =0x30
0x10400a39c <+116>: ret
2.2、返回結(jié)構(gòu)體實現(xiàn)棧傳遞
OC返回結(jié)構(gòu)體
struct str getStr(int a, int b, int c, int d, int e, int f){
struct str str1;
str1.a = a;
str1.b = b;
str1.c = c;
str1.d = d;
str1.e = e;
str1.f = f;
return str1;
}
- (void)viewDidLoad {
[super viewDidLoad];
getStr(1, 2, 3, 4, 5, 6);
}
viewDidLoad匯編實現(xiàn)
001--Demo`-[ViewController viewDidLoad]:
0x104e2e3e4 <+0>: sub sp, sp, #0x50 ; =0x50
0x104e2e3e8 <+4>: stp x29, x30, [sp, #0x40]
0x104e2e3ec <+8>: add x29, sp, #0x40 ; =0x40
0x104e2e3f0 <+12>: stur x0, [x29, #-0x8]
0x104e2e3f4 <+16>: stur x1, [x29, #-0x10]
0x104e2e3f8 <+20>: ldur x8, [x29, #-0x8]
0x104e2e3fc <+24>: add x0, sp, #0x20 ; =0x20
0x104e2e400 <+28>: str x8, [sp, #0x20]
0x104e2e404 <+32>: adrp x8, 6
0x104e2e408 <+36>: ldr x8, [x8, #0xc58]
0x104e2e40c <+40>: str x8, [sp, #0x28]
0x104e2e410 <+44>: adrp x8, 6
0x104e2e414 <+48>: ldr x1, [x8, #0xc40]
0x104e2e418 <+52>: bl 0x104e2e7c4 ; symbol stub for: objc_msgSendSuper2
// sp棧頂指針向下偏移8個字節(jié),指針賦值給x8寄存器
0x104e2e41c <+56>: add x8, sp, #0x8 ; =0x8
// 參數(shù)賦值給 w0~w5
0x104e2e420 <+60>: mov w0, #0x1
0x104e2e424 <+64>: mov w1, #0x2
0x104e2e428 <+68>: mov w2, #0x3
0x104e2e42c <+72>: mov w3, #0x4
0x104e2e430 <+76>: mov w4, #0x5
0x104e2e434 <+80>: mov w5, #0x6
-> 0x104e2e438 <+84>: bl 0x104e2e38c ; getStr at ViewController.m:30
0x104e2e43c <+88>: ldp x29, x30, [sp, #0x40]
0x104e2e440 <+92>: add sp, sp, #0x50 ; =0x50
0x104e2e444 <+96>: ret
getStr匯編實現(xiàn)
001--Demo`getStr:
0x100426594 <+0>: sub sp, sp, #0x20 ; =0x20
0x100426598 <+4>: mov x9, x8
0x10042659c <+8>: str w0, [sp, #0x1c]
0x1004265a0 <+12>: str w1, [sp, #0x18]
-> 0x1004265a4 <+16>: str w2, [sp, #0x14]
0x1004265a8 <+20>: str w3, [sp, #0x10]
0x1004265ac <+24>: str w4, [sp, #0xc]
0x1004265b0 <+28>: str w5, [sp, #0x8]
0x1004265b4 <+32>: ldr w8, [sp, #0x1c]
0x1004265b8 <+36>: str w8, [x9]
0x1004265bc <+40>: ldr w8, [sp, #0x18]
0x1004265c0 <+44>: str w8, [x9, #0x4]
0x1004265c4 <+48>: ldr w8, [sp, #0x14]
0x1004265c8 <+52>: str w8, [x9, #0x8]
0x1004265cc <+56>: ldr w8, [sp, #0x10]
0x1004265d0 <+60>: str w8, [x9, #0xc]
0x1004265d4 <+64>: ldr w8, [sp, #0xc]
0x1004265d8 <+68>: str w8, [x9, #0x10]
0x1004265dc <+72>: ldr w8, [sp, #0x8]
0x1004265e0 <+76>: str w8, [x9, #0x14]
0x1004265e4 <+80>: add sp, sp, #0x20 ; =0x20
0x1004265e8 <+84>: ret

2.3、匯編實現(xiàn)a + b的函數(shù)
.text
.global _funcA, _sum
_funcA:
stp x29, x30, [sp, #-0x10]!
// sub sp, sp, #0x10
// stp x29, x30, [sp]
bl _sum
// ldp x29, x30, [sp]
// add sp, sp, #0x10
ldp x29, x30, [sp], #0x10
ret
_sum:
add x0, x0, x1
ret
3、函數(shù)的局部變量
函數(shù)的局部變量放在棧里面!
3.1、局部變量傳遞
局部變量c
int funcB(int a, int b) {
int c = 6;
return a + b + c;
}
int main(int argc, char * argv[]) {
funcB(10, 20);
}
funcB的匯編調(diào)用
001--Demo`funcB:
-> 0x104b4e428 <+0>: sub sp, sp, #0x10 ; =0x10
0x104b4e42c <+4>: str w0, [sp, #0xc]
0x104b4e430 <+8>: str w1, [sp, #0x8]
// 局部變量c
0x104b4e434 <+12>: mov w8, #0x6
// 將 c的值寫入到內(nèi)存中,入棧
0x104b4e438 <+16>: str w8, [sp, #0x4]
0x104b4e43c <+20>: ldr w8, [sp, #0xc]
0x104b4e440 <+24>: ldr w9, [sp, #0x8]
0x104b4e444 <+28>: add w8, w8, w9
0x104b4e448 <+32>: ldr w9, [sp, #0x4]
0x104b4e44c <+36>: add w0, w8, w9
0x104b4e450 <+40>: add sp, sp, #0x10 ; =0x10
0x104b4e454 <+44>: ret
4、函數(shù)的嵌套調(diào)用
函數(shù)嵌套
int funcB(int a, int b) {
int c = 6;
int d = funcSum(a, b, c);
int e = funcSum(a, b, c);
return e;
}
int funcSum(int a, int b, int c) {
int d = a + b + c;
printf("%d", d);
return d;
}
int main(int argc, char * argv[]) {
funcB(10, 20);
}
funcB的匯編
001--Demo`funcB:
0x100766398 <+0>: sub sp, sp, #0x30 ; =0x30
0x10076639c <+4>: stp x29, x30, [sp, #0x20]
0x1007663a0 <+8>: add x29, sp, #0x20 ; =0x20
0x1007663a4 <+12>: stur w0, [x29, #-0x4]
0x1007663a8 <+16>: stur w1, [x29, #-0x8]
0x1007663ac <+20>: mov w8, #0x6
0x1007663b0 <+24>: stur w8, [x29, #-0xc]
0x1007663b4 <+28>: ldur w0, [x29, #-0x4]
0x1007663b8 <+32>: ldur w1, [x29, #-0x8]
0x1007663bc <+36>: ldur w2, [x29, #-0xc]
0x1007663c0 <+40>: bl 0x1007663ec ; funcSum at main.m:28
0x1007663c4 <+44>: str w0, [sp, #0x10]
0x1007663c8 <+48>: ldur w0, [x29, #-0x4]
0x1007663cc <+52>: ldur w1, [x29, #-0x8]
0x1007663d0 <+56>: ldur w2, [x29, #-0xc]
0x1007663d4 <+60>: bl 0x1007663ec ; funcSum at main.m:28
-> 0x1007663d8 <+64>: str w0, [sp, #0xc]
0x1007663dc <+68>: ldr w0, [sp, #0xc]
0x1007663e0 <+72>: ldp x29, x30, [sp, #0x20]
0x1007663e4 <+76>: add sp, sp, #0x30 ; =0x30
0x1007663e8 <+80>: ret
5、全局變量和常量
全局變量和常量的取值
當前的偏移頁數(shù)+當前頁號+偏移量
adrp x0, 2
add x0, x0, #0xe27
// 全局變量g
int g = 12;
int func(int a, int b) {
printf("haha"); // 常量 haha
int c = a + g;
return c;
}
int main(int argc, char * argv[]) {
func(1, 2);
return 0;
}
func的匯編
002-Demo`func:
0x100d71fd0 <+0>: sub sp, sp, #0x20 ; =0x20
0x100d71fd4 <+4>: stp x29, x30, [sp, #0x10]
0x100d71fd8 <+8>: add x29, sp, #0x10 ; =0x10
0x100d71fdc <+12>: stur w0, [x29, #-0x4]
0x100d71fe0 <+16>: str w1, [sp, #0x8]
// 2>>12 + 0x100d71000 + 0xe27
// 2(當前的偏移頁數(shù))向右偏移12位 + 0x100d71000(當前頁號)+ 0xe27(偏移量)
0x100d71fe4 <+20>: adrp x0, 2
0x100d71fe8 <+24>: add x0, x0, #0xe27 ; =0xe27
0x100d71fec <+28>: bl 0x100d7234c ; symbol stub for: printf
0x100d71ff0 <+32>: ldur w8, [x29, #-0x4]
0x100d71ff4 <+36>: adrp x9, 8
0x100d71ff8 <+40>: ldr w9, [x9, #0x4a0]
0x100d71ffc <+44>: add w8, w8, w9
0x100d72000 <+48>: str w8, [sp, #0x4]
0x100d72004 <+52>: ldr w0, [sp, #0x4]
0x100d72008 <+56>: ldp x29, x30, [sp, #0x10]
0x100d7200c <+60>: add sp, sp, #0x20 ; =0x20
0x100d72010 <+64>: ret