Why does GCC 6 assume data is 16-byte aligned?

有些话、适合烂在心里 提交于 2021-02-07 12:15:19

问题


(Sorry in advance for not having managed to reduce my problem to a simple failing test case...)

I have faced issues with upgrading to GCC 6.3.0 to build our codebase (relevant flags: -O3 -m32).

Specifically, my application segfaults within a struct ctor call because of GCC optimizations.

In this ctor, GCC used movaps :

movaps %xmm0,0x30a0(%ebx)

movaps requires the operand to be 16-byte aligned. But at this point in time, %ebx points to my object, which is not necessarily 16-byte aligned. From 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).“

Hence the segfault (when built with -O3 -m32).

Why does it seem like GCC assumed the allocated object would be 16-byte aligned ? Am I misunderstanding something ?

Notes:

  • No alignment hints or attributes on this struct
  • Object has been initialized via default new operator
  • Depends on the level of optimization:
    • PASS: -m32 -O2
    • FAIL: -m32 -O2 -ftree-slp-vectorize
    • PASS: -m32 -O3 -fno-tree-slp-vectorize
    • FAIL: -m32 -O3

This other project, seem to have hit similar issues : https://github.com/godotengine/godot/issues/4623

Their investigation points to -fvect-cost-model=dynamic. Investigation on my codebase rather points to -ftree-slp-vectorize.


回答1:


It's possible that the compiler has a reason to think the object has an alignment ≥ 16 bytes. It's possible to find out what the compiler thinks the alignment is by using the alignof() operator in C++11. GCC has an extension __alignof__ that is available in C and earlier C++ versions.

A structure's alignment is the highest alignment of anything in it, recursively. There could be something in there with higher alignment than expected.

While the C++11 standard guarantees that memory returned by new is aligned to the value needed by the "fundamental alignment requirement" of any object, this only applies to standard types and objects made of them. Using C++11 alignas() or the __attribute__((aligned(x))) GCC extension to request higher alignment might exceed what new provides.

A solution to this would be to use std::aligned_alloc() (C++11 or later) or posix_memalign() (POSIX-only but < C++11) to get aligned memory. This could be coupled with the placement form of the new operator to construct the object in that memory or class specific operator overloads of new and delete.



来源:https://stackoverflow.com/questions/42271584/why-does-gcc-6-assume-data-is-16-byte-aligned

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!