建议先看《CSAPP》的3.7节,讲的很细。我们这里就直接看例子来分析了。
例子
上面的程序,我们写了一个 func 的调用,主要是观察其参数传递时,寄存器的使用以及栈的变化情况。
在ARM64体系结构中,栈是从高地址往低地址生长。栈在函数调用过程中起到非常重要的作用,包括存储函数使用的局部变量、传递参数等。在函数调用过程中,栈是逐步生成的。为单个函数分配的栈空间,即从该函数栈底(高地址)到栈顶(低地址)这段空间称为栈帧(Stack Frame)。
ARM64在函数参数传递时,参数1~参数8 分别保存到 X0~X7 寄存器中 ,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 X0 中。
ARM在参数传递时,参数1~参数4 分别保存到 R0~R3 寄存器中 ,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 R0 中。
我们看下上面程序的反汇编代码,有个地方需要注意,为了观察最原始的汇编代码需要在
Applicataion.mk 里面添加一个选项,否则编译器会优化一些逻辑:可以看到 a b c d e f g h,这8个参数是存放到了 W0 - W7 中,W 是 X 的32 位形式。
对于参数 i 的处理分3步:
是先将栈地址赋值给了 X10,然后将 i 的值存放到 W9 指向的地址里面,结合起来理解就是将 i 的值放到了栈里面。
我们动态的调试一下,观察栈变化:

前面的X0到X7的寄存器变化是符合预期的。
继续往下看,断点走到BL处,发现栈变化:

发现,将 9 的值储存到了 sp 的位置,偏移量为0。说明
[X10,#0x40+i] 计算出来的值就是 [X10],我们可以在这里按下Q键,看真实的汇编:
继续往下看,看跳转到 func 函数里面后栈的变化情况。一直走到 func 的 ret 指令,看栈的内容:
可以看到,栈底首先储存的是第9个参数。
然后是返回地址,就是函数执行完之后需要执行的下一条指令的地址。
然后接着是栈指针,这个栈指针是 main 函数的栈地址,因为func函数执行完之后,需要将栈指针给还原,mian才好继续执行。
然后接着是参数,这是因为函数的逻辑可能需要使用到 X0 到 X7寄存器。所以先将寄存器的值储存到栈中,方便后续获取。
最后是局部变量,它的值也是放到了栈中。










