X32位汇编和X64位区别无参函数分析(一)

前言

一、X32汇编函数无参无返回分析

二、X64汇编函数无参无返回分析

总结


前言

提示:以下是个人学习总结:如有错误请大神指出来,只供学习参考,本内容使用使用VS2017开发工具:语言是C++,需要一些常见的汇编指令,寄存器的概念,不会的可以看下其他的博主的,我用的这里方便学习全程debug,函数用的默认C++cdecl调用约定模式(可以网上查下调用约定,右边入参到左边,称为外平栈)。


好久没更新博客了,准备把汇编自我总结复习的顺带把过程记录下来,接下来开始吧,准备简单的无参函数。

一、X32汇编函数无参无返回分析

1.代码图片(示例):

不知道为什么不能赋值图这里直接赋值代码了。
#include <iostream>void shenjianxz() {int a;int c;int d = 3;int d2 = 4;a = d - d2;
}int main()
{shenjianxz();}

0099179E call        00991131 这个就是上面那个简单shenjianxz()函数调用,

CPU主要执行的是根据EIP执行跳转的,

call指令会 push 009917A3 压栈 :因为我们调用完函数返回的时候会取这个地址,跳转到下一行执行的代码,  EIP寄存器=00991131

现在我们跳去看看按F11

这里 jmp    中间跳转程序空间保存的函数地址    00EA1750,咱们先不管,这不是重点

简单解下:jmp 只改变eip地址,cpu会自动运行到执行的地址去,在点下F11进入 调用函数代码区了。

重点关注下:ESP寄存器到哪了,EBP寄存器值等于多少。

我讲解下上面代码含义:

shenjianxz
009918F0  push        ebp  

保留ebp 寄存器
009918F1  mov         ebp,esp  
为了后面恢复esp栈顶位置把他赋值给ebp进行操作
009918F3  sub         esp,0F0h  

因为前面已经保存了esp的赋值,就不担心这里esp就开始扩展0F0h 位置esp位置肯定就变了
009918F9  push        ebx  
009918FA  push        esi  
009918FB  push        edi  
保留 ebx,esi,edi 寄存器位置
009918FC  lea         edi,[ebp-0F0h]  

这里ebp的作用就体现了,最前面我们不是把esp赋值给了ebp吗,
这里就代表把sub         esp,0F0h  地址赋值给edl

00991902  mov         ecx,3Ch    3c次数
00991907  mov         eax,0CCCCCCCCh  
0099190C  rep stos    dword ptr es:[edi]  
重复3c次把occccccch=int 3先不用管,就理解是ccccccc赋值给edi 每次成功赋值就 edi+4
0099190E  mov         dword ptr [ebp-20h],3  
00991915  mov         dword ptr [ebp-2Ch],4  
0099191C  mov         eax,dword ptr [ebp-20h]  
0099191F  sub         eax,dword ptr [ebp-2Ch]  

ebp的位置是push ebp的位置,之后不是 ebp=esb 下一句不是 sub         esp,0F0h  扩展了0f0的大小空间么
那么ebp-20,-2c都是在扩展的位置区间,可见X32是ebp-N代表取局部变量

00991922  mov         dword ptr [ebp-8],eax  
最终把结果放到ebp-8内存中
00991925  pop         edi  
00991926  pop         esi  
00991927  pop         ebx  
因为esp一直在栈顶所以还原3个寄存器 esp-Ch位置
00991928  mov         esp,ebp  
esp已经距离很远了,因为扩展了0F0h大小字节,所以用ebp恢复esp位置esp在 push ebp位置了
0099192A  pop         ebp  
恢复ebp栈底
0099192B  ret  
之前我们用call 调用的函数,这里面push的是 call的下一条代码地址=pop eip 让cpu跳转到eip位置,下面是对应的自己画的图:

2.小结:
    1:X32是先保留push ebp寄存器,在扩展堆栈大小
    2:mov         ebp,esp 保留栈顶位置,方便后面恢复
    3:[ebp-20],[ebp-2c]都是在扩展的位置区间,可见X32是ebp-N代表取局部变量,参数获取(这里演示无参数)

二、X64汇编函数无参无返回分析

1.代码图片(示例)

同样的代码看不同:

前面讲过,这里也是jmp方式跳转到函数代码快,继续F11跟进去,因为中间重启过地址发生变化,直接看下面的函数内容就行

00007FF7CA1717C0  push        rbp  
00007FF7CA1717C2  push        rdi  
00007FF7CA1717C3  sub         rsp,168h  
00007FF7CA1717CA  lea         rbp,[rsp+20h]  
00007FF7CA1717CF  mov         rdi,rsp  
00007FF7CA1717D2  mov         ecx,5Ah  
00007FF7CA1717D7  mov         eax,0CCCCCCCCh  
00007FF7CA1717DC  rep stos    dword ptr [rdi]  
这里是重复ecx的次数填充栈顶开始往回每次 rdi+4
00007FF7CA1717DE  lea         rcx,[__D730393F_c@cpp (07FF7CA181027h)] 
00007FF7CA1717E5  call        __CheckForDebuggerJustMyCode (07FF7CA171087h)
这2行 因为是debug模式是检测堆栈的直接跳过看下面的  
00007FF7CA1717EA  mov         dword ptr [rbp+44h],3  
00007FF7CA1717F1  mov         dword ptr [rbp+64h],4  
RBP+N 代表局部变量,在X32中是EBP-N代表局部变量,那么这里就是把立即数赋值给局部变量
我的理解因为之前 扩展168h,rsp,168h 
这里局部变量不能>rbp+148h大小范围,因为rsp+20了之前,大于了下一条就到了push rdi的位置了

