C语言函数的栈帧与销毁(面试亮点)
目录
如果你能熟练的掌握函数的栈帧与销毁在面试中是及其亮眼的加分项,所以我们来以实例来将解函数是如何实现栈帧与销毁的。
一. 函数栈帧
二.寄存器
三. 用例题讲解创建栈帧的过程
3.1 main 函数的反汇编代码。
第一步:给调用main函数的函数分配栈帧。
第二步:通过将edp压栈,将edp赋值给esp,再将esp的值减减。这样esp和edp之间的差值就是main函数的栈帧空间。
第三步: 将edi,esi,ebx压栈。
第四步:初始化
第五步:给实参分配空间
第六步:将实参拷贝到新地址
第七步: call指令传参
call跳add()函数的地址之后,在添加call指令的下一条指令的地址。
3.2 add函数的栈帧
第一步:为add创建栈帧
第二步:将形参相加:
3.3 return 的栈帧
第一步
z出了add()栈帧被销毁,但是值被临时放到eax寄存器里。
第二步
第三步:回收空间
第四步:pop edp
第五步:回来之后执行call指令的下一条指令
第六步
创建的完整过程(没带销毁)
四.面试问题
4.1 局部变量时怎么创建的?
4.2 为什么局部变量的值是随机值?
4.3 函数是怎么传参的?传参的顺序是什么?
4.4 形参和实参的关系是什么?
4.5 函数的调用是怎么做的?
5.6 函数调用是结束后怎么返回的?
如果你能熟练的掌握函数的栈帧与销毁在面试中是及其亮眼的加分项,所以我们来以实例来将解函数是如何实现栈帧与销毁的。
一. 函数栈帧
edp,esp这两个寄存器存放的是地址,这两个地址是用来维护函数栈帧的。
每一个函数调用都要在栈区中创建一个空间。
二.寄存器
1.1 edp:栈底指针。
1.2 esp:栈顶指针,每次push,它都会向上(低地址)挪动,push就会--,pop就会++。
esp和edp中间的 内容才是当前维护的内容,esp上方的内容已经销毁的内容。
寄存器:寄存器是集成到CPU 上的是独立的存储空间。与硬盘,内存都是独立存在的。
三. 用例题讲解创建栈帧的过程
3.1 main 函数的反汇编代码。
main函数也是被调用,main函数是被t_main CRTStartup调用。

第一步:给调用main函数的函数分配栈帧。

第二步:通过将edp压栈,将edp赋值给esp,再将esp的值减减。这样esp和edp之间的差值就是main函数的栈帧空间。

第三步: 将edi,esi,ebx压栈。
lea:是load effective address 是加载有效地址的意思。即esp-014H。

第四步:初始化
从edi开始向下ecx次即39h次,将ecx里dword(一个word两个字节,doubleword是四个字节)个内容初始化为0cccccccch,初始化39h(39h是十六进制,换成十进制次)次。即将main函数里的内容全部初始化为0cccccccch。
所以如果变量不初始化,那么就默认0cccccccch。
第五步:给实参分配空间
将ebp-14h(即b的值)存放到eax里,然后将eax压栈 。



第六步:将实参拷贝到新地址
不用给形参分配新空间,在函数调用之前,就将实参拷贝到新空间。


第七步: call指令传参
call的地址是
![]()
然后call指令,call指令跳到add()函数的地址

call跳add()函数的地址之后,在添加call指令的下一条指令的地址。
所以call()指令之后,将call指令的下一条指令的地址压栈。

3.2 add函数的栈帧
然后才是真正的进入add()函数。
第一步:为add创建栈帧
所以我们并没有创建形参,而是在调用函数的时候就把实参传递过去了。 将他们当成X,Y。
因此可以证明形参只是实参的拷贝。所以改变形参不会改变实参。

第二步:将形参相加:


3.3 return 的栈帧

形参是实参的临时拷贝,不是在add栈帧里创建的只是调用一个压栈的空间。
第一步
z出了add()栈帧被销毁,但是值被临时放到eax寄存器里。
所以为了防止z出了作用域被销毁,所以将z放到eax寄存器里临时保存,寄存器是不会因为程序销毁而销毁的。
第二步

pop会导致esp++ ,esp上面的栈会被释放被回收了S。
第三步:回收空间
![]()
将ebp赋值给esp的意思就是将esp挪动到edp的位置,上面的空间被回收。

