【发布时间】:2015-02-11 01:52:22
【问题描述】:
我正在阅读this,我注意到他们的示例显示 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 加载值的位置,有没有一种很好的方法来确定它们应该去哪里,如果我在循环中运行它会改变什么吗?
--编辑 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 寄存器都应该可以访问。
--编辑 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 上。
--编辑 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
【问题讨论】:
-
x87 FPU 是基于栈的,
FILD将一个新值推送到栈顶,通常称为st0。因此之前的st0变为st1,以此类推。在循环中也要小心,因为你只有 8 个寄存器。我不知道那本维基书,但我可以推荐simply FPU tutorial。 -
那我怎么弹出?这是fistp的作用吗?
-
是的,大多数指令中的
P表示弹出。也有非爆裂变体。 -
我可以直接弹出值而不存储在某个地方吗?
-
是的。你可以
fstp st0。另请参阅 this question 和指令集参考。