C语言进阶栈帧示例详解教程

 更新时间:2022年02月16日 09:55:56   作者:乔乔家的龙龙  
这篇文章主要为大家介绍了C语言进阶栈帧的示例详解教程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

正片开始

今天来讲讲我对栈帧创建与销毁的拙见。
理解什么是栈帧首先知道什么是栈:

在数据结构中, 栈是限定仅在表尾进行插入或删除操作的线性表。栈是一种数据结构,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。

栈有什么用?

在计算机系统中,栈也可以称之为栈内存是一个具有动态内存区域,存储函数内部(包括main函数)的局部变量和方法调用和函数参数值,是由系统自动分配的,一般速度较快;存储地址是连续且存在有限栈容量,会出现溢出现象程序可以将数据压入栈中,也可以将数据从栈顶弹出。压栈操作使得栈增大,而弹出操作使栈减小。

栈用于维护函数调用的上下文,离开了栈函数调用就没法实现。

讲到这里,小朋友你是否有很多问号?那打住,我们抛开无聊的学术前文,另起炉灶。

寄存器

要讲清楚栈帧就必须理解一手寄存器。尤其是 ebp,esp这2个寄存器中存放的地址,这两个地址是用来维护函数栈帧的。

在这里插入图片描述

寄存器有很多种这里不赘述

在这里插入图片描述

main函数创建

我们这里随便搞一个最简单的Add函数

