C&C++函数调用过程

14 篇文章 0 订阅

调用函数主要关注三个方面分别是函数名,返回值和参数列表,我接下来将会深入底层讲解调用函数的过程。

调用函数的过程主要有四方面,①函数参数代入,②函数栈帧开辟,③函数返回值,④函数栈帧回退

首先来看一段简单的c文件代码,和它的汇编码,只需简单浏览即可:

源码:

int fun1(int a, int b)
{
	int c = a + b;
	return c;
}

int main()
{
	int a = fun1(10, 20);

	return 0;
}

 汇编码:

main函数

int main()
{
00C31410  push        ebp  
00C31411  mov         ebp,esp  
00C31413  sub         esp,0CCh  
00C31419  push        ebx  
00C3141A  push        esi  
00C3141B  push        edi  
00C3141C  lea         edi,[ebp-0CCh]  
00C31422  mov         ecx,33h  
00C31427  mov         eax,0CCCCCCCCh  
00C3142C  rep stos    dword ptr es:[edi]  
	int a = fun1(10, 20);
00C3142E  push        14h  
00C31430  push        0Ah  
00C31432  call        fun1 (0C31127h)  
00C31437  add         esp,8  
00C3143A  mov         dword ptr [a],eax  

	return 0;
00C3143D  xor         eax,eax  
}
00C3143F  pop         edi  
00C31440  pop         esi  
00C31441  pop         ebx  
00C31442  add         esp,0CCh  
00C31448  cmp         ebp,esp  
00C3144A  call        __RTC_CheckEsp (0C3113Bh)  
00C3144F  mov         esp,ebp  
00C31451  pop         ebp  
00C31452  ret  

fun1函数

int fun1(int a, int b)
{
009813D0  push        ebp  
009813D1  mov         ebp,esp  
009813D3  sub         esp,0CCh  
009813D9  push        ebx  
009813DA  push        esi  
009813DB  push        edi  
009813DC  lea         edi,[ebp-0CCh]  
009813E2  mov         ecx,33h  
009813E7  mov         eax,0CCCCCCCCh  
009813EC  rep stos    dword ptr es:[edi]  
	int c = a + b;
009813EE  mov         eax,dword ptr [a]  
009813F1  add         eax,dword ptr [b]  
009813F4  mov         dword ptr [c],eax  
	return c;
009813F7  mov         eax,dword ptr [c]  
}
009813FA  pop         edi  
009813FB  pop         esi  
009813FC  pop         ebx  
009813FD  mov         esp,ebp  
009813FF  pop         ebp  
00981400  ret  

首先知道ebp为栈底寄存器,esp为栈顶寄存器。push为操作,操作方式为在esp中的栈顶存放数据,栈顶上移。

在查看fun函数参数如何代入之前,我们先看一下main的栈顶和栈底

(1)函数参数代入

两次push后,参数就被放在了main函数的栈顶,且入栈为从右往左,效果如下:

(2)fun函数栈帧开辟

 

 可以看到,call就相当于调用函数,这里重新设置了栈底ebp和栈顶esp,过程如下:

查看fun函数的开辟栈帧的过程会发现它与main函数的开辟及其类似,其实,main函数的下面也有主函数参数,也就是可以把main函数也看做为一个普通函数。

(3)函数返回

利用寄存器带回,将寄存器的值写入接收返回值的常量

(4)栈帧回退

将fun的栈顶指向fun的栈底:

mian函数中:esp移动8位,消除参数

现在就回到了main函数的栈顶。

(5)其他问题

①因为参数大小不同,8字节及以上的参数采用的是提前在栈顶开辟内存,以保存大字节的参数。

②返回8字节及以上的返回值也是采用提前开辟内存的方法。

③有三种不同的约定调用方式,分别为__cedel、__stdcall、__fastcall,这三种方式有一些细节的不同,但是思想相同,本文讲的是__cedel方式。

  • 16
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值