第四步:pop edp
pop edp,将edp出栈,这里栈顶元素edp是main函数的edp,所以将他pop之后他会回到原main函数的edp位置。
然后esp++;这是esp和edp两个指针彻底回到main函数的作用域里。esp指向00C21450即回到了call指令的下一条指令的地址,所以要执行call指令的下一条指令。

第五步:回来之后执行call指令的下一条指令

将esp+8:这里加8的目的值将两个形参的空间给销毁。

第六步

将eax的值赋值给edp -20h,刚刚我们为了防止z的值丢失所以我们将它的值存放在寄存器eax里,所以函数的任务完成了,现在需要将操作完的值还给main函数。
正好edp-20h就是main函数的C。这样返回值就被传回来了。

创建的完整过程(没带销毁)
四.面试问题
4.1 局部变量时怎么创建的?
答:首先,我们为这个局部变量分配栈帧空间,然后在为这个空间初始化空间,然后在为局部变量分配空间。
4.2 为什么局部变量的值是随机值?
答:因为如果局部变量不初始化的话,函数栈帧空间的初始化是随机值,所以如果局部变量不初始化的话,那么它的值就是它分配的那段空间的随机值。如果你将局部变量初始化了,那么你初始化的值就会覆盖掉随机值。
4.3 函数是怎么传参的?传参的顺序是什么?
我们并没有创建形参,而是在调用函数的时候就把实参传递过去了。在还没有调用函数的时候,就以及将实参的拷贝push压栈到空间里,到调用函数的时候,并没有为形参分配空间,而是使用esp+偏移量,找到实参的拷贝。
传参的顺序:参数从右向左压栈。
4.4 形参和实参的关系是什么?
答:形参是实参的拷贝,改变形参不会影响实参。因为他们的空间是独立的。
4.5 函数的调用是怎么做的?
5.6 函数调用是结束后怎么返回的?
在函数调用之前就将call指令的下一条指令的地址就压栈了,然后再将edp(此时的edp是调用函数的上一条函数如main函数的edp)压栈,这样在pop掉edp时,edp会返回到原edp的位置,由于pop操作,会使esp++,这样esp就会调用call指令的下一条指令的地址,这样就会时函数调用返回,然后返回的值,事先已被寄存器eax临时保存,这样值也会被寄存器带回。
相关文章:
C语言函数的栈帧与销毁(面试亮点)
目录 如果你能熟练的掌握函数的栈帧与销毁在面试中是及其亮眼的加分项,所以我们来以实例来将解函数是如何实现栈帧与销毁的。 一. 函数栈帧 二.寄存器 三. 用例题讲解创建栈帧的过程 3.1 main 函数的反汇编代码。 第一步:给调用main函数的函数分配…...
使用 GreenSock(GSAP)实现 字符串动画
要使用 GreenSock(GSAP)实现 "JianMa XinXi" 这个字符串的动画,其中两个 x 字符自动旋转,j 和 m 字符上下跳动,并且美化这个字符串使其可以作为 logo 使用,我们可以通过以下步骤来实现࿱…...
linux系统zabbix监控服务端部署
zabbix服务端部署 zabbix服务端部署安装mysql创建初始数据库为Zabbix server配置数据库为Zabbix前端配置PHP启动Zabbix server和agent进程浏览器访问ipConfigure DB connection页面Zabbix server details页面登录账户名密码 zabbix 官网www.zabbix.com服务端部署 rpm -Uvh ht…...
算法----回溯(附录---剪枝)
回溯相信大家都已经了解了所以这章我将见但介绍下回溯剪枝 为什要剪枝 在《算法----回溯(正文)》中我提到过回溯就是暴力,为什么那些题能过,因为数据范围小 那如果数据范围大了,就不行了,这时剪枝的作用就…...
从Unity到Three.js(模型文件加载)
模型加载功能探索,用blender导出了个glb格式的cube进行的测试。 初接触js语法,回调注册的地方直接使用匿名函数总感觉脑子跟不上,反应不过来,就把加载后的回调简单封装了下, 官方文档是直接使用的匿名函数。 另外看官方…...
Webshell一句话木马
一、webshell介绍(网页木马) 分类: 大马:体积大、隐蔽性差、功能多 小马:体积小,隐蔽强,功能少 一句话木马:代码简短,灵活多样 二、一句话木马: :…...
【Web】Spring rce CVE-2022-22965漏洞复现学习笔记
目录 原理概览 漏洞简述 Tomcat AccessLogValve 和 access_log 例题: 原理概览 spring框架在传参的时候会与对应实体类自动参数绑定,通过“.”还可以访问对应实体类的引用类型变量。使用getClass方法,通过反射机制最终获取tomcat的日志配置成员属性…...
springboot/ssm大学生选修选课系统高校选课排课成绩管理系统Java系统
springboot/ssm大学生选修选课系统高校选课排课成绩管理系统Java系统 开发语言:Java 框架:springboot(可改ssm) vue JDK版本:JDK1.8(或11) 服务器:tomcat 数据库:my…...
【芯片设计- RTL 数字逻辑设计入门 14 -- 使用子模块实现三输入数的大小比较】
文章目录 三输入数的大小比较问题分析verilog codeTestBench Code综合图仿真波形图 三输入数的大小比较 在数字芯片设计中,通常把完成特定功能且相对独立的代码编写成子模块,在需要的时候再在主模块中例化使用,以提高代码的可复用性和设计的层…...
Xilinx FPGA——在线升级
同以前单片机在线升级的做法一样,本质就是通信Flash操作跳转。 一、通信驱动 我使用的是UDP有线传输, 二、Flash芯片驱动 规划Flash芯片的区域,一般bootloader放在起始位置,APP放在bootloader之后的空白区域。 2.1 Flash擦除 我…...
电商小程序02数据源设计
上一篇我们讲解了电商小程序的需求分析,分析了需要具备的功能并且绘制了系统原型。有了原型之后下一步的事情就是根据原型来设计数据源。 数据源就像盖房子打地基一样,地基打不好,楼可能就盖不高,盖起来要再想调整就比较困难。 …...
Leetcode 3033. Modify the Matrix
Leetcode 3033. Modify the Matrix 1. 解题思路2. 代码实现 题目链接:3033. Modify the Matrix 1. 解题思路 这一题是一道easy的题目,整体思路上没啥难度,就是按照题目翻译一下即可,先遍历一下找到每一列的最大元素,…...
蓝桥杯刷题--python-4
0成绩分析 - 蓝桥云课 (lanqiao.cn) import os import sys # 请在此输入您的代码 n=int(input()) max_=float(-inf) min_=float(inf) res=0 for _ in range(n): score=int(input()) # 最高分 max_=max(max_,score) # 最低分 min_=min(min_,score) # 总分 res+=sc…...
openJudge | 距离排序
总时间限制: 1000ms 内存限制: 65536kB 描述 给出三维空间中的n个点(不超过10个),求出n个点两两之间的距离,并按距离由大到小依次输出两个点的坐标及它们之间的距离。 输入 输入包括两行,第一行包含一个整数n表示点的个数,第二…...
【算法】排序详解(快速排序,堆排序,归并排序,插入排序,希尔排序,选择排序,冒泡排序)
目录 排序的概念: 排序算法的实现: 插入排序: 希尔排序: 选择排序: 堆排序: 冒泡排序: 快速排序: 快速排序的基本框架: 1.Hoare法 2. 挖坑法 3.前后指针法 快…...
LeetCode Python -8.字符串转整数
文章目录 题目答案运行结果 题目 请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C 中的 atoi 函数)。 函数 myAtoi(string s) 的算法如下: 读入字符串并丢弃无用的前导空格检查下一个…...
【java】笔记10:类与对象——本章练习
题目1: 代码如下: import java.util.Scanner; public class Input{public static void main(String[]args){Circle cnew Circle();PassObject yuannew PassObject();System.out.println("r""\t""times");yuan.printAreas…...
《UE5_C++多人TPS完整教程》学习笔记8 ——《P9 访问 Steam(Acessing Steam)》
本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P9 访问 Steam(Acessing Steam)》 的学习笔记,该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版,UP主(也是译者&…...
缓存穿透问题与解决方案
引言 在分布式系统中,缓存技术被广泛应用以提高系统性能和响应速度。然而,缓存穿透是一个常见而严重的问题,特别是在面对大规模请求时。本文将深入探讨缓存穿透的原因、影响以及一些有效的解决方案,以确保系统在面对这一问…...
《Git 简易速速上手小册》第1章:Git 基础(2024 最新版)
文章目录 1.1 Git 简介:版本控制的演变1.1.1 基础知识讲解1.1.2 重点案例:协作开发流程优化案例:功能开发与分支策略 1.1.3 拓展案例 1:代码审查与合并1.1.4 拓展案例 2:冲突解决 1.2 安装和配置 Git:首次设…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
