You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在FASM中打印float为何需先推送同值+4?REAL4本质是什么?

关于FASM打印浮点数的疑问解答

问题背景

在FASM中尝试打印浮点数时遇到异常,观察x64dbg生成的C程序汇编代码后尝试编写代码但失败,最终找到可行方案但不理解原理:

观察到的C程序汇编片段

mov dword ptr ss:[esp+1C],eax
fld dword ptr ss:[esp+1C] ; 加载单精度浮点数到FPU栈st(0)
fstp qword ptr ss:[esp+4] ; 将st(0)的值转成双精度并存入栈中
mov dword ptr ss:[esp],c.404000
call <JMP.&printf>

最初的错误尝试代码

format PE
entry start

include '%include%\win32a.inc'

section '.text' code readable executable
start:
fld dword ptr dVal
fstp qword ptr dVal2
push msg
call [printf]
call [getchar]
call [exit]

section '.idata' import data readable
library msvcrt, 'msvcrt.dll'

import msvcrt, printf, 'printf'\
exit, 'exit', getchar, 'getchar'

section '.bss' data readable writeable
dVal2 dq ?

section '.data' data readable
msg db '%f',10,13,0
dVal dq 3.14

程序要么崩溃,要么输出错误值,最终找到两种可行写法:

写法一:先转双精度再拆分压栈

...
section '.text' code readable executable
start:
fld dword ptr dVal
fstp qword ptr dVal2
push dword ptr dVal2+4
push dword ptr dVal2
push msg
call [printf]
call [getchar]
call [exit]
...

写法二:直接拆分双精度变量压栈

...
section '.text' code readable executable
start:
push dword ptr dVal+4
push dword ptr dVal
push msg
call [printf]
call [getchar]
call [exit]
...

疑问解答

1. 为什么要推送值+4和值两个部分?

核心原因有两点:

  • printf的%f格式符要求参数是双精度浮点数(8字节):不管传入的原本是单精度(float,4字节)还是双精度(double,8字节),%f都会按双精度解析。如果只传4字节,printf会读取栈上额外的4字节随机数据,导致解析错误或程序崩溃。
  • x86架构的小端字节序:多字节数据在内存中是低字节存低地址、高字节存高地址。以8字节的double为例,变量dVal的起始地址对应低4字节,dVal+4对应高4字节。而x86的push指令每次只能压入4字节,且调用printf时参数要从右往左压栈,所以需要先压入高4字节(dVal+4),再压入低4字节(dVal),这样栈里的8字节布局正好符合double的小端存储格式,printf才能正确解析。

另外你最初的错误代码还有一个问题:调用printf时只压入了msg,没有传入浮点数参数,这直接导致printf读取栈上的随机值,必然引发异常。

2. MASM中的REAL4本质是什么?

REAL4就是32位单精度浮点数,对应C语言里的float,和FASM中用dd定义的浮点数完全等价。MASM用REAL4、REAL8(64位双精度,对应double,即FASM的dq)这类关键字,是为了明确指定浮点数的精度,避免和同长度的整数类型混淆。

内容的提问来源于stack exchange,提问作者Radioactive Epic Face

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 02:06:05