int   add(int x,int y)
{
       int z;
       z=x+y;
       return z;
}
int main()
{
	int  data1;
    int  data2;
    int  ret;
    while(1)
    {
       int data1,data2 = 0;
       scanf("%d %d",&data1,&data2);
       add(data1,data2);
	    return 0;
}

搞栈帧的话我的编译器是不适合的,我是vs2019,因为编译器越高级函数的封装越复杂周密,不容易我们去剖析栈帧,我就尽量语言表达严谨一点吧。编译器反汇编过程就能反应我们栈帧创建的过程,这是我在网上找的反汇编页面可以参考一下

在这里插入图片描述

其中反汇编用到的指针我们要清楚意义:

在这里插入图片描述

在编译器中,main函数也是会被其他函数调用的,调用堆栈窗口后反汇编可以看到如下字样:

main
_tmainCRTStartup
mainCRTStartup

后面两句意义不明的玩意儿就是在调用main函数。为什么要讲这个呢?我们说每一次函数调用都要分配空间,main函数不例外也要分配栈帧空间。
以下内容和上面汇编指令表食用更佳:
首先 push ,即压栈,就是往栈sei东西进去。push 会让esp让低地址走,就会在原先基础上压进来一个 ebp 指针。

在这里插入图片描述

接下是 mov 指针,mov把后面的指针赋到前面去,esp给了ebp,也就是相当于在移位。

在这里插入图片描述

接下来是 sub 减法操作,减去一个内容来使esp指针走向低地址来开辟main函数栈帧。

在这里插入图片描述

过程模拟如下:

在这里插入图片描述

局部变量创建

接下来esp已经走到那几个内容的头上去了,这时出现了 lea 指针,即 load effective address 加载有效地址,其实在这个指针指定对象里面放入一个地址

在这里插入图片描述


我们后面的 [ebp-0C0h],其实就是刚刚 sub操作,本质上还是原来开辟栈帧起点 ebp 的地址,把这个地址放入edi 里面。

在这里插入图片描述

接下来的连续 mov 时在把从edi 开始的 30h 这么多个空间里面的 dword(double word-四字节数据)全部初始化成 eax 里面 “0CCCCCCCCh”的内容,保证为main函数预开辟的内存全变成 “CCCCCCCCh”,这么说来改的还是蛮多的。
接下来当我们创建变量时,比如 int a = 10;就会出现类似下面字样:

int a = 10;                      
00C2142E C7 45 EC 0A 00 00 00 mov             dword ptr [ebp-8h],0Ah

这里就是在创建局部变量了, ebp指针减了 8h,这个 8h 就是给a留的位子**(这里的 h 是编译器给的标识,我们只需要明白这是一个十六进制数)**就行了。所以总结一下,其实创建方式与main函数没有太大出入。

函数部分

Add函数传参时也是在将 esp 进行压栈,但注意,这时的esp里面的值是 10,相当于是在传 10 这个值。传完参紧接着就会调用函数

00C2144B E8 91 FC FF FF           call             00C210E1

call 指针作用就是调用函数,F11 执行call指令后会发现在跳转到作用的同时,他会把 call指令的下一条指令的地址传到里面,在顶上压一个main函数的ebp ,esp又会跑到最上面,一但函数执行完后返回就会很自然的回到该地址。

在这里插入图片描述

在main函数的 ebp 上面又会传统艺能,以相同的方式开辟 Add 函数的空间,又初始化成全 c,以相同方式创建临时变量……
这时你可能会注意到传进函数的 x,y去哪里了?其实已经为他准备好了,在返回进行下一项指令时,x,y就会乖乖跑到这片空间储存

在这里插入图片描述

Add函数完成后回把传的参返回, 就是我们的 pop 指针,即出栈,这里参数每从栈顶pop一次 esp 指针就会上移一个单位,ebp也会随之退回一个单位,利用指针的偏移量找回他的形参,最后返回值ret,其逻辑本质上就是弹出main ebq那里的下一项指令的地址。
我们走出函数后,esp,ebq会回收,这时这块空间就会直接销毁,挫骨扬灰。
整个函数部分就完美的呈现出来了。

形参与实参

形参确实是我在压栈时开辟的空间,这坨空间是独立的,只是值是相同的,形参是实参的一份临时拷贝,改变形参不影响实参,那返回值是怎么带回来的呢?其实是通过寄存器。

以上就是C语言进阶栈帧示例详解教程的详细内容,更多关于C语言栈帧的资料请关注脚本之家其它相关文章!

相关文章

  • C语言数组任意位置插入一个元素方法

    C语言数组任意位置插入一个元素方法

    这篇文章主要给大家分享C语言数组任意位置插入一个元素方法,
    2021-11-11
  • Unity编辑器下重启的方法

    Unity编辑器下重启的方法

    这篇文章主要介绍了Unity编辑器下重启的方法的相关资料,希望通过本文能帮助到大家,让大家学习理解这部分内容,需要的朋友可以参考下
    2017-10-10
  • 一文带你学会C语言中的qsort函数

    一文带你学会C语言中的qsort函数

    qsort函数是C语言的库函数,能实现对各种元素类型的比较,使用的基本思想是快速排序法,头文件是<stdlib.h>,本文不讲解具体实现原理,只对使用方法进行说明,希望对大家有所帮助
    2022-12-12
  • c++ 面向对象设计五大原则

    c++ 面向对象设计五大原则

    这篇文章主要介绍了c++ 面向对象设计五大原则,帮助大家更好的理解和学习c++面向对象设计,感兴趣的朋友可以了解下
    2020-08-08
  • C语言之飞机大战游戏

    C语言之飞机大战游戏

    这篇文章主要为大家详细介绍了C语言之飞机大战,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • C语言源码实现停车场管理系统

    C语言源码实现停车场管理系统

    这篇文章主要为大家详细介绍了C语言源码实现停车场管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12
  • C++利用SQLite实现命令行工具

    C++利用SQLite实现命令行工具

    这篇文章主要为大家详细介绍了一个基于 C++、SQLite 和 Boost 库的简单交互式数据库操作 Shell,该 Shell 允许用户通过命令行输入执行各种数据库操作,感兴趣的可以了解下
    2023-11-11
  • VC6.0常见链接错误与解决方法

    VC6.0常见链接错误与解决方法

    这篇文章主要介绍了VC6.0开发中一些常见链接错误的解决方法,需要的朋友可以参考下
    2013-07-07
  • C++如何将vector数字写入到txt文件中

    C++如何将vector数字写入到txt文件中

    这篇文章主要介绍了C++如何将vector数字写入到txt文件中问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • 浅谈c++中的输入输出方法

    浅谈c++中的输入输出方法

    下面小编就为大家带来一篇浅谈c++中的输入输出方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-06-06

最新评论