函数调用的过程理解_汇编角度
目录
- 1、调用函数流程(main函数调用print函数):
- Step1 保存main函数现场地址等信息
- Step2 跳转到print函数的位置
- Step3 执行print函数的指令
- Step4 返回main函数,执行下一条指令
- 流程连续性总结
- 2、其他知识总结
1、调用函数流程(main函数调用print函数):
Step1. 保存main函数现场地址等信息
Step2. 跳转到print函数的位置
Step3. 执行print函数的指令
Step4. 返回main函数,执行下一条指令
Step1 保存main函数现场地址等信息
要存储的内容,主要有3个:
(1)传入print函数的形参【父函数中实现】
(2)原eip(main函数call指令的下一条指令的地址)【父函数中实现】
(3)原ebp(main函数的ebp地址,因为是main函数直接调用print函数)【子函数中实现】
实现方式:
在main函数中,依次执行以下指令:
push eax; # 传入函数的形参arg
call print; #作用是保存eip。当然,也有跳转的作用(见Step2)
在print函数开头,依次执行以下指令:
push ebp; # 保存父函数main函数的栈底地址,方便调用函数结束后pop回去
mov ebp esp; # 指定print函数的栈帧基地址(print函数对应的栈底地址)
Step2 跳转到print函数的位置
核心是修改eip寄存器,把eip寄存器的值,修改为print函数的入口地址。
实现方式: 在main函数中调用call指令
call print.77c70888; # 相当于esp = esp - 4; push eip(此时的eip值,就是下面"main函数中的下一条指令"的地址); mov eip print函数的地址77c70888(跳转到新函数)
main函数中的下一条指令;
Step3 执行print函数的指令
子函数最开始,一般要执行以下的命令:
push ebp; # 保存原ebp
mov ebp esp; # ebp指向当前函数的栈底
...
sub esp, num; # 为子程序分配栈空间
...
pop ebp; # 让ebp指向父函数的栈帧基地址
ret n; # 让eip指向“main函数call指令的下一条指令的地址”;n是指平衡堆栈,即让最先push进去的形参args清空
Step4 返回main函数,执行下一条指令
核心是修改eip寄存器的值,把eip寄存器的值,修改为main函数中下一条指令的地址。
实现方式:在print函数中,调用ret命令
ret ; #相当于pop eip; esp = esp + 4
注意,如果原先栈中还有其他数据,esp 没有归位会导致主函数引用栈中数据出错。在这种背景下,出现了堆栈平衡的概念。即,还需对esp 进行单独操作,才能将 esp 指向原函数栈顶。以常见的 c 语言,函数有好几种调用规则。比如 cdecl 方式和 stdcall 方式。
cdecl 方式中,由主程序执行 add esp, n 指令调整 esp,达到堆栈平衡。在 stdcall 方式中,由子程序在返回时,执行 ret n 平衡堆栈。n 其实就是函数的参数所占的空间大小。
流程连续性总结
重要参考:《从汇编角度理解 ebp&esp 寄存器、函数调用过程、函数参数传递以及堆栈平衡》
函数调用
在一个函数中,调用另外一个函数,往往有以下几个步骤:
| 汇编指令 | 指令归属函数 | SP 变化 | 作用 |
|---|---|---|---|
| push arg2 | 主函数 | sp-4 | |
| push arg1 | 主函数 | sp-4 | |
call function | 主函数 | sp-4 | 开始调用子程序,同时保存返回地址 |
push ebp | 子函数 | sp-4 | |
| mov ebp, esp | 子函数 | sp-4 | 将当前esp 存入 ebp,目的是定位函数参数 |
| sub sp, #num | 子函数 | sp-num | 为子程序分配栈空间 |
| … | 子函数 | … | 函数的具体实现逻辑 |
| pop ebp | 子函数 | sp+4 | |
| ret | 子函数 | sp+4 |
说明:
push arg在调用一个函数之前,需要把传递的参数压入栈,因此需要有。每次 push 之后,栈多了一个字长(32 位系统 --> 4 字节),因此栈顶需要往上移动 4 字节,该指令暗含sub sp, #4callcall 指令用来调用某个函数,该指令有3个操作(1)sp = sp - 4(2)将返回地址压入栈; (3)修改eippush ebp,mov ebp, esp这样的操作,你会在各个函数的开头见到,保存上一个函数栈的基址,并更新本函数的基址ret,即 return,此时 sp 应该指向 call 指令刚刚压入的返回地址;执行ret其实就是将此时栈中的数据弹出,存至 eip 寄存器。eip 存放的是下一条即将执行的指令的地址。 同时 sp = sp + 4ret指令相当于pop eip(esp = esp + 4)call指令相当于push eip(esp = esp - 4);mov eip 新函数的地址
下图左边是主函数调用子函数,右边是子函数返回主函数:

