4

ワンライナーC関数がありreturn value * pow(1.+rate, -delay);ます。これは、将来価値を現在価値に割り引くものです。分解の興味深い部分は

0x080555b9:neg%eax
0x080555bb:プッシュ%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:0x8051ce0に電話
0x080555d8:fmull 0xfffffff8(%ebp)

この関数をシングルステップで実行している間、gdbは次のように述べています(レートは0.02、遅延は2です。スタックで確認できます)。

(gdb)si
0x080555c630戻り値*pow(1. + rate、-delay);
(gdb)info float
  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              
                       TOP:3
コントロールワード:0x037f IM DM ZM OM UM PM
                       PC:拡張精度(64ビット)
                       RC:最も近い値に丸める
タグワード:0x0000
命令ポインタ:0x73:0x080555c3
オペランドポインタ:0x7b:0xbff41d78
オペコード:0xdd45

そして後fld1

(gdb)si
0x080555c830戻り値*pow(1. + rate、-delay);
(gdb)info float
  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      
                       TOP: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

めちゃめちゃ適当。ここにあるのは、スタック オーバーフローです。

具体的には、ユーザー (またはおそらくコンパイラー) が x87 スタックをオーバーフローさせました。保持できる値は 8 つだけであり、fld1が発行された時点で、すでにいっぱいになっています ( のタグ ワードで示されます0000)。したがって、fld1スタックがオーバーフローし ( で示されますIE, SF, C1)、表示されている結果が生じます。

これが発生する理由についてはEMMS、x87 命令を使用する前に を使用せずに MMX 命令を使用したか、コンパイラにバグがあるか、プラットフォームの ABI に違反するアセンブリ コードがどこかにある (または使用しているライブラリが x87 命令に違反している) 可能性があります。アビ)。

于 2010-05-13T22:41:35.963 に答える
4

FPU スタック オーバーフローが発生しているようです。FPU タグ ワードは 0 です。これは、すべてのレジスタが使用されていることを意味します。一部が空であると予想される場合、「有効」とマークされたすべてのレジスタも表示されます。

なぜこれが起こるのかわかりません。EMMSたぶん、命令を発行しないMMXコードがありますか?または、スタックを適切にクリアしないインライン アセンブリでしょうか。

于 2010-05-13T22:40:37.493 に答える