首先我们来看这样一个函数
int test(int i) {
return i;
}它生成的汇编代码是这样的
test(int):
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov eax, DWORD PTR [rbp-4]
pop rbp
ret首先解释几个寄存器的定义
- rbp 和 rsp 寄存器分别是栈帧基址指针(Base Pointer)和栈指针(Stack Pointer), 就是当前栈帧底的基地址,以及当前栈顶的地址。
- edi 保存函数参数的寄存器
- eax 保存函数返回值的寄存器
我们来逐行看一下这段汇编代码
push rbp: 将当前栈帧基指针rbp压入栈中,用于保存上一个函数的栈帧。mov rbp, rsp: 将当前栈顶指针rsp赋值给rbp,以建立当前函数的新栈帧。rsp现在是上一个栈帧的顶地址,让它作为当前栈帧的基地址。mov DWORD PTR [rbp-4], edi: 将函数参数edi中的值存储到当前栈帧的 4 字节偏移处,也就是局部变量i的位置。mov eax, DWORD PTR [rbp-4]: 将局部变量[rbp-4]的值加载到eax寄存器中,准备作为函数返回值。pop rbp: 恢复上一个函数的栈帧基指针rbp。ret: 函数返回,控制权转移到调用者。
其中1 2 5 6 基本每个函数都有,它们维护了函数调用栈的结构。