【汇编逆向系列】七、函数调用包含多个参数之浮点型- XMM0-3寄存器

news2026/2/19 18:45:50

目录

1. 汇编代码

1.1 debug编译

1.2 release编译

2. 汇编分析

2.1 浮点参数传递规则

2.2 栈帧rsp的变化时序

2.3 参数的访问逻辑

2.4 返回值XMM0寄存器

3. 汇编转化

3.1 Debug编译

3.2 Release 编译

3.3 C语言转化


1. 汇编代码

上一节介绍了整型的函数传参,那么浮点型有什么不同,将在这一节介绍,包含float和double的浮点型都是类似的传参方式。这一节将不再区分少数参数和多个参数,直接使用多个参数浮点型的汇编代码例子。

1.1 debug编译

many_double_params:
  0000000000000A20: F2 0F 11 5C 24 20  movsd       mmword ptr [rsp+20h],xmm3
  0000000000000A26: F2 0F 11 54 24 18  movsd       mmword ptr [rsp+18h],xmm2
  0000000000000A2C: F2 0F 11 4C 24 10  movsd       mmword ptr [rsp+10h],xmm1
  0000000000000A32: F2 0F 11 44 24 08  movsd       mmword ptr [rsp+8],xmm0
  0000000000000A38: 57                 push        rdi
  0000000000000A39: 48 83 EC 10        sub         rsp,10h
  0000000000000A3D: 48 8B FC           mov         rdi,rsp
  0000000000000A40: B9 04 00 00 00     mov         ecx,4
  0000000000000A45: B8 CC CC CC CC     mov         eax,0CCCCCCCCh
  0000000000000A4A: F3 AB              rep stos    dword ptr [rdi]
  0000000000000A4C: F2 0F 10 44 24 20  movsd       xmm0,mmword ptr [rsp+20h]
  0000000000000A52: F2 0F 58 44 24 28  addsd       xmm0,mmword ptr [rsp+28h]
  0000000000000A58: F2 0F 58 44 24 30  addsd       xmm0,mmword ptr [rsp+30h]
  0000000000000A5E: F2 0F 58 44 24 38  addsd       xmm0,mmword ptr [rsp+38h]
  0000000000000A64: F2 0F 58 44 24 40  addsd       xmm0,mmword ptr [rsp+40h]
  0000000000000A6A: F2 0F 58 44 24 48  addsd       xmm0,mmword ptr [rsp+48h]
  0000000000000A70: F2 0F 5E 05 00 00  divsd       xmm0,mmword ptr [__real@4018000000000000]
                    00 00
  0000000000000A78: 48 83 C4 10        add         rsp,10h
  0000000000000A7C: 5F                 pop         rdi
  0000000000000A7D: C3                 ret
  0000000000000A7E: CC                 int         3
  0000000000000A7F: CC                 int         3
  0000000000000A80: CC                 int         3

1.2 release编译


many_double_params:
  0000000000000000: F2 0F 58 C1        addsd       xmm0,xmm1
  0000000000000004: F2 0F 58 C2        addsd       xmm0,xmm2
  0000000000000008: F2 0F 58 C3        addsd       xmm0,xmm3
  000000000000000C: F2 0F 58 44 24 28  addsd       xmm0,mmword ptr [rsp+28h]
  0000000000000012: F2 0F 58 44 24 30  addsd       xmm0,mmword ptr [rsp+30h]
  0000000000000018: F2 0F 5E 05 00 00  divsd       xmm0,mmword ptr [__real@4018000000000000]
                    00 00
  0000000000000020: C3                 ret

2. 汇编分析

2.1 浮点参数传递规则

在 Windows x64 调用约定中:

  • 前 4 个浮点参数​​通过 XMM0-XMM3 寄存器传递
  • 第 5 个及以上参数​​通过栈传递(从右向左压栈)
  • 调用者需预留 ​​32 字节影子空间​​(Shadow Space),用于被调函数保存寄存器参数

2.2 栈帧rsp的变化时序

在栈帧变化上浮点型与整型保持着完全一致的逻辑

; 1. 保存前4个浮点参数到影子空间
movsd [rsp+20h], xmm3   ; 参数4 → [影子空间+0x20]
movsd [rsp+18h], xmm2   ; 参数3 → [影子空间+0x18]
movsd [rsp+10h], xmm1   ; 参数2 → [影子空间+0x10]
movsd [rsp+8],   xmm0   ; 参数1 → [影子空间+0x08]

; 2. 保存非易失寄存器
push rdi                 ; RSP -= 8

; 3. 分配局部变量空间
sub rsp, 10h             ; RSP -= 16 (0x10)

