__int128 gcc -O SSE 优化对齐段错误

__int128 alignment segment fault with gcc -O SSE optimize

我使用 __int128 作为结构的成员。 它适用于 -O0(无优化)。

但是,如果启用优化 (-O1),它会因段错误而崩溃。

它在指令 movdqa 处崩溃,该指令需要 var 对齐 16。 地址由 malloc() 分配,仅按 8.

对齐

我试图通过 -mno-sse 禁用 SSE 优化,但编译失败:

/usr/include/x86_64-linux-gnu/bits/stdlib-float.h:27:1: error: SSE register return with SSE disabled

如果我想同时使用 __int128-O1 怎么办?

提前致谢 吴

顺便说一句,如果 __int128 仅用于堆栈(而不是堆)似乎没问题。

==== 编辑 ====

对不起,我没有说实话。

其实我没有用malloc()。我使用了一个 returns 地址按 8 对齐的内存池库。 我说malloc()只是想简单点。

经过测试,我知道 malloc() 是按 16 对齐的。而且 __int128 成员在 struct 中也是按 16 对齐的。

所以问题只是我的内存池库。

非常感谢。

对于 x86-64 System V,alignof(max_align_t) == 16 所以 malloc 总是 returns 16 字节对齐的指针。听起来你的分配器坏了,如果也用于 long double 也会违反 ABI。 (将此作为答案重新发布,因为事实证明 答案)。

malloc 返回的内存保证能够容纳任何标准类型,这意味着如果大小足够大,则足够对齐。

这不能是 32 位代码,因为 gcc 在 32 位目标中不支持 __int128。 (我认为 32 位 glibc malloc 仅保证 8 字节对齐。实际上在当前系统上,alignof(max_align_t) == 16 在 32 位模式下也是如此。)


一般来说,如果您违反了类型的对齐要求,编译器允许生成错误的代码。在 x86 上,事情通常只适用于未对齐的内存,直到编译器使用需要对齐的 SIMD 指令。即使 uint16_t* 未对齐的自动矢量化也会出错 (),所以不要假设窄类型总是安全的。如果需要在 C 中表达未对齐的负载,请使用 memcpy


显然 alignof(__int128) 是 16。所以他们没有重复 i386 System V 中的怪异之处,即使是 8 字节的对象也只能保证 4 字节对齐,而结构打包规则意味着编译器不能'不要总是让他们自然对齐。

这是一件好事,因为它使使用 SSE 进行复制变得高效,并且意味着 _Atomic __int128 不需要任何额外的特殊处理来避免缓存行拆分,这会使 lock cmpxchg16b很慢。