提问人:Radioactive Epic Face 提问时间:1/31/2023 最后编辑:zx485Radioactive Epic Face 更新时间:1/31/2023 访问量:73
为什么打印浮点数时需要按相同的值 +4?
Why do I need to push the same value +4 when printing a float?
问:
很长一段时间以来,我一直在尝试在 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>
我认为将浮点值加载到 st(0) 中并在地址上加载 st(0) 值,基本上很明显,所以我曾经尝试过以下操作:fld
fstp
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价值本质上是什么?
答:
该函数只能打印 64 位浮点数(双精度)。这样的双精度包含 8 个字节。通过将此值从 FPU 存储到堆栈来将此值推送到堆栈上:printf
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 个字节。
假设您像问题中一样声明为 qword,这将意味着 的大小为 .FSTP
还可以转换为 DWORD(浮点数)或存储为 x87 寄存器中使用的原始 10 字节内部格式。这就是我们需要的原因,因为这并不意味着操作数大小。dVal2
fstp [dVal2]
fstp qword ptr [esp]
[esp]
与往常一样,要访问大小与该标签后第一项不同的数据标签附近的存储,MASM 需要覆盖该大小,否则它会抱怨不匹配,因此 ,因为仅在 64 位模式下可用。(它将在 XMM1 中作为第二个参数传递给函数。push dword ptr [dVal2+4]
push qword ptr
评论