assembly 为什么我需要在打印浮点数时将相同的值压入+4?

11dmarpk  于 2023-02-04  发布在  其他
关注(0)|答案(1)|浏览(118)

很长一段时间以来,我一直在尝试用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值本质上是什么?

ux6nzvsh

ux6nzvsh1#

printf函数只能打印64位浮点数(双精度型)。这样的双精度型包含8个字节。通过从FPU存储到堆栈来将此值压入堆栈:

sub     esp, 8           ; make space for the double
fstp    qword ptr [esp]  ; store double into that space
push    OFFSET msg
call    [printf]

或者分两步推入堆栈,每步4字节:

fstp    [dVal2]          ; store double to global/static variable
push    dword ptr [dVal2+4]    ; push high half of double
push    dword ptr [dVal2]      ; push low half of double
push    OFFSET msg
call    [printf]

注意当栈变小时,我们必须先压入高位的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中,它将作为第二个参数传递给函数)。

相关问题