2、其他知识总结
1、esp寄存器,永远指向整个栈帧的栈顶(esp寄存器保存的值是堆栈的地址值);栈顶中的内容,可能是一个地址值,也可能是一个立即数等等。esp寄存器指向的堆栈地址始终有值!所以push是先移esp后压栈,pop是先弹栈后移esp。
2、ebp寄存器,永远指向当前函数所在栈帧的栈底(ebp寄存器保存的值是堆栈的地址值);栈底中的内容,永远保存的是上一个函数(父函数)的ebp地址!(方便函数执行完后pop回去,即修改ebp)
- ebp 的作用之一就是找到函数的形参(通过
ebp + 偏移量),当然栈中的局部变量也是可以通过 ebp 来定位的(ebp - 偏移量)
3、父函数调用子函数,子函数的栈帧(低地址)是紧挨着父函数的栈帧(高地址)。
-
所以父函数调用子函数,一定是①args先压榨 ② 然后 原eip压栈(by call)③ 再 ebp压栈 ④ 最后函数的局部变量压榨
-
父函数栈帧 和 子函数栈帧,隔着的东西就是:args 和 eip

4、栈的增长方向,永远向着低地址的方向增长。
5、call 指令相当于:esp = esp - 4; push eip; mov eip 函数的地址.77c70888 (注意,push中已包含esp移动,这里只是表示先后)
6、ret指令相当于:pop eip; esp = esp + 4 (注意,pop中已包含esp移动,这里只是表示先后)
7、push eax指令,只会修改栈和esp:① esp = esp - 4 ② mov [esp], eax 这个[esp]表示esp指向的栈值(内存值)被赋值。
8、pop eax指令,不仅会修改栈和esp,而且还会修改eax(寄存器被赋值):① mov eax, [esp] ②esp = esp + 4
9、寄存器的地址值是不会变的,变的只是寄存器中装的堆栈地址值,以及这个堆栈地址中的内存内容值。这个类似并区别于C语言的指针变量。C语言指针变量有2个地址值,一个是指针变量装的堆栈地址值,另一个是指针本身的地址值(也位于堆栈)。指针变量声明后,它存在于内存中(堆栈中),指针释放了,这个指针的地址值也就无了。区别点在于 指针有本身的地址值(可以通过&取出来),而寄存器没有本身的地址值的说法(取不出来,或者有也是固定的但不常用)。指针变量的常操作数据有3个:①p ②*p ③&p;esp寄存器常操作的数据有2个:①esp ②[esp]
- esp:esp寄存器的内容值,即栈/内存的某个地址
- [esp]:栈中的值 / 内存中的值
相关文章:
函数调用的过程理解_汇编角度
目录 1、调用函数流程(main函数调用print函数):Step1 保存main函数现场地址等信息Step2 跳转到print函数的位置Step3 执行print函数的指令Step4 返回main函数,执行下一条指令流程连续性总结 2、其他知识总结 1、调用函数流程&…...
【Java-一些常见单列集合面试问题】
目录 1.List,Set的区别? 2.ArrayList与Vector区别? 3.Arraylist与LinkedList区别? 4.ArrayList的扩容机制? 5.HashSet、LinkedHashSet和TreeSet 区别? 6.HashSet如何过滤重复元素? 1.List,Set的区别…...
搭建个人博客需要做哪些事
文章目录 前言搭建步骤站点服务器站点域名注册域名ICP 备案公安备案域名解析 博客图床图床是什么图床搭建 博客站点搭建建站工具本地搭建博客部署 站点运营百度收录百度统计 总结 前言 花了几天时间,搭建了一个个人博客,也算是完成了年初立的一个flag&a…...
《向量数据库指南》——非结构化数据的行业需求及向量数据库的关键角色
非结构化数据的行业需求及向量数据库的关键角色 引言 在当今数字化时代,数据已成为驱动社会进步与产业升级的核心要素。随着技术的飞速发展,特别是人工智能(AI)技术的广泛应用,数据的类型与规模正以前所未有的速度增长。其中,非结构化数据作为数据海洋中的主体部分,其…...
C++:map容器的使用
一、map的使用介绍 map文档介绍 1.1 map的模版参数 Key:键值对中Key的类型 T:键值对中value的类型 Compare:比较器的类型,map中的元素是按照Key来进行比较的,缺省情况(不传参数时)按照小于来…...
C++初学(10)
10.1、共用体 共用体是一种数据格式,它能够存储不同的数据类型,但只能同时存储其中的一种类型。比如说:结构可以同时存储int、long、和double,而共用体只能存储int、long、或double。共用体的句式与结构相似,但含义不…...
在MAC安装Lazarus 起点 - 我们的第一个Lazarus程序!
安装Lazarus 首先到Lazarus官网,找到合适的版本下载页面,比如Mac的版本: https://sourceforge.net/projects/lazarus/files/Lazarus%20macOS%20x86-64/Lazarus%203.4/ 将三个文件都下载到本地,需要安装这三个文件: …...
【每日刷题】Day96
【每日刷题】Day96 🥕个人主页:开敲🍉 🔥所属专栏:每日刷题🍍 🌼文章目录🌼 1. LCP 44. 开幕式焰火 - 力扣(LeetCode) 2. 1022. 从根到叶的二进制数之和 - …...
EGO-Swarm 仿真环境搭建
EGO-Swarm仿真环境搭建 参考教程: https://github.com/ZJU-FAST-Lab/ego-planner-swarm EGO-Swarm是一种分散的异步系统解决方案,用于仅使用机载资源在未知的障碍物丰富的场景中进行多机器人自主导航。 1. 查看系统环境 要运行本仿真程序,…...
【EI会议征稿通知】第九届计算机技术与机械电气工程国际学术论坛(ISCME 2024)
会议官网:www.is-cme.com 一轮截稿时间:2024年8月16日(早投稿,早录用) 大会时间:2024年11月8-10日 大会地点:中国 南京 接受/拒稿通知:投稿后1-2周 收录检索:EI Compend…...
【starRocks-docker 部署问题汇总】
Starrocks系列文章目录 例如:starrocks 常见问题汇总 文章目录 Starrocks系列文章目录前言一、Starrocks-be运行一段时间后,容器无法restart?二、等待后续跟新 前言 starrocks基于docker-compose部署的3节点分布式(3FE,3BE),遇到的问题也都…...
threejs中,如何检测一个模型周边一定范围内的其它模型
在Three.js中,要检测一个模型(我们可以称之为“主体模型”)周边一定范围内的其他物体,你可以通过以下步骤来实现: 1、定义检测范围: 首先,确定你需要检测的范围,这通常是一个以主体…...
UDP端口可达性检测(端口扫描)工具开发
UDP端口可达性检测(端口扫描)工具开发 1、应用场景分析 主机X与主机Y部署在AB双网环境下,两个主机间通过UDP协议进行数据交互。应用程序发送数据时,优先使用A网发送数据,如果A网异常则通过B网发送数据。两个主机应用间没有设置心跳帧 &…...
第三届计算、通信、感知与量子技术国际会议(CCPQT 2024)会议通知
会议信息 大会官网:http://www.ccpqt.org/ 官方邮箱:ccpqt_paper126.com 会议地点:中国珠海 会议时间:2024年10月25日-10月27日 主讲嘉宾 Prof. Trung Q. Duong IEEE Fellow and AAIA Fellow Memorial University of Newfoundl…...
Qt文件读写
Qt中文件读写类简述 包含头文件#include <QFile> 读写模式如下 枚举 文件读写步骤 1 先使用string 类型来接受打开文件的返回值 QFileDialog::getOpenFileName(this,"文件","./"); //打开一个文件 2 构建文件对象 Qfile ff (qstring)接受打…...
发现了一套超厉害的英语资料,绝对YYDS
昨某节目主持人与我闲聊英语学习的事情。 她工作数年,希望提升英文资讯的阅读能力。她主持的是中文节目,但节目对个人的知识广度和深度要求颇高。 现在的知识又太泛太杂,你需要了解国外最新资讯,多获得一手资料,面对节…...
C# new关键字作用
在C#中,当子类定义了与父类同名的字段或者方法时,可以使用new关键字进行隐藏。使用new和不使用new关键字的区别主要在于如何处理字段的隐藏和可访问性。 讲人话就是,假设父类的字段或方法,子类是可以直接访问的(publi…...
Python代码之特征工程基础
1. 什么是特征工程 特征工程是指从原始数据中提取、转换和创建适合于模型训练的数据特征的过程。它是机器学习和深度学习中非常重要的一步,因为好的特征工程可以显著提高模型的性能。特征工程涉及从数据中提取有意义的信息,并将其转换为模型可以理解和使…...
低代码平台:效率利器还是质量妥协?
目录 低代码平台:效率利器还是质量妥协? 一、引言 二、低代码平台的定义和背景 1、什么是低代码平台? 2、低代码平台的兴起 三、低代码开发的机遇 1、提高开发效率 2、降低开发成本 3、赋能业务人员 四、低代码开发的挑战 1、质量…...
大数据-Big Data
1. 简介 1.1. 主要特点 大数据(Big Data)是指规模巨大、复杂多变的数据集合,这些数据集来源于多个不同的源,包括社交媒体、移动设备、物联网、传感器等。大数据的主要特点如下: 数据量大(Volume):大数据的起始计量单位是PB(1024TB)、EB(1024PB,约100万TB)或ZB(…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
倒装芯片凸点成型工艺
UBM(Under Bump Metallization)与Bump(焊球)形成工艺流程。我们可以将整张流程图分为三大阶段来理解: 🔧 一、UBM(Under Bump Metallization)工艺流程(黄色区域ÿ…...
