函数调用堆栈的过程

分析函数的调用过程,以一段代码为例:

#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. 被调用方函数活动开辟空间

 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值