函数的调用过程(栈帧的创建和销毁)

2023-05-16

  为了更好地认识函数的调用过程,我们可以用反汇编代码去理解学习。

一、基本概念

1.栈帧(过程活动记录):是编译器用来实现函数调用的一种数据结构,每个栈帧对应一个未运行完的函数,栈帧中保存了该函数的返回地址和局部变量。

2.栈(stack):又名堆栈,是一种运算受限的线性表,只允许在表的一端输入输出,这一端叫栈顶,相对的另一端是栈底,遵循后进先出,栈底是高地址,栈顶是低地址,栈由内存高地址向低地址生长。

3.push: 压栈    pop:出栈

4.寄存器: 位于CPU内部,存放运行程序中的数据和指令。

ebp (栈帧的栈底指针)     esp(栈帧的栈顶指针)

二、调用add函数的代码

#include <stdio.h>
int add(int a, int b)
{
	int ret = 0;
	ret = a + b;
	return ret;
}
int main()
{
	int a = 10;
	int b = 20;
	int ret = add(a, b);
	return 0;
}

三、截取的部分反汇编代码,进行逐语句分析

int main()
{
00B81410  push        ebp             //在此之前,main函数在mainCRTstartup中调用,先为mainCRTsturtup开辟栈帧,有栈底,有栈顶。现在开始压栈。
00B81411  mov         ebp,esp       //让ebp指向esp的位置。
00B81413  sub         esp,0E4h     //esp指向[esp-oE4h]的位置,sub为减
00B81419  push        ebx             //分别将ebx、esi、edi压栈
00B8141A  push        esi  
00B8141B  push        edi  

00B8141C  lea         edi,[ebp-0E4h]           //加载有效地址,让edi存放[ebp-0E4h]的位置,1C至2C表示对空间进行初始化,从edi所指向的位置开始向高地址进行拷贝,初始内容为0CCCCCCCCh,拷贝39次
00B81422  mov         ecx,39h
00B81427  mov         eax,0CCCCCCCCh  
00B8142C  rep stos    dword ptr es:[edi]  

int a = 10;
00B8142E  mov         dword ptr [a],0Ah      //将10赋值于给a变量分配的空间
int b = 20;
00B81435  mov         dword ptr [b],14h       //将20赋值于给b变量分配的空间
int ret=add(a, b);
00B8143C  mov         eax,dword ptr [b]       //进行传参,让寄存器eax存放b的值
00B8143F  push        eax                          //将eax压栈
00B81440  mov         ecx,dword ptr [a]       //进行传参,让寄存器ecx存放a的值
00B81443  push        ecx                          //将ecx压栈
00B81444  call        _add (0B810E6h)       //call指令下一条地址,为add函数的调用及返回做准备

——————————————————————————————————————

00B810DC  jmp         00B83BBE  
__ValidateImageBase:
00B810E1  jmp         00B82910  
_add:
00B810E6  jmp         00B813C0                //即进入add函数
_GetProcessHeap@0:
00B810EB  jmp         00B83C2A  
__RTC_SetErrorFuncW:

——————————————————————————————————————
int add(int a, int b)
     4: {
00B813C0  push        ebp                //ebp压栈,是main函数的ebp
00B813C1  mov         ebp,esp          //让ebp指向esp的位置。
00B813C3  sub         esp,0CCh       //esp指向[esp-0CCh]的位置,sub为减
00B813C9  push        ebx                //分别将ebx、esi、edi压栈
00B813CA  push        esi  
00B813CB  push        edi  

00DC13CC  lea         edi,[ebp-0CCh]        //加载有效地址,让edi存放[ebp-0CCh]的位置,CC至DC表示对空间进行初始化,从edi所指向的位置开始向高地址进行拷贝,初始内容为0CCCCCCCCh,拷贝33次
00DC13D2  mov         ecx,33h  
00DC13D7  mov         eax,0CCCCCCCCh  
00DC13DC  rep stos    dword ptr es:[edi]  
     5: int ret = 0;
00DC13DE  mov         dword ptr [ebp-8],0              //将0放入[ebp-8]处
     6: ret = a + b;
00DC13E5  mov         eax,dword ptr [ebp+8]          //将[ebp+8]处的值10放入eax
00DC13E8  add         eax,dword ptr [ebp+0Ch]      //将[ebp+0Ch]处的值20放入eax并相加,得eax中的值为30.
00DC13EB  mov         dword ptr [ebp-8],eax          //将eax的内容拷贝在[ebp-8]中,即ret变量
     7: return ret;
00DC13EE  mov         eax,dword ptr [ebp-8]          //将ret的值存入eax中
     8: }
00DC13F1  pop         edi                                    //edi、esi、ebx、出栈,栈帧逐渐开始销毁
00DC13F2  pop         esi  
00DC13F3  pop         ebx  
00DC13F4  mov         esp,ebp                            //让esp指向ebp位置
00DC13F6  pop         ebp                                    //弹出ebp,
00DC13F7  ret                                                    //使其指向调用者调用函数之后的下一条指令的地址


00B81444  call        00B810E6                           //下一条指令地址出栈
00B81449  add         esp,8                                //将之前放入栈的两个实参从栈中移除,esp下移
00B8144C  mov         dword ptr [ebp-20h],eax     //将eax中的值30放入[ebp-20h]中,函数调用也到此结束
    14: return 0;

四、函数调用图


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

函数的调用过程(栈帧的创建和销毁) 的相关文章

随机推荐

  • QML入门----设计器详解(拖拽添加控件)

    文章目录 导语1 基本视图2 文件类型 一 界面说明1 库 xff08 Library xff09 2 导航 xff08 Navigator xff09 3 属性 xff08 Properties xff09 4 连接视图 导语 设计器的基
  • C++11 非常方便的特性

    文章目录 C 43 43 11一 nullptr1 含义2 作用3 NULL存在的问题 二 auto1 含义2 限制3 使用场景 三 lambda1 含义2 优点3 用法 四 基于范围的for循环1 作用2 用法3 循环内更改数组 C 43
  • QML入门----C++与QML交互快速应用

    文章目录 前言一 Qt中有关QML的C 43 43 类1 QQmlEngine2 QQmlContext3 QQmlComponent4 QQmlExpresssssion 二 其他1 使用C 43 43 属性 xff08 Q PROPER
  • QML错误:Component is not ready

    一 原因 终极原因 xff1a 组件没有构建好 xff0c 有可能是加载的QML路径不对 xff0c 或者是QML代码错误 xff0c 或者是QML组件还没有加载完 二 解决办法 打印详细错误 QQmlEngine engine span
  • QT 打开程序闪烁cmd窗口

    包含多种原因 xff0c 我的原因是Pro文件多写了一些其他的 xff0c 删除了下面这句OK了 DISTFILES span class token operator 43 span span class token operator 6
  • QT UTC(T和Z格式)时间转换为北京时间

    一 UTC 协调世界时 xff0c 又称世界统一时间 世界标准时间 国际协调时间 由于英文 xff08 CUT xff09 和法文 xff08 TUC xff09 的缩写不同 xff0c 作为妥协 xff0c 简称UTC 和北京时间相差八小
  • QT 文件操作大全

    文章目录 常用文件模式一 创建文件二 读文件三 写文件四 清空文件夹五 计算文件夹个数六 计算文件夹总大小七 转换大小为B KB M G八 批量修改文件名 常用文件模式 模式含义QIODevice ReadOnly只读方式QIODevice
  • QT QScrollArea 滑动到指定item位置

    一 QT自带的api QListWidget QTableWidget QTreeWidget都有自带的api可以调用 xff0c 如下示例 但是当自定义一个QScrollArea区域 xff0c 布局中插入多个item时 xff0c 就需
  • 马克飞象常用操作(markdown )

  • QT 移入控件展示卡片

    功能 xff1a 移入widget显示卡片 xff0c 并且可以进入卡片不消失 xff08 widget与卡片距离离得很近 xff09 xff0c 移出卡片才离开 span class token keyword bool span spa
  • 树莓派pico入门第一站:让主板上的小灯闪起来。(附代码)

    首先配置你的树莓派pico xff0c 把它插在你的电脑上 xff0c 你的电脑会多出来一个 U盘 xff0c 把这个文件复制 xff0c 粘贴 到你的树莓派pico里面 xff0c 你多出来的 U盘 会自动 消失 xff0c 这时候 xf
  • QT 网格布局插入固定列数的item

    一 场景 在网格布局插入固定列数的item xff0c 比如三列item xff0c 根据item的总数计算 span class token macro property span class token directive hash s
  • QT QMetaEnum枚举与字符串互转

    一 示例 span class token macro property span class token directive hash span span class token directive keyword include spa
  • QT 抓取widget转换为图片

    QString folder span class token operator 61 span span class token class name QStandardPaths span span class token operat
  • window11 安装linux子系统(一键安装)并连接到vs code

    文章目录 一 window 使用linux环境的几种方式二 安装wsl1 进入这个目录下 xff0c 将cmd exe已管理员身份运行2 命令行输入以下命令 xff0c 然后重启计算机3 再次已管理员身份打开 xff0c 执行命令 xff0
  • QT 利用URL Protocol实现网页调起本地程序

    一 QT 安装时脚本注入注册表或者自己添加 span class token comment 依次为目录 键 值 xff0c 34 URL Protocol 34 这个键必须有 span WriteRegStr HKCR span clas
  • PC 配置jenkins自动打包

    文章目录 一 下载jenkins运行环境二 下载jenkins三 安装 qt 5 12 2 和 VS 2017四 安装git并配置gitlab五 jenkins配置git 一 下载jenkins运行环境 java jdk 11 镜像下载地址
  • 心系Flyme

    我来自陕西省神木县 xff0c 大学我考入了陕西科技大学 xff0c 成为了一名信息与计算科学专业的学生 xff0c 希望在以后的道路中 xff0c 通过我自己的努力 xff0c 提升自己的价值 在大二大三学习编程 xff0c 希望自己可以
  • C语言的编译链接过程

    编写的一个C程序 xff08 源程序 xff09 xff0c 转换成可以在硬件上运行的程序 xff08 可执行程序 xff09 xff0c 需要进行翻译环境和运行环境 翻译环境则包括两大过程编译和链接 xff0c 经过编译和链接过程便可形成
  • 函数的调用过程(栈帧的创建和销毁)

    为了更好地认识函数的调用过程 xff0c 我们可以用反汇编代码去理解学习 一 基本概念 1 栈帧 xff08 过程活动记录 xff09 xff1a 是编译器用来实现函数调用的一种数据结构 xff0c 每个栈帧对应一个未运行完的函数 xff0