很长一段时间以来,我一直在尝试用FASM打印一个浮点值,直到我最终找到了一个解决方案,它成功了,但是,为什么会这样呢?在一个C程序中,我用x64dbg生成的汇编代码是这样的:
mov dword ptr ss:[esp+1C],eax
fld st(0), dword ptr ss:[esp+1C] ;<--- focusing on these 2
fstp qword ptr ss:[esp+4],st(0) ;<---
mov dword ptr ss:[esp],c.404000
call <JMP.&printf>
我认为fld
将float值加载到st(0)中,而fstp
将st(0)值加载到一个地址上,这一事实基本上是非常明显的,因此我经常尝试以下操作:
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
经过多次尝试,它让我崩溃,或者像0或随机数这样的结果,与我想要的无关。然而,经过这么多的研究,我终于发现我可以简单地做这样的事情
...
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]
...
为什么我需要在打印浮点值之前把相同的值加4?MASM的REAL4值本质上是什么?
1条答案
按热度按时间ux6nzvsh1#
printf
函数只能打印64位浮点数(双精度型)。这样的双精度型包含8个字节。通过从FPU存储到堆栈来将此值压入堆栈:或者分两步推入堆栈,每步4字节:
注意当栈变小时,我们必须先压入高位的4字节,然后压入低位的4字节。因为一次只能压入4字节,所以需要两次单独的压入操作,但双字节是8字节。
假设你声明
dVal2
为一个qword,就像问题中那样,这意味着fstp [dVal2]
的大小。fstp
can also转换为dword(浮点型)或存储为x87寄存器中使用的原始10字节内部格式。这就是为什么我们需要fstp qword ptr [esp]
,因为[esp]
并不意味着操作数大小。和往常一样,要访问数据标签附近的存储空间,且该标签的大小与标签后的第一项的大小不同,MASM需要您覆盖该大小,否则它将报告不匹配,即
push dword ptr [dVal2+4]
,因为push qword ptr
仅在64位模式下可用(在XMM1中,它将作为第二个参数传递给函数)。