| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> 【C语言】你知道程序是如何调用函数的吗? -> 正文阅读 |
|
[C++知识库]【C语言】你知道程序是如何调用函数的吗? |
目录 ? ? ? ? 一个.c文件在调用函数的时候(包括main 函数),其内存中的栈区有什么变化?要压栈、出栈哪些寄存器呢?函数的参数是如何进行传递的呢?函数调用结束之后栈区又是如何变化的呢?本文通过使用汇编语言,对这些内容进行了较为详细的剖析。 1.函数栈帧的含义概念?? ? ? ??首先,栈的概念想必不需要过多解释,那么什么是栈帧?引用百度百科:C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。从这句话中,可以提炼以下几点信息: · 栈帧是一块因函数运行而临时开辟的空间。 ? ? ? ? 我们知道,C语言的内存区分成了 静态区、栈区、堆区,函数栈帧无疑是在栈区创建和销毁的,所以其要符合栈“后进先出”的特点。 要用到的汇编语言的知识? ? ? ? 在这里使用汇编语言方面知识的原因是:通过它,我们可以深入底层了解一个程序是如何运行的,在何时——什么东西压栈,什么东西出栈,寄存器(汇编语言中一些用来暂时存储数据的东西)如何变化等等。这些都是C语言无法直观体现的,我们可以通过Visual Stdio 的在调试时的反汇编功能,将C语言代码转换成汇编语言代码,以便更好地观察。(另,C语言也是汇编语言编写的。)所以,简单地说,本文主要是在分析汇编语言的执行过程。 ? ? ? ? 我们首先要了解几个汇编语言方面的东西,其中ESP和EBP时专门维护函数栈帧的,分别指向栈顶和栈底:
示例? ? ? ? 比如,我们写下一个如下的C语言程序,非常容易,只有main() 函数和一个 Add() 函数,主函数里面调用了 Add() 。
? ? ? ? 那么,一开始调用主函数的时候,主函数的函数栈帧就压栈;然后在主函数里面,调用了Add() 函数,此时Add() 的函数栈帧也要压栈。那么现在面临一个问题,是维护Add() 函数,还是维护main() 函数,亦或两者都维护? 2.理解栈帧2.1 main函数栈帧的创建? ? ? ? 实际上,main() 函数也是由其他函数调用的,其调用链条如下: ? ? ? ? 创建main函数的函数栈帧代码如下,汇编语言的注释是用 ; 所以这里 ; 后面的内容是注释,帮助理解代码。
第一行? ? ? ? ? 我们来开始逐句剖析上方代码,首先执行第一行(图中红色圆圈圈出来的黄色箭头,表示已经执行完其上一行,按F10调试就执行当前行),由于是压栈操作,所以esp的值会有所变化,如下图右边监视窗口,esp的值(十六进制显示的)相较之前改变了,所以变成红色: ? ? ? ? 如下,ebp压栈,同时esp上移: 第二行 ? ? ? ? ?该行是将esp的值赋给ebp,效果也如下图,右边监视窗口的红色部分所示。 ? ? ? ? 如下,将esp的值赋给ebp之后,ebp和esp指向同一块地方: 第三行 ? ? ? ? 该行是将esp的值减去0E4h(十六进制),得到的结果赋给esp,如下图。 ? ? ? ? ?如图所示,由于图中从下往上是地址高处到地址低处,所以esp值变小,实际上图中是上移。并且,现在ebp和esp维护的空间,就是main函数的函数栈帧: 第四行 ? ? ? ? 压栈,压入ebx,改变栈顶指针esp的值。 ? ? ? ? 如下,压栈,esp上移: 第五行 ? ? ? ? 压入esi,改变esp的值。 ? ? ? ? 如下,和上一步类似: 第六行 ? ? ? ? 压入edi,改变esp的值。? ? ? ? ? 和上一步也类似: 第七行 ? ? ? ? 将[ebp-24h] 表示的地址赋值给edi。 ? ? ? ? 这里就是把 edi 里面的值改变,从函数栈帧看不出什么,看上面的监视图就可以直到确实是改变了。 最后三行 ? ? ? ? 如之前代码里的注释所说。 ? ? ? ? 如下,两个箭头指示的值是一样的,其代表的是edi所表示的地址,从该地址开始,往后9个dw(double word 双字,一个双字等于四个字节)的内容,都赋值为cccccccc (十六进制)。 ? ? ? ? 这三行代码效果如下: ? ? ? ? 整个过程可以用一张动图生动形象地展示: 2.2 局部变量的创建? ? ? ? 接下来,我们在汇编代码中鼠标右击,然后将下图红色箭头所指示的"显示符号名" 的勾去掉。 ? ? ? ? 发生改变的是下图中红色圆圈圈出来的,可以看出,原本所有的变量名,都变成了寄存器减去某个十六进制数字。他们实际上是等价的,即变量的地址就等于替换后的地址。 ? ? ? ? 接下来分析局部变量创建过程。
? ? ? ? 如下图,可以通过两个红色箭头看到,右边监视的ebp的值就是左边 地址处的箭头指向的地址,说明这就是ebp的地址,然后减去八位,再根据栈从下往上使用以及Visual Stdio小端存储的特点,就成了内存区里面红色方框框出来的内容。(注意,比如 cc cc cc cc ,cc占据的是一个字节的空间,四个cc 就占据四个字节,而汇编语言中,地址-1,只跳过一个c,所以ebp-8是跳过8个c,即四个字节) ? ? ? ? 如下,图中一个小格子代表四个字节,不难看出,变量a存储的位置,在栈底指针往上跳过四个字节的地方。 ? ? ? ? 然后创建局部变量b,通过内存图可以看出,变量b和变量a是间隔八个字节的: ? ? ? ? 如下图: 2.3 函数传参? ? ? ? 代码如下:
? ? ? ? 执行前两行代码,确实将变量b的值赋给了eax,然后eax引起的压栈导致了esp改变: ? ? ? ? 如下图,不要忘了eax里面的值和变量b是一样的哦: ? ? ? ? 执行后两行代码: ? ? ? ? 其效果和前两行类似,同时ecx里面存的是变量a的值: 2.4 调用函数? ? ? ? 上面的内容执行完之后,要执行如下语句,其意思是,执行?002C10B4 地址处的内容:
? ? ? ? 然后我们将其滑倒该地,发现是这样的,意思是跳到002C1740地址处: ? ? ? ? ?又找到该地址,发现如下,所以,通过这两步调用Add() 函数,如下红色部分,和创建main函数的函数栈帧类似,实际上就是创建了Add() 的函数栈帧: ? ? ? ? 效果如下,建立了Add函数的函数栈帧: ? ? ? ? 红色个方框后面两行代码不是很重要,是用来检查bug的,如下代码和图片:
? 2.5 函数返回?? ? ? ? 函数返回:
? ? ? ? 第一行代码:?将ebp+8 地址处的数据放到eax?。 ? ? ? ? 第二行代码:将ebp+0Ch 地址处的数据和eax相加,结果存到eax里面。 ? ? ? ? 如下图中,由于图片从下往上是地址从高到低,所以图片中ebp+8是在ebp下方。实际上就是ecx和eax的值相加,然后存到eax里面。eax里面存储变量b的值,ecx里面存储变量a的值,最后eax的值就是变量a、b之和。并且eax是不会随着Add() 函数的函数栈帧销毁而改变值。 ? ? ? ? 通过监视也可以看出,eax的值变成0x0000001e,转换成十进制就是30。
? ? ? ? ?就是出栈、赋值等等,结果如下,回到了调用Add() 函数之前的状态: ? ? ? ? 然后执行main() 函数后续代码代码,如下图红色框出: ? ? ? ? 第一行:esp加8,即esp在途中向下移动四个字节。 ? ? ? ? 第二行,将eax的值赋给ebp-20h 地址处。 ? ? ? ? 执行完之后,调试图如下,通过对比两个红色方框的内容,左边红色方框的地址,和右边&c 的值一样,说明那就是变量c 存储的地方,其值也是变量c 的值: ? ? ? ? 示意图如下: ? ? ? ? 通过对函数栈帧创建、销毁过程的剖析使我们不仅了解计算机做了什么,还了解了它是如何做的。通过函数栈帧尝试解析递归等问题相信也会更加直观。由于本人水平有限,不足之处还请大家多多指教。 |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/22 19:10:28- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |