4

我有一个单行 C 函数,它只是return value * pow(1.+rate, -delay);- 它将未来值折扣为现值。拆解的有趣部分是

0x080555b9 : 否定 %eax
0x080555bb : 推 %eax
0x080555bc : 字段 (%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 : 调用 0x8051ce0
0x080555d8 : fmull 0xfffffff8(%ebp)

在单步执行此函数时,gdb 说(速率为 0.02,延迟为 2;您可以在堆栈上看到它们):

(gdb) 硅
0x080555c6 30 返回值 * pow(1.+rate, -delay);
(gdb) 信息浮动
  R7:有效 0x4004a6c28f5c28f5c000 +41.68999999999999773      
  R6:有效 0x4004e15c28f5c28f6000 +56.34000000000000341      
  R5:有效 0x4004dceb851eb851e800 +55.22999999999999687      
  R4:有效 0xc0008000000000000000 -2                         
=>R3:有效 0x3ff9a3d70a3d70a3d800 +0.02000000000000000042    
  R2:有效 0x4004ff147ae147ae1800 +63.77000000000000313      
  R1:有效 0x4004e17ae147ae147800 +56.36999999999999744      
  R0:有效 0x4004efb851eb851eb800 +59.92999999999999972      

状态字:0x1861 IE PE SF              
                       顶部:3
控制字:0x037f IM DM ZM OM UM PM
                       PC:扩展精度(64 位)
                       RC:四舍五入到最近
标签字:0x0000
指令指针:0x73:0x080555c3
操作数指针:0x7b:0xbff41d78
操作码:0xdd45

之后fld1

(gdb) 硅
0x080555c8 30 返回值 * pow(1.+rate, -delay);
(gdb) 信息浮动
  R7:有效 0x4004a6c28f5c28f5c000 +41.68999999999999773      
  R6:有效 0x4004e15c28f5c28f6000 +56.34000000000000341      
  R5:有效 0x4004dceb851eb851e800 +55.22999999999999687      
  R4:有效 0xc0008000000000000000 -2                         
  R3:有效 0x3ff9a3d70a3d70a3d800 +0.02000000000000000042    
=>R2: 特殊 0xffffc000000000000000 实数不定 (QNaN)
  R1:有效 0x4004e17ae147ae147800 +56.36999999999999744      
  R0:有效 0x4004efb851eb851eb800 +59.92999999999999972      

状态字:0x1261 IE PE SF C1      
                       顶部:2
控制字:0x037f IM DM ZM OM UM PM
                       PC:扩展精度(64 位)
                       RC:四舍五入到最近
标签字:0x0020
指令指针:0x73:0x080555c6
操作数指针:0x7b:0xbff41d78
操作码:0xd9e8

在这之后,一切都下地狱了。事情被严重高估或低估了,所以即使我的 freeciv AI 尝试中没有其他错误,它也会选择所有错误的策略。就像派全军去北极一样。(叹气,要是我能走那么远就好了。)

我一定是遗漏了一些明显的东西,或者被某些东西蒙蔽了双眼,因为我无法相信这fld1会失败。更不用说它只在少数通过此功能后才会失败。在较早的传递中,FPU 正确地将 1 加载到 ST(0) 中。0x080555c6 处的字节肯定会编码fld1- 在正在运行的进程中使用 x/... 检查。

是什么赋予了?

4

2 回答 2

6

Remarkably appropriate. What you have here is a stack overflow.

Specifically, you (or possibly your compiler) has overflowed the x87 stack. It can only hold 8 values, and at the time that the fld1 is issued, it is already full (indicated by the tag word of 0000). Thus, the fld1 overflows the stack (indicated by IE, SF, C1) which causes the result that you're seeing.

As to why this is happening, you may have used MMX instructions without using an EMMS before using the x87 instructions, or your compiler has a bug, or you have assembly code somewhere that violates your platform's ABI (or a library that you are using violates the ABI).

于 2010-05-13T22:41:35.963 回答
4

看起来您有 FPU 堆栈溢出。FPU 标记字为 0,表示使用所有寄存器。您还可以看到所有标记为“有效”的寄存器,而我希望有些寄存器是空的。

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

于 2010-05-13T22:40:37.493 回答