首先我们来看这样一个函数
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 基本每个函数都有,它们维护了函数调用栈的结构。