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

Jul*_*not 9 c++ gcc glibc memory-alignment gcc6

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

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

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

在这个ctor中,GCC使用了movaps:

movaps %xmm0,0x30a0(%ebx)
Run Code Online (Sandbox Code Playgroud)

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

"在GNU系统中,malloc或realloc返回的块的地址总是八的倍数(或64位系统上的十六个)."

因此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.

Tre*_*ntP 3

编译器可能有理由认为该对象的对齐方式为 \xe2\x89\xa5 16 字节。通过使用 C++11 中的运算符可以找出编译器认为的对齐方式alignof()。GCC 有一个可在 C 和早期 C++ 版本中使用的扩展__alignof__

\n\n

结构的对齐方式是其中任何内容的最高对齐方式,递归地。那里可能有比预期更高的对齐度的东西。

\n\n

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

\n\n

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

\n