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

标签 c++ gcc glibc memory-alignment gcc6

(很抱歉未能将我的问题简化为一个简单的失败测试用例...)

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

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

在这个构造函数中,GCC 使用了 movaps :

movaps %xmm0,0x30a0(%ebx)

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

“The address of a block returned by malloc or realloc in GNU systems is always a multiple of eight (or sixteen on 64-bit systems).“

因此出现段错误(当使用 -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

最佳答案

编译器可能有理由认为对象的对齐长度≥ 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 的类特定运算符重载相结合。

关于c++ - 为什么 GCC 6 假设数据是 16 字节对齐的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42271584/

相关文章:

c++ - 我收到此错误 : "glibc detected"

c++ - c++中new int和new(int)有什么区别?

长序列上的 C++ 正则表达式段错误

c - 使用 GCC 和 Make 时如何禁用警告失败?

malloc - 在 glibc malloc 中迭代所有 arenas 中的所有 block

c - 如何索引障碍分配

c++ - XCode 4.6 上的 VST - 插件在加载时直接提供高输出

c++ - 当类有多个模板参数时专门化成员模板?

c++ - 为什么包含头文件是一件邪恶的事情?

memory - __attribute__((packed,aligned(n))) 和 __attribute__((aligned(n))) 有什么区别?