ARM上针对非对齐浮点数访问生成的GCC汇编

4
你好,我目前正在开发一个程序,需要处理一组浮点数的数据块,这些浮点数可能是未对齐的(有时候也是)。我正在使用gcc 4.6.2编译ARM cortex-a8的代码。我对生成的汇编代码有一个问题:
举个例子,我写了一个最小的示例:对于以下测试代码:
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;
}

7
C99标准中包含这样一条脚注:“在使用一元运算符*对指针进行引用时,无效的值包括空指针、指向对象类型不合适的地址……”。我毫不怀疑C++标准也会有类似的警告。因此,你的程序在技术上是未定义的,并且编译器可以随意生成任何指令序列,而不是出现错误。 - Pascal Cuoq
float* 总是被假定至少具有 alignof(float) 的对齐方式。如果你违反了这一点,你需要使用 memcpy 或其他方法来避免未定义行为。(即使在编译 x86 时也是如此)为什么在 AMD64 上对 mmap'ed 内存进行非对齐访问有时会导致段错误? / https://trust-in-soft.com/blog/2020/04/06/gcc-always-assumes-aligned-pointers/ - Peter Cordes
1个回答

3

正如您所指出的那样,ARM ARM A3.2.1 规定无论 SCTLR.A 值如何,VLDR 都会生成 Alignment fault

我已在 Cortex-A9 上测试了您的示例,结果如下:

# float_align                                                   
[1] + Stopped (signal)     float_align 

然而,我对ARM Cortex-A8 TRM 4.2.1也感到困惑,它说明:

如果未指定对齐限定符,并且A=1,则对齐故障将在其未对齐到元素大小时发生。

如果未指定对齐限定符,并且A=0,则视为非对齐访问

这可能是个不完整的解释,因为ARM ARM通过详细的指令表提供了更多信息。
因此,我认为答案是,需要自己注意对齐问题,因为编译器无法在所有情况下找出正在加载的地址,例如地址可能在链接后才可用等。

嗨,auselen,感谢您的回复。根据ARMv7-A和ARMv7-R章节A3.2对齐支持/A3.2.1的ARM架构参考手册,有一些指令(VLDR和其他指令)不支持未对齐访问。参考手册链接 - Jahn
感谢auselen的关注,我也会进一步研究Pascal关于C(++)标准的评论,并在此发布结果。 - Jahn
我也得出了结论,我们必须自己注意对齐方式。这是一个非常有趣的事实,特别是当您以指定格式获取无法控制的数据或者函数被调用时获得了指向其他位置创建的数据的指针时尤为如此。 - Jahn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接