美文网首页
[arm64]2、函数调用

[arm64]2、函数调用

作者: 史记_d5da | 来源:发表于2021-11-29 22:08 被阅读0次

    1、栈

    栈:是一种具有特殊的访问方式的存储空间(后进先出, Last In Out Firt,LIFO)

    1.1、SP和FP寄存器

    sp寄存器在任意时刻会保存我们栈顶的地址.
    fp寄存器也称为x29寄存器属于通用寄存器,但是在某些时刻我们利用它保存栈底的地址!

    注意:ARM64开始,取消32位的 LDM,STM,PUSH,POP指令! 取而代之的是ldr\ldp str\stp
    ARM64里面 对栈的操作是16字节对齐的!!

    1.2、函数调用栈

    常见的函数调用开辟和恢复的栈空间

    sub    sp, sp, #0x40             ; 拉伸0x40(64字节)空间
    stp    x29, x30, [sp, #0x30]     ;x29\x30 寄存器入栈保护
    add    x29, sp, #0x30            ; x29指向栈帧的底部
    ... 
    ldp    x29, x30, [sp, #0x30]     ;恢复x29/x30 寄存器的值
    add    sp, sp, #0x40             ; 栈平衡
    ret
    
    栈空间图

    1.3、关于内存读写指令

    注意:读/写 数据是都是往高地址读/写

    1、str(store register)指令
    将数据从寄存器中读出来,存到内存中.
    2、ldr(load register)指令
    将数据从内存中读出来,存到寄存器中
    此ldr 和 str 的变种ldp 和 stp 还可以操作2个寄存器.

    1.4、bl和ret指令

    1、bl标号

    • 将下一条指令的地址放入lr(x30)寄存器
    • 转到标号处执行指令

    2、ret
    默认使用lr(x30)寄存器的值,通过底层指令提示CPU此处作为下条指令地址!

    ARM64平台的特色指令,它面向硬件做了优化处理的

    3、x30寄存器
    x30寄存器存放的是函数的返回地址.当ret指令执行时刻,会寻找x30寄存器保存的地址值!

    注意:在函数嵌套调用的时候.需要讲x30入栈!

    2、函数的参数和返回值

    ARM64下,函数的参数是存放在X0到X7(W0到W7)这8个寄存器里面的.如果超过8个参数,就会入栈.
    函数的返回值是放在X0 寄存器里面的.

    因此函数的参数最好不要超过8个

    2.1、实现test函数超过8个参数调用
    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汇编实现

    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的值保存在上一个栈空间中
        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函数执行图

    test函数的执行

    001--Demo`test:
        0x10400a328 <+0>:   sub    sp, sp, #0x30             ; =0x30 
    // 从上一个栈空间从内存读参数到寄存器
    ->  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、返回结构体实现栈传递

    OC返回结构体

    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汇编实现

    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个字节,指针赋值给x8寄存器
        0x104e2e41c <+56>: add    x8, sp, #0x8              ; =0x8 
    // 参数赋值给 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汇编实现

    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函数执行过程
    2.3、汇编实现a + b的函数
    .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、函数的局部变量

    函数的局部变量放在栈里面!

    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的汇编调用

    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的值写入到内存中,入栈
        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、函数的嵌套调用

    函数嵌套

    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、全局变量和常量

    全局变量和常量的取值
    当前的偏移页数+当前页号+偏移量
    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(当前的偏移页数)向右偏移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    
    

    相关文章

      网友评论

          本文标题:[arm64]2、函数调用

          本文链接:https://www.haomeiwen.com/subject/gkihxrtx.html