[arm64]2、函數(shù)調(diào)用

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  
viewDidLoad函數(shù)執(zhí)行圖

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    
getStr函數(shù)執(zhí)行過程
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    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容