函数调用堆栈(1)

时间:2021-03-31 19:03:27

函数调用:我们先来看看底下的这一段代码:

int sum(int a,int b)
{
int tmp=0;
tmp=a+b;
return tmp;
}
int main()
{
int a=10;
int b=20;
int ret=0;
ret=sum(a,b);
printf("%d\n",ret);
return 0;
}

那么我们考虑几个问题:
1、额,我们都知道函数运行从主函数开始,那么运行到 ret=sum(a,b) 是怎么跳到sum函数的?
2、执行sum函数的时候,是怎么把tmp 的值带回来到主函数并赋值给 ret 的呢?
3、从sum函数返回怎么知道返回到 ret=sum(a,b) 并执行下一条语句,而不是返回到主函数的开始呢?

带着这几个问题,我们一起来探究到底是怎么回事?
程序执行的时候需要用到虚拟地址空间里的栈,把一些进程运行的参数保存到栈中。

我们看看上面程序的汇编代码:注意啊,看不懂下面的代码没关系,会有图解哟,耐心看图解吧。
主函数的反汇编:

int main()
{
012D1880 push ebp
012D1881 mov ebp,esp
012D1883 sub esp,0E4h
012D1889 push ebx
012D188A push esi
012D188B push edi
012D188C lea edi,[ebp-0E4h]
012D1892 mov ecx,39h
012D1897 mov eax,0CCCCCCCCh
012D189C rep stos dword ptr es:[edi]
int a=10;
012D189E mov dword ptr [ebp-4],0Ah
int b=20;
012D18A5 mov dword ptr [ebp-8],14h
int ret=0;
012D18AC mov dword ptr [ebp-0ch],0
ret=sum(a,b);
012D18B3 mov eax,dword ptr [b] //其实就是变量b所在的地址
012D18B6 push eax
012D18B7 mov ecx,dword ptr [a]
012D18BA push ecx
012D18BB call sum (012D1082h)
012D18C0 add esp,8
012D18C3 mov dword ptr [ret],eax
printf("%d\n",ret);

sum函数的反汇编:

int sum(int a,int b)
{
00E91830 push ebp
00E91831 mov ebp,esp
00E91833 sub esp,0CCh
00E91839 push ebx
00E9183A push esi
00E9183B push edi
00E9183C lea edi,[ebp-0CCh]
00E91842 mov ecx,33h
00E91847 mov eax,0CCCCCCCCh
00E9184C rep stos dword ptr es:[edi]
int tmp=0;
00E9184E mov dword ptr [tmp],0
tmp=a+b;
00E91855 mov eax,dword ptr [a]
00E91858 add eax,dword ptr [b]
00E9185B mov dword ptr [tmp],eax
return tmp;
00E9185E mov eax,dword ptr [tmp]
}
00E91861 pop edi
00E91862 pop esi
00E91863 pop ebx
00E91864 mov esp,ebp
00E91866 pop ebp
00E91867 ret

我们一点一点分析:
图一:
函数调用堆栈(1)
图二:
函数调用堆栈(1)
图三:
函数调用堆栈(1)
图四:
函数调用堆栈(1)
图五:
函数调用堆栈(1)
调用堆栈就是这样啦!
总结一下函数调用的过程:
函数调用堆栈(1)