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

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

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

C语言函数栈帧的创建与销毁详解

2022-09-27 15:29tjh94512 C/C++

这篇文章主要为大家详细介绍了C语言函数栈帧的创建与销毁,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

前言

大家在学习的时候一定有以下困惑: 局部变量是怎么创建的?为什么局部变量的值是随机值?函数是怎么传参?传参的顺序是怎样的?形参与实参是什么关系?函数调用是怎么做到的?函数调用完成不是销毁了吗,如何带回的返回值?

以上这些都可以通过了解函数栈帧的创建与销毁来理解。接下来我就带大家来了解函数栈帧的创建与销毁。

本次使用的编辑器是VS2013,因为越先进的编辑器,越不容易观察到底层。好了,我们回到正题。

 

一、函数栈帧是什么?

 

1.寄存器

寄存器里有eax,ebx,ecx,edx,ebp,esp等,我们今天要重点了解的是ebp与esp这两个寄存器。

 

2.ebp与esp

这两个寄存器中存放的是地址,整两个地址使用来维护函数栈帧的。每一个函数调用,都要在栈区创建一个空间,这块空间叫做函数栈帧,用esp与ebp来维护。

 

二、函数栈帧的创建

 

1.代码块

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

这个代码只是一个很简单的实现了加法函数,不用多说。

 

2.调用堆栈

接下来开始调试程序来看底层代码如何实现,首先打开调用堆栈

C语言函数栈帧的创建与销毁详解

从这里可以清楚地知道,main函数之前还有两个函数在调用,所以大家平时认为的main函数就是最初的开始是错误的哦。

 

3.esp与ebp如何维护栈帧

在栈的使用中,是从高地址开始的。其中ebp指向栈底,esp指向栈顶。

C语言函数栈帧的创建与销毁详解

main函数被调用后,程序会为main函数分配栈空间。接下来调试并右击鼠标转到反汇编。可以看到

C语言函数栈帧的创建与销毁详解

这些代码的意思是

将ebp的值压栈,然后将esp赋给ebp,给esp减去0E4h的大小,之后分别将ebx,esi,edi压栈

压栈的意思是将元素放到栈顶。在上面调用堆栈可以看到main函数由__tmainCRTStartup调用。图解如下:

C语言函数栈帧的创建与销毁详解

值得一提的是,在栈顶放元素是esp会自动指向新放元素的上方。

C语言函数栈帧的创建与销毁详解

C语言函数栈帧的创建与销毁详解


上图中我们很容易的看出在调用main函数是为main函数开辟的栈空间即栈帧,并且将esp的值给ebp,ebp和esp指向同一块空间,然后esp变小指向上面的区域,接下来将ebx,esi,edi压栈。

C语言函数栈帧的创建与销毁详解

C语言函数栈帧的创建与销毁详解

接下来这四句,lea是加载有效地址,从上图中,我们知道ebp指向的地址,那么edi存放的就是ebp-0E4h的地址也就是③esp处的地址,最后一句rep stos dword ptr es:[edi] 意思是从edi里面重复拷贝ecx次eax的内容。一次拷贝四个字节,dword是四个字节的意思。

C语言函数栈帧的创建与销毁详解

接下来这三个汇编代码的意思就是将值放入相应的空间。至于为什么是为什么是ebp-8和ebp-20,这个和编译器有关,就不过多叙述。

C语言函数栈帧的创建与销毁详解

C语言函数栈帧的创建与销毁详解

由汇编代码可知,接下来就开始创建形式参数,将要传递的参数值存入eax与ecx这两个寄存器中并压入栈顶,所以创建的形式参数并不在add函数的函数栈帧哦,并且我们之前常说的形参是实参的一份临时拷贝无疑是非常正确的。

C语言函数栈帧的创建与销毁详解

C语言函数栈帧的创建与销毁详解

接下来开始add函数调用。call是调用的意思,后面是add函数的地址用来找到调用函数。这里值得一提的是call指令下一条指令的地址被存储来方便执行完add函数可以跳回来。

Add函数创建栈帧的过程其实和main函数一样的,先将ebp压栈方便找到指向main函数栈底的空间,再将esp的地址存放到ebp里面,此时,esp和ebp指向同一位置,再将esp上移0CCh个位置,然后就是ebx,esi,edi压栈,这里不多作说明,由下图可清晰理解:

C语言函数栈帧的创建与销毁详解

C语言函数栈帧的创建与销毁详解

接下来初始化z与执行加法也没什么要说的,z=x=y是找到之前创建的形参来进行加法。并将结果移动到z里。

C语言函数栈帧的创建与销毁详解

返回z的操作是将z的值存放到eax这个寄存器中,所以函数销毁变量与返回的值这个操作并不冲突。

C语言函数栈帧的创建与销毁详解

最后销毁add函数栈帧,pop就是弹出元素然后把元素放入后面的寄存器,每次pop都会销毁一个栈顶元素然后esp自动++往下挪移。三下pop之后要回收空间了,操作是把ebp的值传给esp这样esp指向的空间是main函数的栈顶,然后popebp这个操作会将之前栈底存放的之前存放的main函数的栈底指针传给ebp,这样ebp就指向了main函数的栈底。如下图:

C语言函数栈帧的创建与销毁详解

接下来销毁main函数的操作也与之前一样,就不细说了。

 

总结 

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注服务器之家的更多内容!        

原文链接:https://blog.csdn.net/tjh94512/article/details/123030598

延伸 · 阅读

精彩推荐
  • C/C++Opencv透视变换综合实例详解

    Opencv透视变换综合实例详解

    这篇文章主要为大家详细介绍了Opencv透视变换综合实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    东城青年10492021-07-29
  • C/C++C语言数据结构 快速排序实例详解

    C语言数据结构 快速排序实例详解

    这篇文章主要介绍了C语言数据结构 快速排序实例详解的相关资料,快速排序采用分治的思想,两边数据进行排序,需要的朋友可以参考下...

    u01088961610152021-05-27
  • C/C++C++扫雷游戏的简单制作

    C++扫雷游戏的简单制作

    这篇文章主要为大家详细介绍了C++扫雷游戏的简单制作,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    我有颗小粒的痣7012021-08-25
  • C/C++C语言实现井字棋(三子棋)

    C语言实现井字棋(三子棋)

    这篇文章主要为大家详细介绍了C语言实现井字棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    mac_timmy9112021-11-03
  • C/C++深入理解C/C++中的写时拷贝

    深入理解C/C++中的写时拷贝

    这篇文章主要给大家介绍了C/C++中写时拷贝的相关资料,所谓写时拷贝也就是拖延版的深拷贝,下面文章中介绍的非常清楚,需要的朋友可以参考学习,下...

    Dawn_sf9592021-05-06
  • C/C++C++ 多线程编程建议之 C++ 对多线程/并发的支持(下)

    C++ 多线程编程建议之 C++ 对多线程/并发的支持(下)

    这篇文章主要介绍的是 C++ 多线程编程建议之 C++ 对多线程/并发的支持的相关资料,承接前文 现代 C++ 对多线程/并发的支持,接下来我们看看回发生什么吧...

    Zijian/TENG6932022-01-21
  • C/C++OpenCV实现透视变换矫正

    OpenCV实现透视变换矫正

    这篇文章主要为大家详细介绍了OpenCV实现透视变换矫正,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    GraceSkyer9622022-09-02
  • C/C++C++计算每个字符出现的次数

    C++计算每个字符出现的次数

    这篇文章主要介绍了C++计算每个字符出现的次数的相关资料,需要的朋友可以参考下...

    王勋广7212021-04-01