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

Posted CPP开发者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++函数调用过程深入分析相关的知识,希望对你有一定的参考价值。

(给CPP开发者加星标,提升C/C++技能)

来源:CSDN - 洞庭小哥
https://blog.csdn.net/dongtingzhizi/article/details/6680050

0. 引言

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

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

图1


1. 函数调用

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

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

图2

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

图3

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

图4

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

图5

2. 保存现场

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

图6

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

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

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

图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. 执行子函数

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

图8

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

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

图9

4. 恢复现场

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

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

图10

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

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

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

图11

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

图12

图13

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

结束!

- EOF -


推荐阅读   点击标题可跳转

1、

2、

3、


关注『CPP开发者』

看精选C++技术文章 . 加C++开发者专属圈子

↓↓↓


点赞和在看就是最大的支持❤️

以上是关于C++函数调用过程深入分析的主要内容,如果未能解决你的问题,请参考以下文章

C++中一个函数被调用的完整过程分析

Java技术专题「原理专题」深入分析Java中finalize方法的作用和底层原理

深入了解C++ (13) | 走近vtprvtbl,揭秘动态多态

逆向分析-之深入理解函数

转深入理解递归函数的调用过程

C++ 内存布局:深入理解C++内存布局