我正在阅读this并且我注意到他们的示例显示fld将值加载到不同的位置(st0,st1,然后返回到st0),而没有指定加载到何处。我假设fild以类似的方式工作,因为它只是加载整数的方式(或者我的理解无论如何),但我可能是错的。所以我的问题是:fld在哪里,更具体地说是fild加载值?是否有一个参数来指定要使用哪个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
DOESN' T将值推到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推送到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&n; s,st5 = 100,st6 = 4,st7 = 4
答案 0 :(得分:1)
您的原始代码是正确的。 fld
和fild
将加载的值推送到x87堆栈。此推送始终将值置于st0中,将st0的旧值移至st1,将旧st1移至st2,依此类推。
fild dword [ebp-4] ; st0 = x
fild dword [ebp-8] ; st1 = x, st2 = y
fild dword [ebp-12] ; st2 = x, st1 = y, st0 = z
fmul st0, st1 ; st2 = x, st1 = y, st0 = z * y
fmul st0, st2 ; st2 = x, st1 = y, st0 = z * y * x
fistp dword [ebp-8] ; st1 = x, st0 = y
您的代码可能会崩溃,因为ebp
指向错误的位置,或者因为代码的其他部分出错,而不是您发布的部分。你不会说哪个指令崩溃了。在崩溃的那一刻,程序计数器(pc)指向崩溃的指令。
我把你的代码放在一个简短的程序中,然后在我的OpenBSD / amd64机器上的gdb中成功运行它。
section .data
dd 0
dd 0
dd 5
space:
section .text
global main
main:
mov ebp, space
mov ecx, 5
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]
int 3
组装并运行:
$ nasm -felf64 fmul3.s && gcc -nopie -o fmul3 fmul3.o
$ gdb fmul3
...
(gdb) run
...
Program received signal SIGTRAP, Trace/breakpoint trap.
...
(gdb) x/3wd (char *)&space - 12
0x601000 <__data_start>: 5 100 5
(gdb) print (int)$rax
$1 = 100
该程序成功乘以5 * 4 * 5 = 100。