4

GCC 4.5.2 (Ubuntu 11.10 x64 上で 32 ビット用にコンパイル) は無効なアセンブリ コードを生成します。オプションなどを適用するだけで、コードを変更せずに修正できるかどうか知りたいです。最適化はすでに -O0 であることに注意してください。

私には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 は、次のアセンブリ コードを生成します。

 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)

ご覧のとおり、m_p 値を %esi に格納し、後で lea を使用して戻り値を追加します。しかし、::Get() も m_p を変更します! GCCが認識していないようです。したがって、%esi の値が廃止されたため、バグ m_p は正しくありません (予想よりも 4 バイト少ない)。

を使用して修正できます

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

しかし、バグをなくすために、コードを変更せずにプラグマやそのようなものを適用できるかどうか疑問に思っています。gcc バージョンに関しては、指定されたバージョンにこだわっています。

4

1 に答える 1

11

それはバグではありません。ご存知のように、m_p += Get();本当にm_p = m_p + Get();. コンパイラは、加算の評価順序を自由に選択できます。したがって、 を取得m_pしてから を実行Get()し、次に追加を行うことは有効であり、投稿したばかりのコードを作成します。

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

于 2012-04-27T08:47:27.113 に答える