00007FF7CA1717F8  mov         eax,dword ptr [rbp+64h]  
00007FF7CA1717FB  mov         ecx,dword ptr [rbp+44h]  
看这里rbp+64 ,+44都是在扩展的局部变量赋值,在范围内
00007FF7CA1717FE  sub         ecx,eax  
00007FF7CA171800  mov         eax,ecx  
00007FF7CA171802  mov         dword ptr [rbp+4],eax  
最后把值赋值给局部变量rbp+4
00007FF7CA171805  lea         rsp,[rbp+0000000000000148h]  
之前rsp-168h,然后rbp+20 这里在加个148h 不就回去了最早的push RDI位置
00007FF7CA17180C  pop         rdi  
00007FF7CA17180D  pop         rbp  
这里就是恢复 RDI RBP里的值
00007FF7CA17180E  ret  这里pop eip 让cpu跳转到调用程序下一条指令执行

 


三、X32位汇编和X64位区别无参函数调用

总结

提示:可以看下对比堆栈图变化和我说的文字区别

X32:
    1:X32是先保留push ebp寄存器,在扩展堆栈大小
    2:mov         ebp,esp 保留栈顶位置,方便后面恢复
    3:[ebp-20],[ebp-2c]都是在扩展的位置区间,可见X32是ebp-N代表取局部变量,参数获取(这里演示无参数)

X64:

   1:X64是先扩展栈顶大小,在进行保留寄存器
    2:EBP+N是获取局部变量
    3:EBP+20=ESP+20,后用EBP进行局部变量赋值,参数获取(这里演示无参数)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/114780.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手机知识:安卓内存都卷到24GB了,为何iPhone还在固守8GB

目录 一、系统机制 二、生态差异 三、总结 在刚刚过去的9月&#xff0c;年货iPhone 15系列正式发布&#xff0c;标准版不出意外还是挤药膏&#xff0c;除了镜头、屏幕有些升级&#xff0c;芯片用iPhone 14 Pro系列的&#xff0c;内存只有6GB&#xff1b;即使是集钛合金机身、…

【大数据】Kafka 实战教程(一)

Kafka 实战教程&#xff08;一&#xff09; 1.Kafka 介绍1.1. 主要功能1.2. 使用场景1.3 详细介绍1.3.1 消息传输流程1.3.2 Kafka 服务器消息存储策略1.3.3 与生产者的交互1.3.4 与消费者的交互 2.Kafka 生产者3.Kafka 消费者3.1 Kafka 消费模式3.1.1 At-most-once&#xff08;…

NVIDIA NCCL 源码学习(十一)- ring allreduce

之前的章节里我们看到了nccl send/recv通信的过程&#xff0c;本节我们以ring allreduce为例看下集合通信的过程。整体执行流程和send/recv很像&#xff0c;所以对于相似的流程只做简单介绍&#xff0c;主要介绍ring allreduce自己特有内容。 单机 搜索ring 在nccl初始化的过…

51单片机仿真软件 Proteus 8 Pro 安装步骤

51单片机仿真软件 Proteus 8 Pro 安装步骤 学习 51 单片机的时候&#xff0c;如果手头没有开发板&#xff0c;可以使用仿真软件 Proteus。Proteus 可以仿真 51 单片机及周边元器件&#xff08;例&#xff1a; LED&#xff09; 的运行情况。 可以简单认为&#xff1a;Proteus …

经典链表问题:解析链表中的关键挑战

这里写目录标题 公共子节点采用集合或者哈希采用栈拼接两个字符串差和双指针 旋转链表 公共子节点 例如这样一道题&#xff1a;给定两个链表&#xff0c;找出它们的第一个公共节点。 具体的题目描述我们来看看牛客的一道题&#xff1a; 这里我们有四种解决办法&#xff1a; …

pandas写入MySQL

安装好pandas、mysql pip install pandas pip install pymysql 导入pandas、mysql import pymysql as mysql import pandas as pd 建立连接 conmysql.connect(host10.10.0.221,userroot,passwordroot,databasepandas,port3306,charsetutf8) 创建游标 curcon.cursor() 读…

文档的重要性及接口文档模板

随着工作年限的增长&#xff0c;我们逐渐意识到工作中文档的重要性不可忽视。优质的文档不仅能提高工作效率&#xff0c;还能有效降低沟通成本&#xff0c;因此我们必须注重文档的撰写和格式。最近&#xff0c;由于未能及时更新文档&#xff0c;导致在项目开发中出现了信息冲突…

Vue解决 npm -v 报错(一)

