当前位置: 首页 > news >正文

float数据分别以int和float类型打印的反汇编分析

目录

1.源代码

2.VS配置

3.反汇编代码

3.分析

0.movss指令

1.cvtss2sd指令

资料出处

简介

描述

翻译

提炼要点

2.movsd指令

资料出处

简介

描述

翻译

提炼要点

3.关键指令分析

1.

2.

由double在内存中的存储形式可以推测xmm0寄存器中存储的数据

1.求S

2.将十进制数字转换为二进制

3.规范化

4.求E

5.操作M补0

6.结果

4.题外话

提示

分析

5.推荐阅读


1.源代码

#include <stdio.h>
int main()
{float value = 1.0;printf("value_int = %d\n", value);printf("value_float = %f\n", value);
}

2.VS配置

e1a11a2dc37f44ff9713a64cacc0177f.png

e357b893088f41a699199188153d51c8.png

3.反汇编代码

#include <stdio.h>
int main()
{push        ebp  mov         ebp,esp  sub         esp,44h  push        ebx  push        esi  push        edi  mov         ecx,offset _21126C67_FileName@c (0D6C008h)  call        @__CheckForDebuggerJustMyCode@4 (0D6132Ah)  nop  float value = 1.0;movss       xmm0,dword ptr [__real@3f800000 (0D67B30h)]  movss       dword ptr [value],xmm0  printf("value_int = %d\n", value);cvtss2sd    xmm0,dword ptr [value]  sub         esp,8  movsd       mmword ptr [esp],xmm0  push        offset string "value_int = %d\n" (0D67BD4h)  call        _printf (0D610D2h)  add         esp,0Ch  printf("value_float = %f\n", value);cvtss2sd    xmm0,dword ptr [value]  sub         esp,8  movsd       mmword ptr [esp],xmm0  push        offset string "value_float = %f\n" (0D67BE4h)  call        _printf (0D610D2h)  add         esp,0Ch  
}xor         eax,eax  pop         edi  pop         esi  pop         ebx  mov         esp,ebp  pop         ebp  ret  

3.分析

 push        ebp  mov         ebp,esp  sub         esp,44h  push        ebx  push        esi  push        edi  mov         ecx,offset _21126C67_FileName@c (0D6C008h)  call        @__CheckForDebuggerJustMyCode@4 (0D6132Ah)  nop  

栈区初始化,非本文重点,详细参见36.【C语言】函数栈帧的创建和销毁

0.movss指令

注:有关movss和XMM寄存器的详细内容参见float强制类型转换为int类型的反汇编分析

这里介绍另外8086汇编没有的指令cvtss2sd和movsd

1.cvtss2sd指令

资料出处

CVTSS2SD— Convert Scalar Single Precision Floating-Point Value to Scalar Double PrecisionFloating-Point Value

CVTSS2SD — ConVerT Scalar Single precision floating-point value to Scalar Double precision floating-point value

题外话:缩写里的2对应全称的to,原因:two的音标:/tuː/ to的音标:/tu/,两者的发音类似,因而用2

简介

把标量(Scalar)单精度(Single precision)浮点值(floating-point value)转换(ConVerT)为标量双精度(Double precision )浮点值

描述

Converts a single precision floating-point value in the “convert-from” source operand to a double precision floating-point value in the destination operand. When the “convert-from” source operand is an XMM register, the single precision floating-point value is contained in the low doubleword of the register. The result is stored in the low quadword of the destination operand.

128-bit Legacy SSE version: The “convert-from” source operand (the second operand) is an XMM register or memory location. Bits (MAXVL-1:64) of the corresponding destination register remain unchanged. The destination operand is an XMM register.

翻译

将"convert-from"源操作数中的单精度浮点值转换为目的操作数中的双精度浮点值。当"convert-from"源操作数是一个XMM寄存器时,单精度浮点值存储在寄存器的低双字中.结果存储在目的操作数的低四字中.

128位传统SSE版本:"convert-from"源操作数(第二个操作数)是一个XMM寄存器或内存位置.相应目标寄存器的位(MAXVL-1:64)保持不变.目标操作数是一个XMM寄存器.

备注:SSE是x86的扩展,是Streaming SIMD Extension的缩写,SIMD是Single Instruction Multiple Data的缩写

提炼要点

格式:cvtss2sd dest(存储双精度浮点值),convert-from(存储单精度浮点值)

convert-from可以是XMM寄存器或内存位置;dest可以是XMM寄存器

2.movsd指令

资料出处

CVTSS2SD— Convert Scalar Single Precision Floating-Point Value to Scalar Double PrecisionFloating-Point Value

MOVSD — MOVe or merge Scalar Double precision floating-point value

简介

移动(MOVe)或合并(merge)标量(Scalar)双精度(Double precision)浮点值(floating-point value)

描述

Moves a scalar double precision floating-point value from the source operand (second operand) to the destination operand (first operand). The source and destination operands can be XMM registers or 64-bit memory locations. This instruction can be used to move a double precision floating-point value to and from the low quadword of an XMM register and a 64-bit memory location, or to move a double precision floating-point value between the low quadwords of two XMM registers. The instruction cannot be used to transfer data between memory locations.

