(抱歉,我未能将我的问题简化为一个简单的失败测试案例...)
我在升级到GCC 6.3.0以构建我们的代码库时遇到了问题(相关标志:-O3 -m32
)。
具体而言,我的应用程序在结构体析构函数中由于GCC的优化而导致段错误。
在这个析构函数中,GCC使用了movaps
:
movaps %xmm0,0x30a0(%ebx)
movaps
要求操作数必须是16字节对齐的。但在这个时刻,%ebx
指向我的对象,该对象不一定是16字节对齐的。来自glibc:
“在GNU系统中,malloc或realloc返回的块地址始终是8的倍数(或64位系统上为16)。”
因此,在使用-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
。
alignof
将告诉您编译器认为它需要什么对齐方式。听起来应该不会是 ≥16,但检查一下也无妨。 - TrentPalignof==16
,那么这不会是一个错误,但这意味着您不能使用 glibc 的malloc
。然而,标准限制了实现的malloc
,而不是操作系统的malloc
。GCC 可能需要包装 glibc。(我认为无论如何都应该这样做) - MSaltersalignof
返回64
。alignof(max_align_t)
返回8
(符合预期)。既然没有用户对对象或其成员的对齐要求,为什么alignof
会是64
?我没有直接使用malloc
,但假设new
在使用它。 - Julien Vivenotalignof==64
的原因。正如 @TrentP 和 @MSalters 所指出的那样,这也意味着我不能使用 8 字节对齐的new
。以前的版本和较低级别的优化可能会偶然起作用,因为 GCC 没有利用整体对齐性…… - Julien Vivenot