2012-04-27 12 views
4

GCC 4.5.2(Ubuntu 11.10 x64では32ビット用にコンパイルされますが、無効なアセンブリコードが生成されます)それ。最適化はすでに-O0であることに注意してください。あなたはそれが%のESIでm_p値を格納し、後でそれに返された値を追加します見ることができるようにGCCアセンブリコード生成のバグと回避策

9840  m_p += Get(); 
f689eff5: mov 0x8(%ebp),%eax 
f689eff8: mov 0xd4(%eax),%eax 
f689effe: mov %eax,%esi 
f689f000: mov 0x8(%ebp),%eax 
f689f003: mov %eax,(%esp) 
f689f006: call 0xf66116a0 
f689f00b: lea (%esi,%eax,1),%edx 
f689f00e: mov 0x8(%ebp),%eax 
f689f011: mov %edx,0xd4(%eax) 

私は2つの機能があります。

inline long Class::Get() 
{ 
    long v = *(long*)(m_p); 
    m_p += 4; 
    return v; 
} 
inline void Class::Command() 
{ 
    m_p += Get(); 
} 

GCC 4.5.2は、このアセンブリコードを生成し、 leaを使ってBUT :: Get()はm_pも変更します! GCCは認識していないようです。したがって、%esiの値は時代遅れであるため、バグm_pは正しくありません(4バイトは予想よりも少なくなります)。

私は

inline void Class::Command() 
{ 
    long v = Get(); 
    m_p += v; 
} 

を使用してそれを修正することができます。しかし、私はバグが離れて行くにするために、コードを変更することなく、そのようないくつかのプラグマやなめらかに適用することができれば私は思ったんだけど。 gccのバージョンについては、私は指定されたものに固執しています。

+1

'long v = *(long *)(m_p);'についての警告は表示されませんか?私はこれが型打ちで、技術的にUBだと信じていますか?このような危険なコードを書くつもりなら '-fno-strict-aliasing'を試してみてください。 –

+0

いつでもキャストすることができます... –

+0

いいえ、警告はオフです。しかし、私はそれがどのように関連しているか分かりません。そして、私はこのようなコードを書いていない、私はちょうどそれを使って作業しています。 – queen3

答えて

11

これはバグではありません。ご存知のように、m_p += Get();は実際にはm_p = m_p + Get();です。コンパイラは、加算の評価順序を自由に選択できます。したがって、m_pをフェッチしてからGet()を実行してから、追加すると有効になり、今投稿したコードが作成されます。

新しいシーケンスポイントを作成したため、2番目の例が異なります。この場合、Get()が常に最初に評価されます。

+0

少なくとも、これはコードを変更する正当な理由のようです。ちょうど "gcc bug"よりもはるかに良い、ありがとう。 – queen3

+1

評価の順序から_Undefined_ Behaviorを取得するとは思わない。それは不明です。もちろん、説明する順序は可能な順序であり、GCCの結果を説明します。 – MSalters

+0

@MSalters:正確に。明確化のためにありがとう。 –

関連する問題