服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C语言详尽图解函数栈帧的创建和销毁实现

C语言详尽图解函数栈帧的创建和销毁实现

2022-11-23 12:18利刃Cc C/C++

我们知道c语言中函数都是被调用的,main函数里面能调用其他函数,其实main函数也是被别的函数调用的,下面通过本文给大家分享c语言函数栈帧的创建和销毁过程,一起看看吧

注:本文章所使用的编译器是VS2010,由于不同编译器的函数栈帧与销毁略有差异,所以具体细节请读者自行实践!

 

常见寄存器

寄存器有:eax、ebx、ecx、edx、edi、esi、ebp、esp

其中 ebp 和 esp 是用来维护函数栈帧的,他们里面存放的是地址。

他们维护的是某个正在被调用的函数。通常我们又称 ebp 为栈底指针,称 esp 为栈顶指针

 

基本的汇编语言知识

push:压栈

pop:出栈

mov:若有变量a,b,则把b的值赋给a

ret:返回主程序

call:调用子程序

add:相加

sub:相减

lea:装入有效地址

 

具体实现

我们用一个简单的例子来展示:

#include<stdio.h>
int Add(int x,int y)
{
  int z=0;
  z=x+y;
  return z;
}
int main()
{
  int a=0;
  int b=20;
  int c=0;
  c=Add(a,b);
  printf("%d\n",c);
  return 0;
}

注:每一个函数调用都会在栈区创建一个空间

我们在这里假设从下到上是高地址到低地址的方向

C语言详尽图解函数栈帧的创建和销毁实现

通过我们上述介绍的ebp和esp,我们把他们添加上去后的效果则为:

C语言详尽图解函数栈帧的创建和销毁实现

那么有一个问题:main函数是谁调用的?

为了解决这个问题,我们打开编译器然后进行调试,打开调用堆栈功能

C语言详尽图解函数栈帧的创建和销毁实现

发现这里居然有两个函数,一个是 __tmainCRTStartup(),还有一个是mainCRTStartup()。通过头文件的查找,发现了以下的关系:

C语言详尽图解函数栈帧的创建和销毁实现

main函数被__tmainCRTStartup()调用,而__tmainCRTStartup()被mainCRTStartup()调用。所以,我们在分配空间时,要为__tmainCRTStartup函数以及mainCRTStartup函数分配一块空间。

接下来开始通过反汇编来观察栈帧空间分配:

C语言详尽图解函数栈帧的创建和销毁实现

通过我们之前的了解,在开辟main之前先开辟了__tmainCRTStartup,所以我们来为其分配空间:

C语言详尽图解函数栈帧的创建和销毁实现

先来看前三步,分别是push:压栈和mov:赋值和sub:减法

第一步把ebp放到了栈顶,然后在压栈同时esp会自动向上追踪栈顶,所以esp向上移动一个,第二步是将esp赋给ebp,所以ebp指针指向栈顶,第三步是esp指针的地址减少0E4h(八进制),所以esp指向了上面某一块位置,然后将中间这块空间腾出来让给了main函数,而开辟的大小取决于编译器。

效果如下:

C语言详尽图解函数栈帧的创建和销毁实现

接下来push三次

C语言详尽图解函数栈帧的创建和销毁实现

接下来的四步:lea这步操作就是让[ebp-0E4h]这个值放入edi内,然后通过观察我们可以发现,此时放入新值后的edi所指向的就是对应在进行push三个寄存器ebx、esi、edi操作前的esp的位置,然后将39h赋给ecx,0CCCCCCCCh赋给eax,然后第四步就是将edi地址向下的39h个dword中全部放入0CCCCCCCCh。

C语言详尽图解函数栈帧的创建和销毁实现

这些步骤就开辟了main函数!看接下来的代码:

C语言详尽图解函数栈帧的创建和销毁实现

将10放到了ebp-8的位置,也就是ebp向上八个字节的位置,然后将20放到ebp-20的 位置,将0放到ebp-32的位置,如图:

C语言详尽图解函数栈帧的创建和销毁实现

接下来是add函数的反汇编代码:

C语言详尽图解函数栈帧的创建和销毁实现

这里把ebp-20也就是b的值放到了eax中,然后压栈。接着把ebp-8也就是a 的值放到了ecx中,然后压栈。

C语言详尽图解函数栈帧的创建和销毁实现

