赞成使用该教程,它非常好:)
那里有几个问题:
- 你的价值观不会
st(0)
,st(7)
他们会st(1)
和st(0)
。寄存器编号是固定的,它总是st(0)
在顶部,但桶会转动。当您加载某些内容时,它将是st(0)
. 如果你之后加载其他东西,桶会旋转,你之前拥有的东西将移动到st(1)
当前值将被放入st(0)
。
- 确保您的汇编程序生成适当大小的指令,例如用于
fld
和fst
- 确保您的
invoke
宏知道如何将浮点参数传递给printf
- 你没有清理FPU栈(这里不影响操作,只是一般问题)
我建议您使用调试器单步执行代码,这样您就可以看到正在发生的事情,您甚至不需要尝试使用printf
.
更新:在 linux 上使用 gdb 和工作代码的示例会话(为清晰起见进行了编辑):
$ cat > div.s
.intel_syntax noprefix
.globl main
.data
num1: .double 48.6
num2: .double 17.1
fmt: .string "%g\n"
.text
main:
sub esp, 16
fld qword ptr [num1] # st(0)=48.6
fld qword ptr [num2] # st(0)=17.1, st(1)=48.6
fdivp # st(0)=st(1)/st(0), one item popped
fstp qword ptr [esp+4] # store as argument and pop
mov dword ptr [esp], offset fmt
call printf
add esp, 16
ret
$ gcc -masm=intel -m32 -g div.s -o div
$ ./div
2.84211
$ gdb ./div
GNU gdb (GDB) 7.3.50.20111117-cvs-debian
(gdb) br main
Breakpoint 1 at 0x80483c4: file div.s, line 11.
(gdb) r
Starting program: div
Breakpoint 1, main () at div.s:11
11 sub esp, 16
(gdb) n
main () at div.s:12
12 fld qword ptr [num1] # st(0)=48.6
(gdb)
13 fld qword ptr [num2] # st(0)=17.1, st(1)=48.6
(gdb) info float
=>R7: Valid 0x4004c266666666666800 +48.60000000000000142
R6: Empty 0x00000000000000000000
R5: Empty 0x00000000000000000000
R4: Empty 0x00000000000000000000
R3: Empty 0x00000000000000000000
R2: Empty 0x00000000000000000000
R1: Empty 0x00000000000000000000
R0: Empty 0x00000000000000000000
(gdb) n
14 fdivp # st(0)=st(1)/st(0), one item popped
(gdb) info float
R7: Valid 0x4004c266666666666800 +48.60000000000000142
=>R6: Valid 0x400388ccccccccccd000 +17.10000000000000142
R5: Empty 0x00000000000000000000
R4: Empty 0x00000000000000000000
R3: Empty 0x00000000000000000000
R2: Empty 0x00000000000000000000
R1: Empty 0x00000000000000000000
R0: Empty 0x00000000000000000000
(gdb) n
15 fstp qword ptr [esp+4] # store as argument and pop
(gdb) info float
=>R7: Valid 0x4000b5e50d79435e4e16 +2.842105263157894584
R6: Empty 0x400388ccccccccccd000
R5: Empty 0x00000000000000000000
R4: Empty 0x00000000000000000000
R3: Empty 0x00000000000000000000
R2: Empty 0x00000000000000000000
R1: Empty 0x00000000000000000000
R0: Empty 0x00000000000000000000
(gdb) n
16 mov dword ptr [esp], offset fmt
(gdb) info float
R7: Empty 0x4000b5e50d79435e4e16
R6: Empty 0x400388ccccccccccd000
R5: Empty 0x00000000000000000000
R4: Empty 0x00000000000000000000
R3: Empty 0x00000000000000000000
R2: Empty 0x00000000000000000000
R1: Empty 0x00000000000000000000
=>R0: Empty 0x00000000000000000000
请注意,gdb
打印接下来要执行的指令。FPU 堆栈顶部由箭头标记,这始终st(0)
是根据定义。如有必要,其后以递增顺序和环绕顺序紧随其后。第一个转储显示48.6
正在加载,st(0)
因为它由箭头标记,其他位置是空的。然后,由于箭头移动了(枪管旋转) ,17.1
正在重新装入。st(0)
现在48.6
是st(1)
。FDIVP
执行除法并从堆栈中删除一项,因此我们最终得到结果,st(0)
其余为空。FSTP
然后存储st(0)
asprintf
参数并将其从堆栈中删除,因此所有寄存器现在都是空的。