; 4. 初始化局部空间(调试版行为)
mov rdi, rsp
mov ecx, 4
mov eax, 0CCCCCCCCh      ; 填充未初始化数据标记
rep stosd                ; 用 0xCC 填充 16 字节

 在call指令调用函数时,栈帧rsp-=8, 所以影子空间的位置都要+0x08, 由[rsp]-[rsp+0x20]变化为[rsp+8]-[rsp+0x28]所以movsd [rsp+8], xmm0 ; 参数1 → [影子空间+0x08],第一个参数是放在[rsp+8]。

在push rdi 后, 再次 rsp-=8, 此时所有参数位置要再次+ 0x08

在sub rsp 10h之后,再次 rsp -= 0x10, 所以所有参数位置再次+ 0x10h

这里也充分说明了局部变量的地址是向下增长的

2.3 参数的访问逻辑

; 加载并累加参数(偏移基于当前 RSP)
movsd xmm0, [rsp+20h]   ; 加载参数1 (当前 RSP+0x20 = 原始影子空间+0x08)
addsd xmm0, [rsp+28h]   ; + 参数2 (原始影子空间+0x10)
addsd xmm0, [rsp+30h]   ; + 参数3 (原始影子空间+0x18)
addsd xmm0, [rsp+38h]   ; + 参数4 (原始影子空间+0x20)
addsd xmm0, [rsp+40h]   ; + 参数5 (调用者压栈的第1个额外参数)
addsd xmm0, [rsp+48h]   ; + 参数6 (调用者压栈的第2个额外参数)

由于栈是向下增长的,从参数六开始压栈,参数1 的地址其实是最低的

2.4 返回值XMM0寄存器

在x64架构下,浮点计算的返回值统一使用 ​​XMM0 寄存器​​作为传递载体。这一规则适用于单精度(float)和双精度(double)浮点数,且是跨操作系统(如 Windows 和 Linux)的标准约定

浮点类型​​(包括 floatdouble):结果存储在 XMM0 的低位部分:

  • ​单精度​​(32位):使用 XMM0 的低32位
  • 双精度​​(64位):使用 XMM0 的低64位

3. 汇编转化

3.1 Debug编译

movsd [rsp+20h], xmm3   ; 保存第4个参数(xmm3 → [影子空间+0x20])[1](@ref)
movsd [rsp+18h], xmm2   ; 保存第3个参数(xmm2 → [影子空间+0x18])
movsd [rsp+10h], xmm1   ; 保存第2个参数(xmm1 → [影子空间+0x10])
movsd [rsp+8], xmm0     ; 保存第1个参数(xmm0 → [影子空间+0x08])
push rdi                ; 保存非易失寄存器 RDI(RSP -= 8)
sub rsp, 10h            ; 分配 16 字节局部空间(RSP -= 16)
mov rdi, rsp
mov ecx, 4             ; 循环4次(4×4字节=16字节)
mov eax, 0CCCCCCCCh    ; 未初始化内存标记(调试用)
rep stosd              ; 用 0xCC 填充局部空间
movsd xmm0, [rsp+20h]   ; 加载第1个参数(原始 xmm0)
addsd xmm0, [rsp+28h]   ; + 第2个参数(原始 xmm1)
addsd xmm0, [rsp+30h]   ; + 第3个参数(原始 xmm2)
addsd xmm0, [rsp+38h]   ; + 第4个参数(原始 xmm3)
addsd xmm0, [rsp+40h]   ; + 第5个参数(栈传递)
addsd xmm0, [rsp+48h]   ; + 第6个参数(栈传递)
divsd xmm0, [__real@4018000000000000]  ; xmm0 /= 6.0
add rsp, 10h            ; 释放局部空间(RSP += 16)
pop rdi                 ; 恢复 RDI(RSP += 8)
ret                     ; 返回结果(xmm0 作为返回值)

3.2 Release 编译

; 函数入口点,参数通过寄存器和栈传递
0000000000000000: 8D 04 11           lea         eax, [rcx+rdx]   ; EAX = 参数1(RCX) + 参数2(RDX)
0000000000000003: 41 03 C0           add         eax, r8d          ; EAX += 参数3(R8D)
0000000000000006: 41 03 C1           add         eax, r9d          ; EAX += 参数4(R9D)
0000000000000009: 03 44 24 28        add         eax, dword ptr [rsp+28h] ; EAX += 参数5(栈偏移0x28)
000000000000000D: 03 44 24 30        add         eax, dword ptr [rsp+30h] ; EAX += 参数6(栈偏移0x30)
0000000000000011: 03 44 24 38        add         eax, dword ptr [rsp+38h] ; EAX += 参数7(栈偏移0x38)
0000000000000015: 03 44 24 40        add         eax, dword ptr [rsp+40h] ; EAX += 参数8(栈偏移0x40)
0000000000000019: 03 44 24 48        add         eax, dword ptr [rsp+48h] ; EAX += 参数9(栈偏移0x48)
000000000000001D: 03 44 24 50        add         eax, dword ptr [rsp+50h] ; EAX += 参数10(栈偏移0x50)
0000000000000021: C3                 ret                          ; 返回结果(EAX为返回值)

