函数调用堆栈的过程(转载收藏)
函数调用堆栈的过程(转载收藏)
原文链接:https://blog.csdn.net/qq_41431406/article/details/96446312
#include<stdio.h>
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("ret=%d\n",ret);
return 0;
}
反汇编如下所示:
解析后的反汇编:
画出在栈中的整个过程:
- 总结:
- 1、函数的运行都是在栈上开辟内存。
- 2、栈是通过esp(栈顶指针)、ebp(栈底指针)两个指针来标识的。
- 3、对于栈上的访问都是通过栈底指针的偏移来访问的。
- 4、在call一个函数时,有两件事情要做:先将调用函数的下一行指令的地址压入栈中;再进行跳转。
- 5、在函数调用时检查函数是否申明、函数名是否相同、函数的参数列表是否匹配、函数的返回值多大。
①如果【函数的返回值<=4个字节】,则返回值通过寄存器eax带回。
②如果【4<函数的返回值<=8个字节】,则返回值通过两个寄存器eax和edx带回。
③如果【函数的返回值>8个字节】,则返回值通过产生的临时量带回。 - 6、函数结束ret指令干了两件事:先出栈;再将出栈的值放到CPU的PC寄存器中。因为PC寄存器中永远放的是下一次执行指令的地址,所以就顺理成章的在函数调用完之后依旧接着原来的代码继续执行。
函数调用:
#include<stdio.h>
int sum(int a,int b)
{
/*
push ebp
mov ebp,esp
sub esp,44h
push ebx
push esi
push edi
lea edi,[ebp-44h]
mov ecx,11h
mov eax,0xccccccch
rep stos ===>[esp,ebp]=0xcccccccc
*/
int tmp=0;//mov dword ptr[ebp-4],0
tmp=a+b;
/*
mov eax,dword ptr[ebp+8]
add eax,dword ptr[ebp+0ch]
mov dword ptr[ebp-4],eax
*/
return tmp;//mov dword ptr[ebp-4],eax
}
/*
mov eax,dword ptr[ebp-4]
mov esp,ebp
pop ebp
ret
*/
int main()
{
/*
push ebp
mov ebp,esp
sub esp,44h
push ebx
push esi
push edi
lea edi,[ebp-44h]
mov ecx,11h
mov eax,0xccccccch
rep stos ===>[esp,ebp]=0xcccccccc
*/
int a=10;//mov dword ptr[ebp-4],0Ah
int b=20;//mov dword ptr[ebp-8],14h
int ret=0;//mov dword ptr[ebp-0Ch],0
ret=sum(a,b);
/*
mov eax,ptr[ebp-8]
push eax
mov ebx,ptr[ebp-4]
push ebx
push ecx
call sum
add esp,8
mov dword ptr[ebp-0ch],eax
*/
printf("ret=%d\n",ret);
return 0;
}
简单过程:
1:压入实参 形参初始化 自右向左
2:压下一行指令地址
3:压调用方栈底地址
4:跳转到被调用方函数栈帧
5:被调用方函数活动开辟空间