我正在阅读这篇文章,我注意到他们的示例显示 fld 将值加载到不同的位置(st0、st1,然后返回到 st0),而没有指定加载到的位置。我假设 fild 以类似的方式工作,因为它只是加载整数的方法(或者这是我的理解),但我可能是错的。所以我的问题是:fld,更具体地说,将值加载到哪里?是否有一个参数来指定要使用哪个 fpu 寄存器,或者它只是循环通过 8,还是我缺少一些完全不同的方式?
我专门使用的代码是尝试将 3 个数字相乘。我假设一种方法是加载到 st0,然后加载到 st1,然后加载到 st2,然后是 fmul st0 和 st1(导致 st0),然后是 fmul st0 和 st2。代码如下:
mov dword [ebp-8], 4
mov dword [ebp-12], ecx
fild dword [ebp-4]
fild dword [ebp-8]
fild dword [ebp-12]
fmul st0, st1
fmul st0, st2
fistp dword [ebp-8]
mov eax, dword [ebp-8]
ecx = 5 和 [ebp-4] = 5
此代码崩溃,使用 OllyDbg 我看到在 00000069 处存在访问冲突,但当前未包含在任何寄存器中。
所以是的,有没有办法指定 fild 加载值的位置,有没有一种很好的方法来确定它们应该去哪里,如果我在循环中运行它会改变什么吗?
--EDIT 3-- 大部分是固定的,排序。一件大事是它fmul
不会将值推送到st0
,它只会覆盖 中的任何内容st0
。新代码:
mov dword [ebp-8], ecx
fild dword [ebp-4]
fild dword [four]
fild dword [ebp-8]
fmul st1
fmul st2
fistp dword [ebp-12]
mov eax, dword [ebp-12]
这个循环和递减直到ecx
== 2 然后尝试fild
2 和 1 给出与bad -NAN FFFF C0000000 00000000
之前相同的结果。我不确定 3 与 2 或 1 有何不同(除了更小),但那是它开始给出错误值的时候。我应该注意到 ERROR_MOD_NOT_FOUND 被抛出了,虽然我不确定这意味着什么,因为所有的 cpu 和 fpu 寄存器都应该是可访问的。
--EDIT 2--修复了 Parham Alvani 与文档内容一起显示的流行内容:
mov dword [ebp-8], ecx ; moves eax (starts as 5) into local var (fild can't take a cpu register)
fild dword [ebp-4] ; starts as 5, moves down with outer loop
fild dword [four] ; the integer 4
fild dword [ebp-8] ; starts as 5, moves down with inner loop
fmul st0, st1 ; 0 := 0 * i
fmul st0, st3
fistp dword [ebp-12] ; move st0 to local var
mov eax, dword [ebp-12] ; move local var to eax
这将推动 5,然后推动bad -NAN FFFF C0000000 00000000
两次。 fmul
似乎什么也没做(可能是因为价值观不好)。有没有更好的方法来加载值?似乎我做错了什么fild
,但根据第一个链接中提供的示例,并且定义为here,fild
无论你给它什么,都只是将它推到 st0 上。
--EDIT 1-- 正如 Jester 所建议的,我现在每个循环都从 fpu 堆栈中弹出:
mov dword [ebp-8], 4
mov dword [ebp-12], ecx
fild dword [ebp-4]
fild dword [ebp-8]
fild dword [ebp-12]
fmul st0, st1
fmul st0, st2
fstp st2
fstp st1
fistp dword [ebp-8]
mov eax, dword [ebp-8]
此代码仍然崩溃。00000009 处的访问冲突,st0-4 为 0,st5 = 100,st6 = 4,st7 = 4