3.3 C语言转化

#include <stdint.h>

// 函数原型(6个 double 参数)
double many_double_params(
    double p1, double p2, double p3, double p4,
    double p5, double p6
) {
    // 累加所有参数
    double sum = p1 + p2 + p3 + p4 + p5 + p6;
    // 除以 6.0 后返回
    return sum / 6.0;
}

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

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

相关文章

【MySQL系列】MySQL 执行 SQL 文件

博客目录 一、MySQL 执行 SQL 文件的常见场景二、MySQL 执行 SQL 文件的主要方法1. 使用 MySQL 命令行客户端2. 在 MySQL 交互界面中使用 source 命令3. 使用 MySQL Workbench 等图形化工具4. 使用编程语言接口 三、执行 SQL 文件时的注意事项1. 字符集问题2. 事务处理3. 错误处…

论文MR-SVD

每个像素 7 个 FLOPs意思&#xff1a; FLOPs&#xff08;浮点运算次数&#xff09;&#xff1a;衡量算法计算复杂度的指标&#xff0c;数值越小表示运算越高效。含义&#xff1a;对图像中每个像素进行处理时&#xff0c;仅需执行7 次浮点运算&#xff08;如加减乘除等&#xf…

Java 日期时间类全面解析

Java 日期时间类全面解析&#xff1a;从传统到现代的演进 一、发展历程概览 二、传统日期类&#xff08;Java 8前&#xff09; 1. java.util.Date - 日期表示类 Date now new Date(); // 当前日期时间 System.out.println(now); // Wed May 15 09:30:45 CST 2023// 特定时间…

【工具-Wireshark 抓包工具】

工具-Wireshark 抓包工具 ■ Wireshark 抓包工具■ 通过IP指定查看■■ ■ Wireshark 抓包工具 抓包工具】win 10 / win 11&#xff1a;WireShark 下载、安装、使用 Wireshark下载 阿里云镜像 ■ 通过IP指定查看 ■ ■

设备驱动与文件系统:06 目录与文件

磁盘使用的最后一层抽象&#xff1a;文件系统 今天我们讲第31讲&#xff0c;这一讲将完成磁盘对磁盘使用的最后一层抽象。对此板使用最后一层抽象&#xff0c;抽象出来的是什么呢&#xff1f; 实际上我们使用过磁盘&#xff0c;大家应该有这样的认识&#xff0c;最后不管这个磁…

Linux 系统中的算法技巧与性能优化

引言​ Linux 系统以其开源、稳定和高度可定制的特性&#xff0c;在服务器端、嵌入式设备以及开发环境中得到了极为广泛的应用。对于开发者而言&#xff0c;不仅要掌握在 Linux 环境下实现各类算法的方法&#xff0c;更要知晓如何利用系统特性对算法进行优化&#xff0c;以提升…

【C++系列】模板类型特例化

1. C模板类型特例化介绍 ​​定义​​&#xff1a;模板类型特例化&#xff08;Template Specialization&#xff09;是C中为模板的特定类型提供定制实现的机制&#xff0c;允许开发者对通用模板无法处理的特殊类型进行优化或特殊处理。 ​​产生标准​​&#xff1a; C98/03…

K8S认证|CKS题库+答案| 7. Dockerfile 检测

目录 7. Dockerfile 检测 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、修改 Dockerfile 3&#xff09;、 修改 deployment.yaml 7. Dockerfile 检测 免费获取并激活 CKA_v1.31_模拟系统 题目 您必须在以…

基于Scala实现Flink的三种基本时间窗口操作

目录 代码结构 代码解析 (1) 主程序入口 (2) 窗口联结&#xff08;Window Join&#xff09; (3) 间隔联结&#xff08;Interval Join&#xff09; (4) 窗口同组联结&#xff08;CoGroup&#xff09; (5) 执行任务 代码优化 (1) 时间戳分配 (2) 窗口大小 (3) 输出格式…

c++对halcon的动态链接库dll封装及调用(细细讲)

