(提前抱歉没有设法将我的问题减少到一个简单的失败测试用例......)
我遇到了升级到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
。
答案 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
运算符的放置形式结合使用,以便在new
和delete
的内存或类特定运算符重载中构造对象。