然后就是call就跳到了add这个函数的地址处去,注意,该处call后进行一个压栈操作,将add后面一步的地址放在该栈位:

C语言详尽图解函数栈帧的创建和销毁实现

这种做法是为了调用完add后返回时需要找回原来的地址,所以需要在此处压一个地址,以便add跳回时寻址,才能往下执行。接下来才是add函数的内容:

C语言详尽图解函数栈帧的创建和销毁实现

前几步的操作是为了给add函数开辟空间,这和开辟main函数是一样的,所以这里略过:

C语言详尽图解函数栈帧的创建和销毁实现

接下来就是将0赋给ebp-8的位置,然后把ebp+8也就是刚才传参过来的x,放到eax里,然后把ebp+12就是形参y与eax相加,最后把eax放到ebp-8也就是z的位置:

C语言详尽图解函数栈帧的创建和销毁实现

最后看这个:

C语言详尽图解函数栈帧的创建和销毁实现

C语言详尽图解函数栈帧的创建和销毁实现

首先ebp-8也就是z放到eax,这样子就防止销毁add后数据也没了。

然后就是edi、esi、ebx的pop,然后把esp移到ebp的位置,最后弹出ebp。

C语言详尽图解函数栈帧的创建和销毁实现

最后是ret。我们知道,当运行完call指令后会跳转到下面的代码继续执行,这个时候就可以知道当时存的call指令下一条指令地址的用处了,而ret就是让其退出后执行这一操作的代码。

C语言详尽图解函数栈帧的创建和销毁实现

ret执行完后会pop,于是esp又会+4,向下移动,如图:

C语言详尽图解函数栈帧的创建和销毁实现

然后回到main函数

C语言详尽图解函数栈帧的创建和销毁实现

继续执行以下步骤将eax里面的值(就是之前算出的30),mov放入到[ebp-20h]的位置里(也就是放入c中)。

接下来程序运行完后就是main函数的销毁,与之前Add函数销毁步骤大致相同,就不再赘述了。

 

关于栈帧创建与销毁的问答题

C语言详尽图解函数栈帧的创建和销毁实现

到此这篇关于C语言详尽图解函数栈帧的创建和销毁实现的文章就介绍到这了,更多相关C语言函数栈帧内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/lirendada/article/details/124578536

延伸 · 阅读

精彩推荐
  • C/C++C++ 中的this指针详解及实例

    C++ 中的this指针详解及实例

    这篇文章主要介绍了C++ 中的this指针详解及实例的相关资料,this指针是类的一个自动生成、自动隐蔽的私有成员,它存在于类的非静态成员中,指向被调用函...

    C++教程网3772021-05-23
  • C/C++vs2019配置Qt5开发环境(图文教程)

    vs2019配置Qt5开发环境(图文教程)

    本文主要介绍了如何使用visual studi2019配置qt5开发环境,以及创建qt项目,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以...

    杨--9752022-07-11
  • C/C++C++索引越界的解决方法

    C++索引越界的解决方法

    本文主要介绍了C++索引越界的解决方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    Welcom to LyAsano’s blog!4382021-12-10
  • C/C++C语言实现航班售票系统 C语言实现航班管理系统

    C语言实现航班售票系统 C语言实现航班管理系统

    这篇文章主要为大家详细介绍了C语言实现航班售票系统,C语言实现航班管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴...

    Eraser_328392021-08-11
  • C/C++C++OOP对象和类的详细讲解

    C++OOP对象和类的详细讲解

    这篇文章主要介绍了C++面相对象编程中的类与对象的特性与概念,OOP面向对象语言相对C语言这样面相过程的语言来说具有类和对象以及方法这样的特性,需要...

    _Chrome_4612021-12-21
  • C/C++C++继承介绍

    C++继承介绍

    C++继承可以是单一继承或多重继承,每一个继承连接可以是public,protected,private也可以是virtual或non-virtual...

    C++教程网4562020-11-15
  • C/C++详解C++-二阶构造模式、友元

    详解C++-二阶构造模式、友元

    这篇文章主要介绍了C++-二阶构造模式、友元,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着...

    NQian9442021-07-25
  • C/C++C/C++ INI文件操作实现代码

    C/C++ INI文件操作实现代码

    本文章主要为分享C/C++ INI文件操作实现代码,增加注释和修复了一些问题。这里给出完整的实现文件,在需要的地方包含该头文件就好了...

    烈风7822021-08-13