GCC汇编代码生成错误和解决方法

时间:2012-04-27 08:38:26

标签: c++ gcc assembly code-generation

GCC 4.5.2(在Ubuntu 11.10 x64上,但编译为32位)生成无效的汇编代码,我很好奇是否可以在不更改代码的情况下修复,只需应用选项或类似的东西。请注意,优化已经是-O0。

我有两个功能:

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!海湾合作委员会似乎并未意识到这一点。因此,错误m_p不正确(比预期少4个字节),因为%esi中的值已过时。

我可以使用

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

但我只是想知道我是否可以在不更改代码的情况下应用一些pragma或smth,以使bug消失。至于gcc版本,我坚持使用给定的版本。

1 个答案:

答案 0 :(得分:11)

这不是一个错误。如您所知,m_p += Get();确实是m_p = m_p + Get();。编译器可以自由选择添加的评估顺序。因此,获取m_p,然后执行Get(),然后执行添加是有效的,并创建刚刚发布的代码。

你的第二个例子是不同的,因为你创建了一个新的序列点。在这种情况下,始终首先评估Get()