七个部分(是个大工程) 一,halcon封装函数导出cpp的内容介绍 二,c++中对halcon环境的配置 三,在配置环境下验证halcon代码 四,dll项目创建+环境配置 五,编辑dll及导出 六,调用打包好的动态链接库的配置 七,进行测试 一,halcon的封装及导出cpp的介绍 1,我这里…

【优选算法】分治

一&#xff1a;颜色分类 class Solution { public:void sortColors(vector<int>& nums) {// 三指针法int n nums.size();int left -1, right n, i 0;while(i < right){if(nums[i] 0) swap(nums[left], nums[i]);else if(nums[i] 2) swap(nums[--right], num…

【图片识别改名】如何批量将图片按图片上文字重命名?自动批量识别图片文字并命名,基于图片文字内容改名,WPF和京东ocr识别的解决方案

应用场景 在日常工作和生活中&#xff0c;我们经常会遇到需要对大量图片进行重命名的情况。例如&#xff0c;设计师可能需要根据图片内容为设计素材命名&#xff0c;文档管理人员可能需要根据扫描文档中的文字对图片进行分类命名。传统的手动重命名方式效率低下且容易出错&…

RabbitMQ 的高可用性

RabbitMQ 是比较有代表性的&#xff0c;因为是基于主从&#xff08;非分布式&#xff09;做高可用的RabbitMQ 有三种模式&#xff1a;单机模式、普通集群模式、镜像集群模式。 单机模式 单机模式,生产几乎不用。 普通集群模式&#xff08;无高可用性&#xff09; 普通集群模…

AI架构师修炼之道

1 AI时代的架构革命 与传统软件开发和软件架构师相比&#xff0c;AI架构师面临着三重范式转换&#xff1a; 1.1 技术维度&#xff0c;需处理异构算力调度与模型生命周期管理的复杂性&#xff1b; 1.2 系统维度&#xff0c;需平衡实时性与资源约束的矛盾&#xff1b; 1.3 价…

iview组件库:当后台返回到的数据与使用官网组件指定的字段不匹配时,进行修改某个属性名再将response数据渲染到页面上的处理

1、需求导入 当存在前端需要的数据的字段渲染到表格或者是一些公共的表格组件展示数据时的某个字段名与后台返回的字段不一致时&#xff0c;那么需要前端进行稍加处理&#xff0c;而不能直接this.list res.data;这样数据是渲染不出来的。 2、后台返回的数据类型 Datalist(pn) …

服务器 | Centos 9 系统中,如何部署SpringBoot后端项目?

系列文章目录 虚拟机 | Ubuntu 安装流程以及界面太小问题解决 虚拟机 | Ubuntu图形化系统&#xff1a; open-vm-tools安装失败以及实现文件拖放 虚拟机 | Ubuntu操作系统&#xff1a;su和sudo理解及如何处理忘记root密码 文章目录 系列文章目录前言一、环境介绍二、 使用syst…

(2025)Windows修改JupyterNotebook的字体,使用JetBrains Mono

(JetBrains Mono字体未下载就配置,这种情况我不知道能不能行,没做过实验,因为我电脑已经下载了,不可能删了那么多字体做实验,我的建议是下载JetBrains Mono字体,当你使用VsCode配置里面的JetBrains字体也很有用) 首先参考该文章下载字体到电脑上 VSCode 修改字体为JetBrains …

小番茄C盘清理:专业高效的电脑磁盘清理工具

在使用电脑的过程中&#xff0c;我们常常会遇到系统盘空间不足、磁盘碎片过多、垃圾文件堆积等问题&#xff0c;这些问题不仅会导致电脑运行缓慢&#xff0c;还可能引发系统崩溃。为了解决这些问题&#xff0c;小番茄C盘清理应运而生。它是一款专业的C盘清理软件&#xff0c;能…

AUTOSAR实战教程--标准协议栈实现DoIP转DoCAN的方法

目录 软件架构 关键知识点 第一:PDUR的缓存作用 第二:CANTP的组包拆包功能 第三:流控帧的意义 配置过程 步骤0:ECUC模块中PDU创建 步骤1:SoAD模块维持不变 步骤2:DoIP模块为Gateway功能添加Connection ​步骤3:DoIP模块为Gateway新增LA/TA/SA ​步骤4:PDUR模…

【MySQL系列】MySQL 导出表数据到文件

博客目录 一、使用 SELECT INTO OUTFILE 语句基本语法参数详解注意事项实际示例 二、使用 mysqldump 工具基本语法常用选项实际示例 三、使用 MySQL Workbench 导出导出步骤高级选项 四、其他导出方法1. 使用 mysql 命令行客户端2. 使用 LOAD DATA INFILE 的逆向操作3. 使用编程…