IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> C语言1.函数栈帧的创建和销毁 -> 正文阅读

[嵌入式]C语言1.函数栈帧的创建和销毁

  1. 寄存器(集成到CPU上的): eax、ebx、ecx、edx
    函数栈帧:ebp、esp这两个寄存器中存放的是地址,这两个地址用来维护函数栈帧。
  • 每个函数调用都需要在栈区创建一个空间
  • 每个函数调用都需要栈帧
  • 栈空间使用从高地址到低地址 就像栈,先放底,再放顶
  • 一开始,因为main函数也是被别的函数调用的,叫__tmainCRTStartup,esp和ebp分别指向该栈帧的顶地址和底地址,当调用main函数,用esp上一个内存存ebp,并且ebp指向它,然后esp减0E4h(因为低地址未被用,因为是从高到低使用的, 0E4h显然是main占的空间大小)。总之,调用main的时候,esp和ebp一上(低地址)一下(高地址)地维护main()函数的栈帧。
    此时栈区中栈帧的情况
  • 之后esp上面(在栈顶上放)又有了ebx、esi、edi,即入栈,所以esp也在依次上挪,之后lea=load,之后,edi向下的一片范围为内,所有main内存中的值,全赋值成CCCCC的内容,图中一行是4个字节,之后就能运行你的main中的代码了,比如此时有int a = 10; 就给低内存最下面赋值10,如下图一行,即一个字节。而如果初始化只定义了 int a;直接输出a,就会输出烫烫烫烫烫烫烫烫,其实这是CCCC值对应的内容
    执行赋值语句后给蓝色框内容,从下到上使用栈内存赋值

同时,下图中内存中,最下面地中中给了变量值,赋值成了10。
8*4 = 32位, 32/8 = 4 字节正好是一个int类型,此后再如果有int b = 20;
会给它间隔两个字节的地址赋值,这种方法是vs2013,而其它编译器可能紧挨着放。

请添加图片描述

  • 此时已经知道,程序运行先创建栈帧,再执行内部语句。push:利用eax,ecx(传参)等等寄存器完成操作,这些是不断在esp上面做的,esp也在不断上挪。后面遇到call指令(因为现在开始用函数了),(先记下call地址,44B),call指令把下一条指令的地址压到栈顶,因为后面是要开始进入一个函数,比如要跳到add里面还要出来,需要回来就利用call压到栈顶的地址,之后来到add函数,和之前main中变量运行一样,也是准备地址,放值,esp一直也在挪,在add内部,push,先压ebp的地址,然后move,esp,然后执行做内部语句,次开辟空间为add()函数,里面还是一大坨CCC,然后复制完,传入的参数值,会存在add的低地址部分,执行函数之前,比如遇到add(3, 4),这个时候,存3,4到地址中,等在esp、ebp开辟了add空间后,用到这两个的时候,又返回去找3、4的地址中的值,所以在函数还没调用的时候,实参的值,已经存到了栈里面,所以形参是实参的临时拷贝。
    请添加图片描述
    返回过程:算好的值比如z变量带的值存eax中,因为一会销毁z值,等回到主函数,把寄存器eax值拿出来,然后是一直在pop(),然后顺便销毁空间,回收的时候:move,把ebp赋给esp,b在下面,所以相当于esp向下移动了(低地址到高地址,释放了空间),把之前存到的地址都用起来,因为在调用函数的时候,会存各个函数的ebp值,(因为之前不断在存栈底的值)main函数的,然后esp、ebp(两个寄存器)不断往回挪,然后回到main函数继续往下走,一个指令pop就能让他们回去,当遇到ret指令时,弹出之前call指令存的call的下一条指令地址,ret让回到了主函数call的下一条语句。此时形参用完了,因为add值都返回了,所以把之前参数的值从栈弹出,esp往下挪(即低地址到高地址),esp往下走,相当于释放空间,总之函数返回值在寄存器比如eax中,然后用就拿。

  • 如果再碰到其它函数,再创建栈帧。

  • 栈帧的销毁过程:1.18

局部变量怎么创建的?

在栈帧中分配空间

为什么局部变量不初始化是随机值:

因为之前在开辟空间给了CCCCC ,初始化会覆盖

函数是如何传参的?

当调用函数,还没调用的时候,已经把push压栈进去了参数,真的进入了函数的时候,通过指针偏移量找到在栈内的形参值,所以形参值先存,后才开辟函数空间。

形参和实参区别???

  • 形参在栈内有自己的地址,值是实参的临时拷贝,只是值相同,改变形参不会影响形参

函数调用的结果是怎么传回来的?

call指令下一条指定的地址记住了,走完函数,弹出上一条ebp地址是上一个函数的栈底地址,然后把函数值存在一个寄存器中,销毁之前函数空间,然后利用之前calll指令存到的下一条地址指令地址。

  • 开辟空间大小、不够之类的,问题,可以说:这取决于编译器。编译器很智能
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-04-26 11:55:20  更:2022-04-26 11:57:02 
 
开发: 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/26 2:46:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码