前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C++函数调用过程深入分析

C++函数调用过程深入分析

作者头像
C语言与CPP编程
发布于 2021-04-16 08:58:28
发布于 2021-04-16 08:58:28
2.5K0
举报
文章被收录于专栏:c语言与cpp编程c语言与cpp编程

0. 引言

函数调用的过程实际上也就是一个中断的过程,那么C++中到底是怎样实现一个函数的调用的呢?参数入栈、函数跳转、保护现场、回复现场等又是怎样实现的呢?本文将对函数调用的过程进行深入的分析和详细解释,并在VC 6.0环境下进行演示。分析不到位或者存在错误的地方请批评指正,请与作者联系。

首先对三个常用的寄存器做一下说明,EIP是指令指针,即指向下一条即将执行的指令的地址;EBP为基址指针,常用来指向栈底;ESP为栈指针,常用来指向栈顶。

看下面这个简单的程序并在VC 6.0中查看并分析汇编代码。

图1

1. 函数调用

g_func函数调用的汇编代码如图2:

图2

首先是三条push指令,分别将三个参数压入栈中,可以发现参数的压栈顺序是从右向左的。这时我们可以查看栈中的数据验证一下。如图3所示,从右边的实时寄存器表中我们可以看到ESP(栈顶指针)值为0x0012FEF0,然后从中间的内存表中找到内存地址0x0012FEF0处,我们可以看到内存中依次存储了0x00000001(即参数1),0x00000002(即参数2),0x00000003(即参数3),即此时栈顶存储的是三个参数值,说明压栈成功。

图3

然后可以看到call指令跳转到地址0x00401005,那么该地址处是什么呢?我们继续跟踪一下,在图4中我们看到这里又是一条跳转指令,跳转到0x00401030。我们再看一下地址0x00401030处,在图5中可以看到这才是真正的g_func函数,0x00401030是该函数的起始地址,这样就实现了到g_func函数的跳转。

图4

图5

2. 保存现场

此时我们再来查看一下栈中的数据,如图6所示,此时的ESP(栈顶)值为0x0012FEEC,在内存表中我们可以看到栈顶存放的是0x00401093,下面还是前面压栈的参数1,2,3,也就是执行了call指令后,系统默认的往栈中压入了一个数据(0x00401093),那么它究竟是什么呢?我们再看到图3,call指令后面一条指令的地址就是0x00401093,实际上就是函数调用结束后需要继续执行的指令地址,函数返回后会跳转到该地址。这也就是我们常说的函数中断前的“保护现场”。这一过程是编译器隐含完成的,实际上是将EIP(指令指针)压栈,即隐含执行了一条push eip指令,在中断函数返回时再从栈中弹出该值到EIP,程序继续往下执行。

图6

继续往下看,进入g_func函数后的第一条指令是push ebp,即将ebp入栈。因为每一个函数都有自己的栈区域,所以栈基址也是不一样的。现在进入了一个中断函数,函数执行过程中也需要ebp寄存器,而在进入函数之前的main函数的ebp值怎么办呢?为了不被覆盖,将它压入栈中保存。

下一条mov ebp, esp 将此时的栈顶地址作为该函数的栈基址,确定g_func函数的栈区域(ebp为栈底,esp为栈顶)。

再往下的指令是sub esp, 48h,指令的字面意思是将栈顶指针往上移动48h Byte。那为什么要移动呢?这中间的内存区域用来做什么呢?这个区域为间隔空间,将两个函数的栈区域隔开一段距离,如图7所示。而该间隔区域的大小固定为40h,即64Byte,然后还要预留出存储局部变量的内存区域。g_func函数有两个局部变量x和y,所以esp需移动的长度为40h+8=48h。

图7

接下来的几行指令(如下)是将刚才留出的48h的内存区域赋值为0CCCCCCCCh。

00401039 lea edi,[ebp-48h]

0040103C mov ecx,12h

00401041 mov eax,0CCCCCCCCh

00401046 rep stos dword ptr [edi] 。

接下来三条压栈指令,分别将EBX,ESI,EDI压入栈中,这也是属于“保护现场”的一部分,这些是属于main函数执行的一些数据。EBX,ESI,EDI分别为基址寄存器,源变址寄存器,目的变址寄存器。

