栈
栈
栈:先进后出,后进先出,栈的开口方向是往低地址的,arm64开始对栈的操作是16字节对齐
sp & fp
- sp在任何时候都会指向栈顶的位置
- fp寄存器也称为x29寄存器,属于通用寄存器,但在某些时候可以用它来保存栈底的位置 x29(fp)寄存器指向栈低
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
str & ldr
- str:将数据从寄存器中读出来,存到内存中
- ldr:将数据从内存中读出来,存到寄存器中
- ldr 和 str的变种ldp 和 stp 可以操作两个寄存器
bl & ret & x30(lr)
- bl标号
- 将下一条指令的地址放入lr(x30)寄存器
- 转到标号处执行指令
- ret
- 默认使用lr(x30)寄存器的值,通过底层指令提示CPU此处作为下次指令的地址
- x30(lr)
- x30(lr)寄存器存放的是函数的返回地址,当ret指令执行时会寻找x30(lr)寄存器保存的地址的值
运行上面这段代码
但是当出现函数嵌套时,lr只能保存最里面一层的返回的地址,所以要把每层函数的返回地址都保存在栈区
- x30(lr)寄存器存放的是函数的返回地址,当ret指令执行时会寻找x30(lr)寄存器保存的地址的值
函数
带有参数的函数
arm64下函数的参数是放在x0~x7,或w0~w7,这几个寄存器里,如果超过8个函数,就会入栈
函数的参数超过8个
也就是说当参数超过8个的时候,可能会把栈顶的位置用来当作参数的传递功能,因为在进入到test方法中可以看到,又去上一个函数的栈顶的位置去取参数。
函数的返回值
在还没有进入getstr方法中时,就先把返回值的空间预留好,在getStr中ldr取出数据,str存入前面预留好的栈空间中,用之前函数的栈来保存返回值是因为用自己的栈的话有可能被释放,所以用其他函数的栈空间
局部变量
3和4在前面已经存入寄存器中在funcA中存入栈中,2在funcA中才存入寄存器,随后也存入了栈中