我有一个只有return value * pow(1.+rate, -delay);
的单行C函数 - 它将未来值折现为现值。反汇编的有趣部分是
0x080555b9 : neg %eax 0x080555bb : push %eax 0x080555bc : fildl (%esp) 0x080555bf : lea 0x4(%esp),%esp 0x080555c3 : fldl 0xfffffff0(%ebp) 0x080555c6 : fld1 0x080555c8 : faddp %st,%st(1) 0x080555ca : fxch %st(1) 0x080555cc : fstpl 0x8(%esp) 0x080555d0 : fstpl (%esp) 0x080555d3 : call 0x8051ce0 0x080555d8 : fmull 0xfffffff8(%ebp)
单步执行此函数时,gdb说(速率为0.02,延迟为2;您可以在堆栈中看到它们):
(gdb) si 0x080555c6 30 return value * pow(1.+rate, -delay); (gdb) info float R7: Valid 0x4004a6c28f5c28f5c000 +41.68999999999999773 R6: Valid 0x4004e15c28f5c28f6000 +56.34000000000000341 R5: Valid 0x4004dceb851eb851e800 +55.22999999999999687 R4: Valid 0xc0008000000000000000 -2 =>R3: Valid 0x3ff9a3d70a3d70a3d800 +0.02000000000000000042 R2: Valid 0x4004ff147ae147ae1800 +63.77000000000000313 R1: Valid 0x4004e17ae147ae147800 +56.36999999999999744 R0: Valid 0x4004efb851eb851eb800 +59.92999999999999972 Status Word: 0x1861 IE PE SF TOP: 3 Control Word: 0x037f IM DM ZM OM UM PM PC: Extended Precision (64-bits) RC: Round to nearest Tag Word: 0x0000 Instruction Pointer: 0x73:0x080555c3 Operand Pointer: 0x7b:0xbff41d78 Opcode: 0xdd45
在fld1
:
(gdb) si 0x080555c8 30 return value * pow(1.+rate, -delay); (gdb) info float R7: Valid 0x4004a6c28f5c28f5c000 +41.68999999999999773 R6: Valid 0x4004e15c28f5c28f6000 +56.34000000000000341 R5: Valid 0x4004dceb851eb851e800 +55.22999999999999687 R4: Valid 0xc0008000000000000000 -2 R3: Valid 0x3ff9a3d70a3d70a3d800 +0.02000000000000000042 =>R2: Special 0xffffc000000000000000 Real Indefinite (QNaN) R1: Valid 0x4004e17ae147ae147800 +56.36999999999999744 R0: Valid 0x4004efb851eb851eb800 +59.92999999999999972 Status Word: 0x1261 IE PE SF C1 TOP: 2 Control Word: 0x037f IM DM ZM OM UM PM PC: Extended Precision (64-bits) RC: Round to nearest Tag Word: 0x0020 Instruction Pointer: 0x73:0x080555c6 Operand Pointer: 0x7b:0xbff41d78 Opcode: 0xd9e8
在此之后,一切都变得地狱。事情变得严重过高或被低估,所以即使我的自由人工智能尝试中没有其他错误,它也会选择所有错误的策略。就像把整个军队送到北极一样。 (叹气,如果我走的那么远。)
我必须遗漏一些显而易见的东西,或被某些东西蒙蔽,因为我无法相信fld1
应该永远失败。更不用说它只有在通过这个函数的少数几个之后才会失败。在较早的传递中,FPU正确地将1加载到ST(0)中。 0x080555c6处的字节肯定编码为fld1
- 在运行过程中使用x / ...进行检查。
是什么给出了?
答案 0 :(得分:6)
非常合适。你在这里有一个堆栈溢出。
具体来说,您(或可能是您的编译器)已经溢出x87堆栈。它只能容纳8个值,并且在发出fld1
时,它已经满了(由0000
标记词表示)。因此,fld1
溢出堆栈(由IE, SF, C1
表示),这会导致您看到的结果。
至于为什么会发生这种情况,您可能在使用x87指令之前使用了MMX指令而没有使用EMMS
,或者您的编译器有错误,或者您的汇编代码违反了平台的ABI(或者您正在使用的库违反了ABI。)
答案 1 :(得分:4)
看起来你有一个FPU堆栈溢出。 FPU标记字为0,表示使用所有寄存器。您还可以看到所有标记为“有效”的寄存器,当我希望某些寄存器为空时。
我不知道为什么会发生这种情况。也许你有一些不发出EMMS
指令的MMX代码?或者也许某些内联汇编不能正确清除堆栈?