3. 执行子函数

继续往下看,接下来是局部变量的x和y的赋值,看汇编指令中是怎样去计算x和y的内存地址的呢?如图8所示,是基于ebp去计算的,分别是[ebp-4]和[ebp-8]。我们查看内存表可以看到相应的内存区域已经存入了0x11111111和0x22222222。

图8

此时我们对整个内存区域中存储的内容应该非常清晰了(如图9所示)。

图9

4. 恢复现场

这时子函数部分的代码已经执行完,继续往下看,编译器将会做一些事后处理的工作(如图10所示)。首先是三条出栈指令,分别从栈顶读取EDI,ESI和EBX的值。从图9的内存数据分布我们可以得知此时栈顶的数据确实是EDI,ESI和EBX,这样就恢复了调用前的EDI,ESI和EBX值,这是“恢复现场”的一部分。

图10

第四条指令是mov esp, ebp 即将ebp的值赋给esp。那这是什么意思呢?看看图9的内存数据分布,我们就能很明白了,这条语句是让ESP指向EBP所指的内存单元,也就是让ESP跳过了一段区域,很明显跳过的恰好是间隔区域和局部数据区域,因为函数已经退出了,这两个区域都已经没有用处了。实际上这条语句是进入函数时创建间隔区域的语句 sub esp, 48h的相反操作。

再往下是pop ebp,我们从图9的内存数据分布可以看出此时栈顶确实是存储的前EBP值,这样就恢复了调用前的EBP值,这也是“恢复现场”的一部分。该指令执行完后,内存数据分布如图11所示。

图11

再往下是一条ret指令,即返回指令,他会怎么处理呢?注意在执行ret指令前的ESP值和EIP值(如图12所示),ESP指向栈顶的0x00401093,EIP的值是0x0040105C(即ret指令的地址)。

图12

执行ret指令后我们来查看ESP和EIP值(如图13所示),此时ESP为0012FEF0,即往下移动了4Byte。显然此处编译器隐含的执行了一条pop指令。再来看一下EIP的值,变为了0x00401093,这个值怎么这么熟悉呢!它实际上就是栈顶的4Byte数据,所以这里隐含执行的指令应该是pop eip。而这个值就是前面讲到过的,在调用call指令前压栈的call的下一条指令的地址。从图13中可以看出,正是因为EIP的值变成了0x00401093,所以程序跳转到了call指令后面的一条指令,又回到了中断前的地方,这就是所谓的恢复断点。

图13

还没有完全结束,此时还有最后一条指令add esp, 0Ch。这个就很简单了,从图13中可以看出现在栈顶的数据是1,2,3,也就是函数调用前压入的三个实参。这是函数已经执行完了,显然这三个参数没有用处了。所以add esp, 0Ch就是让栈顶指针往下移动12Byte的位置。为什么是12Byte呢,很简单,因为入栈的是3个int数据。这样由于函数调用在栈中添加的所有数据都已清除,栈顶指针(ESP)真正回到了函数调用前的位置,所有寄存器的值也恢复到了函数调用之前。

https://blog.csdn.net/dongtingzhizi/article/details/6680050

