【问题标题】:Why does GCC 6 assume data is 16-byte aligned?为什么 GCC 6 假设数据是 16 字节对齐的?
【发布时间】:2017-07-05 10:11:26
【问题描述】:

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

我在升级到 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)。”

因此出现段错误(使用 -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,但检查起来会很痛苦。
  • 拥有alignof==16 不是错误,但这意味着你不能使用glibc 的malloc。再说一次,标准限制了实现的malloc,而不是操作系统的malloc。 GCC 可能需要包装 glibc。 (我认为无论如何都应该这样做)
  • alignof 返回64alignof(max_align_t) 返回 8(预期)。对对象或其成员的对齐没有用户要求;为什么 alignof 会是 64 ?我没有直接使用malloc,而是假设new正在使用它。
  • 好吧好吧好吧……在结构深处几层,我刚刚找到了缓存行大小所需的对齐方式。这就是alignof==64 的全部原因。正如@TrentP 和@MSalters 指出的那样,这也意味着我不能使用8 字节对齐的new。由于 GCC 没有利用整体对齐的优势,因此曾经偶然使用以前的版本和较少的优化...
  • (请随意让您的 cmets 回答让我验证)

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


【解决方案1】:

编译器可能有理由认为对象的对齐方式≥ 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,但 new 运算符的放置形式相结合,以在该内存中构造对象或newdelete 的类特定运算符重载。

【讨论】:

猜你喜欢
  • 2020-03-24
  • 1970-01-01
  • 2023-04-08
  • 2015-09-02
  • 2012-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-18
相关资源
最近更新 更多