2010-05-13 66 views
4

我有一个单线程C函数,它只是return value * pow(1.+rate, -delay); - 它将未来值折扣为现值。拆卸的有趣的部分是为什么FLD1加载NaN?

 
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 

在此之后,一切都变成了地狱。事情被严重超过或低估,所以即使我的freeciv AI尝试中没有其他错误,它也会选择所有错误的策略。就像把全军送到北极一样。 (叹息,如果只有我得到那么远。)

我必须失去一些明显的东西,或被某些东西蒙蔽,因为我不能相信fld1应该可能会失败。更少的是,只有在通过这个函数的一些通过之后它才会失败。在较早的通道中,FPU正确加载1到ST(0)。 0x080555c6的字节编码为fld1 - 在运行过程中用x/...检查。

什么给?

回答

6

非常合适。你在这里得到的是一个堆栈溢出

具体来说,你(或者可能是你的编译器)溢出了x87堆栈。它只能保存8个值,并且在发出fld1时,它已满(由标记词0000指示)。因此,fld1溢出堆栈(由IE, SF, C1表示),导致您看到的结果。至于为什么会发生这种情况,您可能在使用x87指令之前不使用EMMS来使用MMX指令,或者您的编译器有错误,或者您的汇编代码在某处违反了您的平台的ABI(或者一个库你正在使用违反ABI)。

+1

啊,你们摇滚!谢谢!它把我推上了墙。至于为什么会发生这种情况:可能是因为我移动了一个调用另一个函数的函数,该函数从一个文件返回到另一个文件,而在新文件中,没有浮点函数的原型,所以我猜编译器从不弹出返回堆栈的值。尽管如此,我本来预计会尽快用完FP堆栈,但现在看来,现在我已经提供了一个原型,它的工作状况好多了。 现在我可以进入下一个段落了! – 2010-05-14 12:02:26

+0

@Bernd:是的,这肯定会导致这类问题。 – 2010-05-14 17:27:14

4

它看起来像你有一个FPU堆栈溢出。 FPU标签字是0,这意味着所有寄存器都被使用。您也可以看到所有标记为“有效”的寄存器,当我希望某些寄存器为空时。

我不知道为什么会发生这种情况。也许你有一些MMX代码不会发出EMMS指令?或者可能是一些内联程序集不能正确清除堆栈?