- EOF -

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 C语言与CPP编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
2 条评论
热度
最新
每月50次的限制
每月50次的限制
11点赞举报
昨天晚上我也看见了,当时太晚了就睡了,今天打开网页看这一条又删掉了。
昨天晚上我也看见了,当时太晚了就睡了,今天打开网页看这一条又删掉了。
回复回复点赞举报
推荐阅读
【CodeBuddy】编程最佳搭子,10分钟手搓网页版2048小游戏
在以前,我们通常是一个屏幕写代码,一个屏幕看文档,剩下的地方看预览,而看文档的这个屏幕压力最大:数十个标签页杂乱堆砌,代码写得正爽呢忘记了某个API用法,又得切回浏览器一个个找,去必应一个个搜......
Ar-Sr-Na
2025/05/12
900
中国版Cursor | 我用CodeBuddy Craft 3分钟复刻NFC经典游戏
做为一个懒人程序员,从AI迅速发展开始就一直在寻找能够替代码农编码的AI工具。从最早的GitHub Copilot,到CodeGeeX,再到Bito。紧接着后面的Cursor,Trae等等。技术生态发展之迅猛,让牛马们直呼学不完。
有一只柴犬
2025/05/13
1731
中国版Cursor | 我用CodeBuddy Craft 3分钟复刻NFC经典游戏
前端开发的春天!腾讯云CodeBuddy+Figma MCP快速还原设计稿
大家好,我是星哥,之前介绍过什么是MCP,在本地配置MCP今天继续介绍使用腾讯云CodeBuddy+Figma MCP快速还原设计稿。
星哥玩云
2025/05/16
300
前端开发的春天!腾讯云CodeBuddy+Figma MCP快速还原设计稿
AI 编程神器 CodeBuddy 体验报告:对话式开发 + 智能补全,真香!
在当今 AI 技术蓬勃发展的编程领域,各类智能编程工具不断涌现,为开发者们带来了全新的编程体验。腾讯云推出的 CodeBuddy 便是其中一款极具创新性的工具,它凭借强大的功能和出色的性能,在众多编程辅助工具中脱颖而出。
架构师精进
2025/05/13
1820
AI 编程神器 CodeBuddy 体验报告:对话式开发 + 智能补全,真香!
CodeBuddy优雅入场!没有最强只有更强
在代码的世界里,键盘的敲击声曾是开发者思维的唯一外化,而今,一种新的“协作旋律”正在改变这一切,AI代码助手正从工具进化为开发者的“第二大脑”。从自动补全一行代码到理解项目全局逻辑,从生成测试用例到优化算法性能,这些智能助手不仅让编码效率呈指数级提升,更在重塑软件开发的本质:当机器学会“理解”需求、“创造”代码,甚至预判错误,程序员的角色正从“码农”蜕变为“架构师”。
闫同学
2025/05/13
2222
【人工智能】自然语言编程革命:腾讯云CodeBuddy实战5步搭建客户管理系统,效率飙升90%
在代码量激增、技术迭代加速的今天,开发者面临两大核心挑战:效率瓶颈与质量风险。腾讯云代码助手CodeBuddy通过AI重构开发流程,为开发者提供三重核心价值:
蒙奇D索隆
2025/05/13
1251
【人工智能】自然语言编程革命:腾讯云CodeBuddy实战5步搭建客户管理系统,效率飙升90%
CodeBuddy腾讯云代码助手:我的首席编程搭子
在编程的世界里,一个得力的助手往往能让我们的工作事半功倍。最近,我有幸体验了腾讯云推出的CodeBuddy代码助手,这款工具不仅集成了众多实用的功能,更在最新升级中引入了全新软件开发智能体Craft、国内首个支持MCP(Multi-Cloud Portability,多云可移植性)的代码助手等创新特性。接下来,我将分享我的使用体验,以及CodeBuddy如何成为我工作中的首席编程搭子。
熊猫钓鱼
2025/05/08
3160
CodeBuddy腾讯云代码助手:我的首席编程搭子
腾讯云代码助手CodeBuddy初体验
大模型的应用如火如荼,辅助编程是其中一个很适合大模型发挥的场景,通过交互提供给开发人员编程相关的辅助,降低了开发门槛,解放劳动力,当然这是双刃剑,生成的代码是否安全可靠,需要格外关注。
bisal
2025/05/13
1940
腾讯云代码助手CodeBuddy初体验
半小时快速入门Spring AI:使用腾讯云编程助手CodeBuddy 开发简易聊天程序
随着人工智能(AI)技术的飞速发展,越来越多的开发者开始探索如何将AI集成到自己的应用中。人工智能正在迅速改变各行各业的工作方式,从自动化客服到智能推荐系统,AI的应用几乎无处不在。Spring AI作为一种开源框架,提供了强大的功能,使开发者能够轻松集成AI到Spring Boot应用中。结合腾讯云编程助手CodeBuddy的帮助,开发者不仅可以大幅度加快开发速度,还能减少常见的开发错误。CodeBuddy通过自动化代码生成和错误提示,特别适合那些对AI技术感兴趣却又没有太多开发经验的用户。
努力的小雨
2025/05/13
1910
程序员福音!CodeBuddy Craft智能体,一行代码没写就下班?
“我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:
Lion 莱恩呀
2025/05/02
2051
程序员福音!CodeBuddy Craft智能体,一行代码没写就下班?
手把手教你如何利用CodeBuddy编写属于自己的AI助手
接下来就和大家介绍这款代码助手的神奇之处吧,据说腾讯云代码助手(CodeBuddy)是腾讯自研的AI编程提效工具,凭借腾讯混元与 DeepSeek 混合模型,专为开发者打造。CodeBuddy不仅支持200+编程语言、兼容多种主流IDE,是国内首个支持 MCP 的代码助手,还为开发者提供开发智能体 Craft、智能代码补全、单元测试、代码诊断等多项高效功能,帮助开发者在编码过程中节省时间、提升效率。目前腾讯内部 85% 以上的开发者已使用 CodeBuddy,编码时间平均缩短 40% 以上,AI生成代码占比超四成,研发效率提升超 16%。
芯动大师
2025/05/14
840
手把手教你如何利用CodeBuddy编写属于自己的AI助手
中国版 Cursor---腾讯云 CodeBuddy | 从安装VSCode到数独小游戏问世
在正文开始之前,先引入一下故事背景:其实,自己最初选择编程行业,也是想自己开发一个小游戏啥的,主要是为了娱乐。没想到进入了编程行业之后,就变成了后端Java 开发者,虽然可能和自己期望的有点差距,但是在Java 语言行业待久了,也就习惯了。只是心里对于做一个小游戏的念想一直还在。恰逢中国版Cursor—- 腾讯云CodeBuddy 来了,对于小游戏的实现也看到了曙光,下面闲话少说,先来介绍一下我们今天的主角。什么是CodeBuddy?
六月的雨在Tencent
2025/05/13
3480
揭秘 CodeBuddy:全方位测评后,我愿称它为开发者 “梦中情辅”
我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴
Undoom
2025/05/12
1520
中国版Cursor:CodeBuddy腾讯云代码助手使用体验
我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴”
卷福同学
2025/05/14
4330
中国版Cursor:CodeBuddy腾讯云代码助手使用体验
中国版 Cursor:CodeBuddy
我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴
程序员NEO
2025/05/13
1830
中国版 Cursor:CodeBuddy
三句话让CodeBuddy给我写一个MC MOD!堪称中国版 Cursor!
众所周知~我是个超级MC迷。其实早就想做一个属于自己的模组了,但是一直没时间学Java,也不知道怎么下手,所以就一直拖着。
MGS浪疯
2025/05/13
1450
三句话让CodeBuddy给我写一个MC MOD!堪称中国版 Cursor!
中国人自己的Cursor?腾讯CodeBuddy从零打造家庭相册
大家好,我是星哥,作为一个二手的高级程序猿,五一出去游玩跟家人的照片想要做个一个web页面分享给家人,今天就用出品的腾讯云代码助手(CodeBuddy)一行代码都不用自己写,看能不能实现的我小愿望。
星哥玩云
2025/05/13
1000
中国人自己的Cursor?腾讯CodeBuddy从零打造家庭相册
当代码有了灵魂:一名全栈工程师的CodeBuddy手记
本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴
熊猫钓鱼
2025/05/17
00
CodeBuddy终极测评:中国版Cursor的开发革命(含安装指南+HTML游戏实战)
腾讯云CodeBuddy是一款基于混元大模型和DeepSeek双引擎的AI编程辅助工具,提供智能代码补全、端到端代码生成和企业级功能。其核心优势包括中文SQL优化、Figma设计稿转代码等特色功能,支持VSCode等IDE快速安装。通过实战案例展示了从需求到代码生成的完整流程,并具备代码翻译、性能优化和团队协作能力,在格式化、代码重构等场景下表现优异,是提升开发效率的强力助手。
海拥
2025/05/13
2511
文科生0基础使用Codebuddy,生成“哆啦A梦”机器人产品介绍网站
“我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴”;
Vivitalk
2025/05/11
1621
文科生0基础使用Codebuddy,生成“哆啦A梦”机器人产品介绍网站
推荐阅读
相关推荐
【CodeBuddy】编程最佳搭子,10分钟手搓网页版2048小游戏
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档