函数参数从右向左依次压栈push,call 要先把下一行指令 压栈,
根据如下代码思考两个问题:
问题一:main函数调用sum,sum执行完以后,怎么知道回到哪个函数中?
问题二:sum函数执行完,回到main以后,怎么知道从哪一行指令继续运行的?
#include <iostream>
using namespace std;
int sum(int a, int b)
{
int temp = 0;
temp = a + b;
return temp;
}
int main()
{
int a = 10;
int b = 20;
int ret = sum(a, b);
cout << "ret:" << ret << endl;
return 0;
}
ebp
是栈帧的栈底(高地址),esp
是永远指向栈顶(低地址)
首先程序进入main函数要在虚拟地址空间开展栈帧,下面两句代码将数据入栈(放入栈底),ret先压入栈中,注释为汇编代码
int a = 10; // mov dword ptr[ebp-4], 0Ah
int b = 20; // mov dword ptr[ebp-4], 014h
函数调用时,按参数列表从右往左压栈(栈顶esp进入)。int ret = sum(a, b); 需要执行的汇编如下
mov eax, dword ptr[ebp-8] // 将b数据放入寄存器eax中
push eax // 压入栈顶之上,并且移动栈顶指针esp
mov eax, dword ptr[ebp-4] // 将a数据放入寄存器eax中
push eax
此时栈帧如下图:
然后会执行
call sum // 进入sum函数了
下面两行汇编暂时不执行
add esp, 8 # 栈顶压入 int ret = sum(a, b);的下一行指令地址,假设地址为0x08124458,回答问题2
mov dword ptr[ebp-0Ch], eax
此时进入sum函数了,在进入函数内第一条指令前(int temp = 0;
)还有几条汇编需要执行,用于分配栈空间
push ebp # 压入main函数栈帧的栈底指针
mov ebp, esp # ebp = esp
紧接着执行 sub esp, 4Ch
,即esp -= 4Ch
功能为给sum
函数开辟栈空间,随后若是vs则汇编使用循环初始化栈空间数据都为0xCCCCCCCC
,若是gcc或g++则不会初始化。
注:
int a;
cout<<a<<endl; // 输出-858993460 也就是0xCCCCCCCC
然后是执行sum函数内三行代码
int temp = 0; // mov eax, dword ptr[ebp+0Ch]
temp = a + b; // 执行如下两条汇编,完成了a+b运算存入寄存器eax中
// mov eax, dword ptr[ebp+0Ch]
// add eax, dword ptr[ebp+8]
// mov dword ptr[ebp-4], eax // 将a+b存入temp
return temp; // mov eax, dword ptr[ebp-4] 将值存入eax带出函数返回,eax = 30
然后sum函数右括号之前也会执行一系列汇编
mov esp, ebp // esp = ebp,即回退栈帧
pop ebp
栈顶出栈,栈顶指针esp
下移,并把值给ebp
,即上图的0x0018ff40
,ebp
又回到main函数栈帧底
随后执行 ret
指令 出栈,把栈顶值(main需要执行的下一条指令地址)存入CPU的PC
寄存器
然后开始执行
add esp, 8 // 假设地址为0x08124458,作用是传入函数的参数出栈
mov dword ptr[ebp-0Ch], eax
最终就得到了计算的结果啦!