四、函数调用包含单个参数之Double类型-mmword,movsd,mulsd,addsd指令,总结汇编的数据类型
一、汇编代码
上一节开始,讲到了很多debug编译独有的汇编方式,为了更好的区分release的编译器优化和debug的区别,从本章节开始将会提供debug和release的汇编用作对比
Debugb编译
single_double_param:00000000000000A0: F2 0F 11 44 24 08 movsd mmword ptr [rsp+8],xmm000000000000000A6: 57 push rdi00000000000000A7: 48 83 EC 10 sub rsp,10h00000000000000AB: 48 8B FC mov rdi,rsp00000000000000AE: B9 04 00 00 00 mov ecx,400000000000000B3: B8 CC CC CC CC mov eax,0CCCCCCCCh00000000000000B8: F3 AB rep stos dword ptr [rdi]00000000000000BA: F2 0F 10 44 24 20 movsd xmm0,mmword ptr [rsp+20h]00000000000000C0: F2 0F 59 05 00 00 mulsd xmm0,mmword ptr [__real@4004000000000000]00 0000000000000000C8: F2 0F 58 05 00 00 addsd xmm0,mmword ptr [__real@3ff4000000000000]00 0000000000000000D0: 48 83 C4 10 add rsp,10h00000000000000D4: 5F pop rdi00000000000000D5: C3 ret
Release编译
single_double_param:0000000000000000: F2 0F 59 05 00 00 mulsd xmm0,mmword ptr [__real@4004000000000000]00 000000000000000008: F2 0F 58 05 00 00 addsd xmm0,mmword ptr [__real@3ff4000000000000]00 000000000000000010: C3 ret
二、汇编分析
1. 栈区空间
和浮点类型类似的同样需要申请16个字节的安全空间,使用的方法也是一样的,同时在release编译中也优化掉了这一部分。详细介绍请看上一章节
sub rsp, 10h ; 分配16字节栈空间
mov rdi, rsp ; rdi指向栈顶
mov ecx, 4 ; 循环4次
mov eax, 0CCCCCCCCh ; 初始化值0xCC(调试模式填充)
rep stos dword ptr [rdi] ; 用0xCC填充栈空间(调试用)
2. Double类型在内存空间的表示
在计算机编程中,double
类型(双精度浮点数)的内存空间占用和结构遵循IEEE 754标准,无论系统架构(32位或64位)或编译器类型,double
类型始终占用 8字节(64位)内存空间,这是IEEE 754标准对双精度浮点数的统一规定,与单精度浮点数(float
,4字节)和长双精度(long double
,通常16字节)形成对比。
double
类型的64位内存空间划分为三个部分:
a.符号位(Sign):1位
0
表示正数,1
表示负数
b. 指数位(Exponent):11位
采用偏移表示法(偏移量1023),实际指数范围为 -1022 到 1023,支持表示极大或极小的数值(如±10⁻³⁰⁸ 到 ±10³⁰⁸)
c. 尾数位(Mantissa):52位
存储小数部分,隐含整数位1
(规格化数),实际精度为 53位二进制有效数字,等效约 15–17位十进制有效数字
这部分的计算方式完全和float类型一致,只是不同类型的位数不同
3. mmword
MMWORD
是 x86/x64 汇编语言中的一种数据类型标识符,主要用于处理 64 位多媒体操作数,尤其在 MMX(MultiMedia eXtensions)和 SSE(Streaming SIMD Extensions)指令集中。以下是其核心要点:
a. 数据类型标识
MMWORD
在汇编中表示一个 64 位(8 字节)的多媒体数据单元,与__m64
(C/C++ 中的 MMX 数据类型)等价- 用于明确操作数的位宽和语义,避免与普通整型混淆(如
QWORD
虽同为 64 位,但表示无符号整数)
b. 指令操作对象
常见于 MMX/SSE 指令的操作数中,例如:
movq mm0, mmword ptr [ebx] ; 将内存中 64 位数据加载到 MMX 寄存器 mm0
mmword ptr
修饰内存地址,指明操作数大小为 64 位
拓展:
windows x64汇编中常见的数据单位总结
一、 基础存储单位
单位 位宽 字节数 定义 典型应用 bit 1位 1/8字节 最小二进制单元(0或1) 布尔运算、硬件标志位 Byte 6位 1字节 由8个bit组成,存储基本单元 字符编码(ASCII)、内存寻址最小单位 Word 16位 2字节 早期CPU一次处理的数据长度 16位系统整数运算(如8086) DWord 32位 4字节 双字(Double Word),由2个Word组成 32位系统整数/指针操作 QWord 64位 8字节 四字(Quad Word),由4个Word或2个DWord组成 64位系统长整型、双精度浮点数 💡 关键说明:
- Word长度可变性:在32位系统中,Word可能被定义为32位(如x86架构)
- 字节固定性:1 Byte恒等于8 bit,不受架构影响
二、 多媒体拓展单位(SIMD指令集专用)
单位 位宽 字节数 对应指令集 典型应用 MMWord 64位 8字节 MMX 早期图像/音频处理(如像素块操作) XMMWord 128位 16字节 SSE/AVX 向量化浮点运算(如4×32位浮点并行) 🔬 技术演进:
- MMWord:复用FPU寄存器,操作64位整数
- XMMWord:SSE引入独立128位寄存器,支持浮点与整型并行计算
4. 逻辑运算指令
该示例中用到了movsd,mulsd,addsd三种64位的浮点数运算
指令 | 操作数格式 | 功能 | 详细介绍 | 适用场景 |
MOVSD | xmm_dest, src | 复制浮点数 | 将 64 位双精度浮点数 从源操作数(内存或 XMM 寄存器)复制到目标操作数(XMM 寄存器) | 加载/存储浮点数据 |
MULSD | xmm_dest, src | 浮点数乘法 | 将目标 XMM 寄存器中的双精度浮点数 乘以 源操作数(内存或 XMM 寄存器),结果存回目标寄存器 | 标量乘法运算 |
ADDSD | xmm_dest, src | 浮点数加法 | 将目标 XMM 寄存器中的双精度浮点数 加上 源操作数(内存或 XMM 寄存器),结果存回目标寄存器 | 标量加法运算 |
三、 汇编转化
movsd mmword ptr [rsp+8], xmm0 ; 将浮点参数保存到栈[rsp+8]
push rdi ; 保存rdi寄存器(被调用者保存)
sub rsp, 10h ; 分配16字节栈空间
mov rdi, rsp ; rdi指向栈顶
mov ecx, 4 ; 循环4次
mov eax, 0CCCCCCCCh ; 初始化值0xCC(调试模式填充)
rep stos dword ptr [rdi] ; 用0xCC填充栈空间(调试用)
movsd xmm0, mmword ptr [rsp+20h] ; 从栈[rsp+0x20]加载参数到xmm0
mulsd xmm0, mmword ptr [__real@4004000000000000] ; 乘以常量2.5(0x400400...)
addsd xmm0, mmword ptr [__real@3ff4000000000000] ; 加上常量1.25(0x3ff400...)
转化成C语言
double single_double_param(double param) {// 调试模式下的栈初始化(对应 rep stos 指令),release则会优化掉这部分volatile char debug_fill[16]; // 0xCC填充的栈空间// 核心计算逻辑(对应 mulsd/addsd)return param * 2.5 + 1.25;
}