你好,我目前正在开发一个程序,需要处理一组浮点数的数据块,这些浮点数可能是未对齐的(有时候也是)。我正在使用gcc 4.6.2编译ARM cortex-a8的代码。我对生成的汇编代码有一个问题:
举个例子,我写了一个最小的示例:对于以下测试代码:
编译器(gcc 4.6.2 - 使用优化选项 -O3)生成的结果是:
举个例子,我写了一个最小的示例:对于以下测试代码:
float aligned[2];
float *unaligned = (float*)(((char*)aligned)+2);
int main(int argc, char **argv)
{
float f = unaligned[0];
return (int)f;
}
编译器(gcc 4.6.2 - 使用优化选项 -O3)生成的结果是:
00008634 <main>:
8634: e30038ec movw r3, #2284 ; 0x8ec
8638: e3403001 movt r3, #1
863c: e5933000 ldr r3, [r3]
8640: edd37a00 vldr s15, [r3]
8644: eefd7ae7 vcvt.s32.f32 s15, s15
8648: ee170a90 vmov r0, s15
864c: e12fff1e bx lr
这里的编译器无法确定数据是否对齐,但仍然使用需要对齐数据的VLDR,否则程序将崩溃并显示总线错误。
现在我的实际问题是:这是来自编译器的正确信息,我需要在我的C++代码中处理对齐还是这是编译器的一个错误?
我还可以添加我的当前解决方法,它可以使gcc在访问值之前进行复制。诀窍是定义一个只包含带有gcc打包属性的浮点数的结构体,并通过结构体指针访问数据。代码片段:
struct FloatWrapper { float f; } __attribute__((packed));
const FloatWrapper *x = reinterpret_cast<const FloatWrapper *>(rawX.data());
const FloatWrapper *y = reinterpret_cast<const FloatWrapper *>(rawY.data());
for (size_t i = 0; i < vertexCount; ++i) {
vertices[i].x = x[i].f;
vertices[i].y = y[i].f;
}
float*
总是被假定至少具有alignof(float)
的对齐方式。如果你违反了这一点,你需要使用memcpy
或其他方法来避免未定义行为。(即使在编译 x86 时也是如此)为什么在 AMD64 上对 mmap'ed 内存进行非对齐访问有时会导致段错误? / https://trust-in-soft.com/blog/2020/04/06/gcc-always-assumes-aligned-pointers/ - Peter Cordes