预备
#include <stdio.h>
int addDetail(int a, int b)
{
return a + b;
}
int add(int a, int b)
{
int c;
c = addDetail(a, b);
return c;
}
int main(int argc, char *argv[])
{
int sum;
sum = add(3, 5);
printf("sum = %d\n", sum);
return 0;
}
汇编
main
add
addDetail
基础
- rbp 是基底指针,指向堆栈的起点
- rsp是栈顶指针,指向堆栈的顶点。
- AT&T 语法中的指令格式为
mnemonic source, destination
- .助记符是指令的人类可读名称。
- 源和目标是操作数,可以是立即数、寄存器、内存地址或标签。
- 立即数是常量,并以 a 为前缀
$
。例如,$0x5
以十六进制表示数字 5。 - 寄存器名称以 . 为前缀
流程调用
main_rsp = 0x7fff ffff de40
main_rbp = 0x7fff ffff de60
进入函数add时的操作, 将添加新的栈帧
- 将main的栈底rbp压入栈中
- 再把rbp重新指向rsp寄存器, 进入新的栈帧
- 再rsp减去0x18个字节, 指向栈顶, 中间位栈空间
- 再把函数参数从寄存器中移动到栈空间
参数a = *($rbp - 0x14)
参数b = *($rbp - 0x18)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
add_rsp = 0x7fff ffff de18
add_rbp = 0x7fff ffff de30
进入add函数内部, 再执行另一个函数addDetail前的操作
add参数a 和 b 在这里多复制了一遍, 可以引出右值引用
- 先把add帧栈中的值赋值到edx和eax寄存器中
- 再把exd和eax寄存器中的值赋值到esi和edi中
进入addDetail函数时的操作
// 为什么不申请空间?
- 将add的栈底rbp压入栈中
- 再把rbp重新指向rsp寄存器, 进入新的栈帧
- 再把函数参数从寄存器中移动到栈空间
参数a = *($rbp - 0x4)
参数b = *($rbp - 0x8)
addDetal_rsp = 0x7fff ffff de08
addDetal_rbp = 0x7fff ffff de08
addDetail函数内部
- 把自动变量移动到计算寄存器中, eax(操作运算符, 结果)和 edx
- 相加, eax得到结果
addDetail函数返回操作
没pop前
pop后, 从栈中弹出之前的detail_rbp ,把rbp 覆盖
retq,跳转回返回地址
返回add函数返回处
把返回的函数值赋值到自动变量中
add函数返回操作
防止自动变量消失, 要存到寄存器
leaveq 返回到 rbp被main_rbp覆盖, retq 跳转
main函数返回, 并退出
把寄存器中的值放到main的自动变量中
printf 输出
退出
最后调用了exit