翻译

将源操作数(第二个操作数)中的标量双精度浮点值移动到目的操作数(第一个操作数),源操作数和目的操作数可以为XMM寄存器或64位内存地址.指令可以来回在XMM寄存器的低四字和64位内存地址移动一个双精度浮点值,或者在XMM寄存器的低四字之间移动.这个指令不能被用来在两个内存地址之间转移数据

提炼要点

格式:movsd dest(存储双精度浮点值),src(存储双精度浮点值)

dest和src可以为XMM寄存器或64位内存地址,但不能同时为64位内存地址

3.关键指令分析

1.

	float value = 1.0;movss       xmm0,dword ptr [__real@3f800000 (0D67B30h)]  movss       dword ptr [value],xmm0  

由于存储单精度浮点值(float类型)要使用xmm寄存器,这里选择xmm0做中转寄存器来存储到value变量的地址dword ptr [value]处

(x86不支持由地址[...]到地址[...]的指令: movss dword ptr [value],dword ptr [__real@3f800000 (0D67B30h)])

2.

	printf("value_int = %d\n", value);cvtss2sd    xmm0,dword ptr [value]  sub         esp,8  movsd       mmword ptr [esp],xmm0  push        offset string "value_int = %d\n" (0D67BD4h)  call        _printfadd         esp,0Ch  

注:call _printf(0D610D2h)处理的细节非本文重点,在此不做分析

注意到: cvtss2sd    xmm0,dword ptr [value] 

疑问:value变量是float类型,在cvtss2sd这一行时,为什么存储在xmm0寄存器的小数要转换为double类型呢?

答:这是编译器的一种默认机制,执行printf("%d\n", value); value是以double传递参数的

回忆IEEE 754标准(具体参见62.【C语言】浮点数的存储)

由double在内存中的存储形式可以推测xmm0寄存器中存储的数据

1.求S

1.0为正数,因此S = 0

2.将十进制数字转换为二进制

1.0=(1.0)_2

3.规范化

(1.0)_2=(1.0)_2*2^0

4.求E

E=0+1023=1023

十进制1023=二进制011 1111 1111(11位)

5.操作M补0

由于M为0,占1位,因此在M的右边增加51个0

6.结果

每4位二进制数转换为1位十六进制数,为3F F0 00 00 00 00 00 00

由于VS默认以小端序存储,因此在内存中的存储形式为00 00 00 00 00 00 F0 3F

打印%d时,只取左侧4字节(即低32位)(int类型4字节),前4字节比特位都是0,所以最终打印为0

打印%f(float)时,和上面的double小数无关,正常打印为1.000000(默认保留小数点后6位)

4.题外话

画出以下汇编指令的栈区内存图

 cvtss2sd    xmm0,dword ptr [value]  sub         esp,8  movsd       mmword ptr [esp],xmm0  push        offset string "value_int = %d\n" (027BE4h)  call        _printfadd         esp,0Ch  

提示

1.call指令不改变esp寄存器的值

2.初始esp寄存器的值为0x009DFD70

分析

1.cvts2sd指令不改变esp

2.sub esp,8指令使得esp减8,为0x009DFD68

3.movsd指令不改变esp

4.push指令压栈,压入0x00027BE4操作了esp,使esp指向栈顶(0x009DFD64)

5.add esp,0Ch指令使esp变为初始值(0x009DFD70)

因此内存图为(注:压栈从高地址向低地址压)

5.推荐阅读

float强制类型转换为int类型的反汇编分析


http://www.mrgr.cn/news/53222.html

相关文章:

  • 【网络协议】之 HTTP 协议详解
  • 简单三步完成 Telegram 生态的 Web3 冷启动
  • 网络通信与并发编程(二)基于tcp的套接字、基于udp的套接字、粘包现象
  • Postman 接口测试
  • 去除视频水印的三种方法,有手就会
  • Vscode+Pycharm+Vue.js+WEUI+django火锅(7) 傍着Copliot战WEUI Picker
  • 1.1 C++语言基础面试问题
  • 试用cursor的简单的记录
  • 力扣困难题汇总
  • OQE-OPTICAL AND QUANTUM ELECTRONICS
  • 掌握高效工作汇报技巧:如何利用即时白板打造完美日报,提升职场影响力
  • C++简易日志系统:打造高效、线程安全的日志记录工具
  • D41【python 接口自动化学习】- python基础之函数
  • Linux系统下使用ncurses获取按键
  • GSM /3G/EPS/5G 的认证过程和算法、密钥
  • Linux -- 进程间通信、初始匿名管道
  • CAS详谈---无锁的锁机制
  • “两马”荣获上全球富豪榜,中国首富成谜
  • 百度智能云千帆 ModelBuilder 大模型服务及开发解读
  • SpringBoot使用SqlSessionFactory方式配置多数据源