通過匯編代碼我們可以探索函數(shù)的本質
- 1: 如果函數(shù)內部沒有調用其他函數(shù), 那么sp不會進行偏移, 編譯器會通過mov bp - N, 0x11的方式向棧中存入數(shù)據(jù). 這是編譯器所進行的優(yōu)化.這個時候這個棧中的區(qū)域被稱為 紅色區(qū)域 不超過128個字節(jié)
- 如果局部變量超過128個字節(jié), 那么還是需要 sub sp, N來開辟棸嗝校空間
int sum(int a, int b, int c) {
int x = 10;
// test();
return a + b + c + x;
}
可以看到, 如果函數(shù)內部沒有調用其他函數(shù), 并且所有參數(shù)的總字節(jié)數(shù)沒有超過128個字節(jié)時 CPU并不會開辟新的空間,而是使用紅色區(qū)域去存儲變量
safe005`sum:
0x103d90700 <+0>: pushq %rbp
0x103d90701 <+1>: movq %rsp, %rbp
0x103d90704 <+4>: movl %edi, -0x4(%rbp)
0x103d90707 <+7>: movl %esi, -0x8(%rbp)
0x103d9070a <+10>: movl %edx, -0xc(%rbp)
-> 0x103d9070d <+13>: movl $0xa, -0x10(%rbp)
0x103d90714 <+20>: movl -0x4(%rbp), %edx
0x103d90717 <+23>: addl -0x8(%rbp), %edx
0x103d9071a <+26>: addl -0xc(%rbp), %edx
0x103d9071d <+29>: addl -0x10(%rbp), %edx
0x103d90720 <+32>: movl %edx, %eax
0x103d90722 <+34>: popq %rbp
0x103d90723 <+35>: retq
- 2: 如果函數(shù)內部調用其他函數(shù), 則必會通過 sub sp, N 來開辟棻咂唬空間
void test() {
}
int sum(int a, int b, int c) {
int x = 10;
test();
return a + b + c + x;
}
以下是上邊函數(shù)的匯編代碼, 可以看到, 如果函數(shù)內部調用了其他函數(shù), 則sp必會上移,開辟棸诿粒空間, 這時候 下一條指令的地址在 椝常空間上一位, bp在上2位
0x10417b6f0 <+0>: pushq %rbp
0x10417b6f1 <+1>: movq %rsp, %rbp
0x10417b6f4 <+4>: subq $0x10, %rsp
0x10417b6f8 <+8>: movl %edi, -0x4(%rbp)
0x10417b6fb <+11>: movl %esi, -0x8(%rbp)
0x10417b6fe <+14>: movl %edx, -0xc(%rbp)
-> 0x10417b701 <+17>: movl $0xa, -0x10(%rbp)
0x10417b708 <+24>: callq 0x10417b6e0 ; test at main.m:12
0x10417b70d <+29>: movl -0x4(%rbp), %edx
0x10417b710 <+32>: addl -0x8(%rbp), %edx
0x10417b713 <+35>: addl -0xc(%rbp), %edx
0x10417b716 <+38>: addl -0x10(%rbp), %edx
0x10417b719 <+41>: movl %edx, %eax
0x10417b71b <+43>: addq $0x10, %rsp
0x10417b71f <+47>: popq %rbp
0x10417b720 <+48>: retq
棧幀
- 棧幀指的是 sp和bp之間的空間 8086CPU中棧幀很明顯就可以看到, 不過64位的CPU中 由于寄存器得到充分的運用, 所以棧幀不是每次函數(shù)調用都可以出現(xiàn)的
全局變量
image.png
- 如上圖所示, 全局變量相對于app來說, 其偏移地址一直是固定不變的, 而基地址是基于整個app在內存中的物理地址來隨時改變的
if 判斷
int a = 2;
if (a == 1) {
NSLog(@"a == 1");
} else if (a == 2) {
NSLog(@"a == 2");
} else if (a == 3) {
NSLog(@"a == 3");
} else if (a == 4) {
NSLog(@"a == 4");
}
0x1014926bb <+27>: movl $0x2, -0x14(%rbp) ; 賦值
-> 0x1014926c2 <+34>: cmpl $0x1, -0x14(%rbp) ; cmp = cpmpare 比較
0x1014926c6 <+38>: movq %rax, -0x20(%rbp)
0x1014926ca <+42>: jne 0x1014926e6 ; <+70> at main.m:21 ; jne: jump not equl 不等的時候跳轉到0x1014926e6指令
0x1014926d0 <+48>: leaq 0x1989(%rip), %rax ; @"a == 1"
0x1014926d7 <+55>: movq %rax, %rdi
0x1014926da <+58>: movb $0x0, %al
0x1014926dc <+60>: callq 0x101492a14 ; symbol stub for: NSLog
0x1014926e1 <+65>: jmp 0x101492750 ; <+176> at main.m:29
0x1014926e6 <+70>: cmpl $0x2, -0x14(%rbp)
0x1014926ea <+74>: jne 0x101492706 ; <+102> at main.m:23
0x1014926f0 <+80>: leaq 0x1989(%rip), %rax ; @"a == 2"
0x1014926f7 <+87>: movq %rax, %rdi
0x1014926fa <+90>: movb $0x0, %al
0x1014926fc <+92>: callq 0x101492a14 ; symbol stub for: NSLog
0x101492701 <+97>: jmp 0x10149274b ; <+171> at main.m
0x101492706 <+102>: cmpl $0x3, -0x14(%rbp)
0x10149270a <+106>: jne 0x101492726 ; <+134> at main.m:25
0x101492710 <+112>: leaq 0x1989(%rip), %rax ; @"a == 3"
0x101492717 <+119>: movq %rax, %rdi
- 以上代碼是if判斷的匯編實現(xiàn), 問題來了, jne的時候 怎么判斷是否相等而去跳轉呢?
-
是用標記寄存區(qū)來存放比較的結果的:
image.png- 如上圖, cmp前后 如果rflags值沒有發(fā)生改變, 說明并不相等; 若發(fā)生改變, 說明相等
-