报错内容&#xff1a; npm WARN config global --global, --local are deprecated. Use --locationglobal instead. 解决方案&#xff1a; 代码&#xff1a; prefix -g 替换为&#xff1a; prefix --locationglobal 原创作者&#xff1a;吴小糖 创作时间&#xff1a;2023.1…

文心一言 VS 讯飞星火 VS chatgpt (118)-- 算法导论10.3 3题

三、用go语言&#xff0c;在ALLOCATE-OBJECT和 FREE-OBJECT过程的实现中&#xff0c;为什么不需要设置或重置对象的 prev 属性呢? 文心一言&#xff1a; 在 Go 语言中&#xff0c;ALLOCATE-OBJECT 和 FREE-OBJECT 过程的实现通常不需要显式地设置或重置对象的 prev 属性。这…

Java EE-使用Servlet搭建一个简单的前后端交互程序

上述前端和后端的代码如下&#xff1a; 前端&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"vie…

搭建网站七牛云CDN加速配置

打开七牛云后台&#xff1b;添加域名&#xff1b; 添加需要加速的域名&#xff0c;比如我添加的是motoshare.cn 源站配置&#xff0c;这里要用IP地址&#xff0c;访问的目录下面要有能访问测试的文件&#xff0c;尽量不要用源站域名&#xff0c;这个只能用加速二级域名&#x…

【试题039】 多个逻辑或例题

题目&#xff1a;设int n;,执行表达式(n0)||(n1)||(n2)||(n3)后,n的值是&#xff1f;代码分析&#xff1a; //设int n; , 执行表达式(n 0) || (n 1) ||(n 2) ||(n 3)后, n的值是?int n;printf("n%d\n", (n 0) || (n 1) || (n 2) || (n 3));//分析&#xff1…

STM32-LTC6804方案成熟BMS方案

方案下载链接&#xff01;&#xff01;https://mp.weixin.qq.com/s?__bizMzU2OTc4ODA4OA&mid2247549092&idx1&snc73855c4e3d5afddd8608d8528864f95&chksmfcfb1373cb8c9a65a4bd1f545a1a587af882f209e7ccbb8944f4d2514d241ca1d7fcc4615e10&token539106225&a…

vue 插槽 作用域插槽

vue 插槽 作用域插槽 **创建 工程&#xff1a; H:\java_work\java_springboot\vue_study ctrl按住不放 右键 悬着 powershell H:\java_work\java_springboot\js_study\Vue2_3入门到实战-配套资料\01-随堂代码素材\day05\准备代码\10-插槽-作用域插槽 vue --version vue crea…

01-JVM 内存结构

JVM 内存结构 Java 虚拟机的内存空间分为 5 个部分&#xff1a; 程序计数器Java 虚拟机栈本地方法栈堆方法区 JDK 1.8 同 JDK 1.7 比&#xff0c;最大的差别就是&#xff1a;元数据区取代了永久代。元空间的本质和永久代类似&#xff0c;都是对 JVM 规范中方法区的实现。不过…

【工具】利用ffmpeg将网页中的.m3u8视频文件转化为.mp4格式

目录 0.环境 1.背景 2.前提 3.详细描述 1&#xff09;在网站上找到你想下载的视频的.m3u8链接 2&#xff09;打开命令行&#xff0c;用ffmpeg命令进行转化 3&#xff09;过程&结果截图 0.环境 windows64 ffmpeg 1.背景 网页上有个.m3u8格式的视频文件&#xff0c;…

Redis 主从复制,哨兵,集群——(2)哨兵篇

目录 1. Redis 哨兵是什么&#xff1f; 2. Redis 哨兵有什么用&#xff1f; 2.1 主动监控 2.2 消息通知 2.3 故障转移 2.4 配置中心 3. Redis 哨兵数量配备要求 4. 哨兵配置文件详解 5. quorum 投票数详解 5.1 quorum 的含义 5.2 网络抖动导致主观下线 5.3 quorum …

云计算与云服务

云计算与大数据 1、虚拟化简介1.1、什么是虚拟化1.2、虚拟化的分类 2、云计算与云服务2.1、云计算2.2、云服务2.3、云计算的特点 3、云服务模式&#xff08;IaaS、PaaS、SaaS和DaaS&#xff09;4、云计算分类&#xff08;公有云、私有云和混合云&#xff09; 1、虚拟化简介 当下…

ToDoList全局事件总线学习笔记

全局事件总线 全局事件总线&#xff1a;任意组件间通信 安装全局事件总线 new Vue({……beforeCreate(){Vue.prototype.$busthis},…… })使用事件总线 接收数据&#xff1a;A组件想接收数据&#xff0c;则在A组件中给$bus绑定自定义事件&#xff0c;事件的回调留在A组件自…

react 学习 —— 16、使用 ref 操作 DOM

什么时候使用 ref 操作 DOM&#xff1f; 有时你可能需要访问由 React 管理的 DOM 元素 —— 例如&#xff0c;让一个节点获得焦点、滚动到它或测量它的尺寸和位置。在 React 中没有内置的方法来做这些事情&#xff0c;所以你需要一个指向 DOM 节点的 ref 来实现。 怎么使用 r…