2

我正在使用 linaro g++ for ARM arch64 来编译一个简单的 cpp 文件:

int main()
{
    char  *helloMain      = "main module (crm.c)";
    long  faculty, num    = 12;
    int   stop,mainLoop   = 1; 
    char  word[80]        = "";
}

生成elf文件后objdump,我得到了它的asm代码:

0000000000001270 <main>:
int main()
{
    1270:   d101c3ff    sub sp, sp, #0x70
    char  *helloMain      = "main module (crm.c)";
    1274:   90000020    adrp    x0, 5000 <_malloc_trim_r+0x160>
    1278:   9111c000    add x0, x0, #0x470
    127c:   f90003e0    str x0, [sp]
    long  faculty, num    = 12;
    1280:   d2800180    movz    x0, #0xc
    1284:   f90007e0    str x0, [sp,#8]
    int   stop,mainLoop   = 1; 
    1288:   52800020    movz    w0, #0x1
    128c:   b90013e0    str w0, [sp,#16]
    char  word[80]        = "";
    1290:   910063e0    add x0, sp, #0x18
    1294:   90000021    adrp    x1, 5000 <_malloc_trim_r+0x160>
    1298:   91122021    add x1, x1, #0x488
    129c:   39400021    ldrb    w1, [x1]
    12a0:   39000001    strb    w1, [x0]
    12a4:   91000400    add x0, x0, #0x1
    12a8:   a9007c1f    stp xzr, xzr, [x0]
    12ac:   a9017c1f    stp xzr, xzr, [x0,#16]
    12b0:   a9027c1f    stp xzr, xzr, [x0,#32]
    12b4:   a9037c1f    stp xzr, xzr, [x0,#48]
    12b8:   f900201f    str xzr, [x0,#64]
    12bc:   b900481f    str wzr, [x0,#72]
    12c0:   7900981f    strh    wzr, [x0,#76]
    12c4:   3901381f    strb    wzr, [x0,#78]
}
    12c8:   52800000    movz    w0, #0x0
    12cc:   9101c3ff    add sp, sp, #0x70
    12d0:   d65f03c0    ret

在 ARMV8 板上执行此代码之前,sp将其初始化为与 0x1000 对齐的地址。

此类代码的执行在 12a8 上引发了对齐错误异常:a9007c1f stp xzr, xzr, [x0]

我注意到x0被添加了,0x1所以它与指令执行的0x1时间对齐。stp

为什么g ++没有使其对齐0x10以避免这种对齐错误异常?

g++ 版本是:

gcc  4.8.1 20130506 (prerelease) (crosstool-NG linaro-1.13.1-4.8-2013.05 - Linaro GCC 2013.05)
4

2 回答 2

4

手册

-munaligned-access
-mno-unaligned-access

启用(或禁用)从非 16 位或 32 位对齐的地址读取和写入 16 位和 32 位值。默认情况下,对所有 pre-ARMv6 和所有 ARMv6-M 架构禁用未对齐访问,并为所有其他架构启用。如果未启用未对齐访问,则打包数据结构中的字将一次访问一个字节。

ARM 属性 Tag_CPU_unaligned_access 将在生成的目标文件中设置为 true 或 false,具体取决于此选项的设置。如果启用了非对齐访问,那么预处理器符号 __ARM_FEATURE_UNALIGNED 也将被定义。

AArch64/ARMv8 支持开箱即用的非对齐访问,因此 GCC 假定它是可用的。如果不是这种情况,您可能必须使用上述开关显式禁用它。您正在使用的“预发布”版本也可能尚未完成,并且存在各种错误/问题。

编辑

正如评论中提到的,对应的AArch64 选项是:

-mstrict-align
-mno-strict-align

如架构规范中所述,避免或允许生成可能未在自然对象边界上对齐的内存访问。

顺便说一下,代码的行为是这样的,因为 GCC 按字面意思解释了赋值:

  1. 将字符串“”(因此只是一个零字节)复制到缓冲区的开头。
  2. 用零填充缓冲区的其余部分。

我怀疑如果您启用优化,未对齐的访问将会消失。或者,如果您使用char word[80] = {0},它应该一次性完成归零。

于 2014-04-24T11:35:43.337 回答
4

经过对ARMV8架构的一些研究,我对自己遇到的data abort exception有了更深入的了解。

  1. 为什么会发生这种对齐错误异常?

    正如@IgorSkochinsky 所提到的,AArch64/ARMv8 支持非对齐访问。但是由于我在一个简单的裸机环境中工作,MMU 没有被启用,所以在这种情况下,内存被视为一个设备,并且设备不支持未对齐的访问。如果启用了 MMU,则此异常消失。

  2. 如何强制 GCC 编译未对齐访问的免费 elf 文件?

    从手册来看,-mno-unaligned-access应该足够了,但对于我的 GCC 版本:

    gcc 4.8.1 20130506(预发布)(crosstool-NG linaro-1.13.1-4.8-2013.05 - Linaro GCC 2013.05)

    它说没有这样的选择。就我而言,另一种选择-mstrict-align解决了这个问题。

于 2014-04-29T06:57:43.260 回答