为什么GCC 6假设数据是16字节对齐的?

时间:2017-02-16 10:43:29

标签: c++ gcc glibc memory-alignment gcc6

(提前抱歉没有设法将我的问题减少到一个简单的失败测试用例......)

我遇到了升级到GCC 6.3.0以构建我们的代码库(相关标志:-O3 -m32)的问题。

具体来说,由于GCC优化,我的应用程序会在struct ctor调用中发生段错误。

在这个ctor中,GCC使用了movaps

movaps %xmm0,0x30a0(%ebx)

movaps 要求操作数 16字节对齐。但是在这个时间点,%ebx指向我的对象,不一定是16字节对齐。来自glibc:

  

“在GNU系统中由malloc或realloc返回的块的地址始终是8的倍数(或64位系统上的16)。”

因此segfault(使用-O3 -m32构建时)。

为什么看起来像GCC假设分配的对象是16字节对齐的?我误解了什么吗?

注意:

  • 此结构上没有对齐提示或属性
  • 已通过默认new运算符
  • 初始化对象
  • 取决于优化级别:
    • 通过:-m32 -O2
    • 失败:-m32 -O2 -ftree-slp-vectorize
    • 通过:-m32 -O3 -fno-tree-slp-vectorize
    • 失败:-m32 -O3

这个其他项目似乎遇到了类似的问题:https://github.com/godotengine/godot/issues/4623

他们的调查指向-fvect-cost-model=dynamic。对我的代码库的调查反而指向-ftree-slp-vectorize

1 个答案:

答案 0 :(得分:2)

编译器有可能认为对象的对齐大于16个字节。通过在C ++ 11中使用alignof()运算符,可以找出编译器认为对齐的内容。 GCC有一个扩展__alignof__,可以在C和早期的C ++版本中使用。

结构的对齐是其中任何内容的最高对齐,递归。可能存在比预期更高的对齐的东西。

虽然C ++ 11标准保证new返回的内存与任何对象的“基本对齐要求”所需的值对齐,但这仅适用于标准类型和由它们构成的对象。使用C ++ 11 alignas()__attribute__((aligned(x))) GCC扩展来请求更高的对齐可能会超出new提供的内容。

对此的解决方案是使用std::aligned_alloc()(C ++ 11或更高版本)或posix_memalign()(仅限POSIX但是< C ++ 11)来获得对齐的内存。这可以与new运算符的放置形式结合使用,以便在newdelete的内存或类特定运算符重载中构造对象。