Linaro g++ aarch64编译导致未对齐错误

Log*_*ing 2 arm g++ memory-alignment arm64

我使用 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]        = "";
}
Run Code Online (Sandbox Code Playgroud)

objdump生成elf文件后,我得到了它的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
Run Code Online (Sandbox Code Playgroud)

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

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

我注意到x0添加了,因此它与执行指令时0x1对齐。0x1stp

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

g++ 版本是:

gcc  4.8.1 20130506 (prerelease) (crosstool-NG linaro-1.13.1-4.8-2013.05 - Linaro GCC 2013.05)
Run Code Online (Sandbox Code Playgroud)

Igo*_*sky 5

手册中:

-munaligned-access
-mno-unaligned-access

启用(或禁用)从非 16 位或 32 位对齐的地址读取和写入 16 位和 32 位值。默认情况下,对于所有 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},它应该一次性完成归零。

  • 请注意(如下面的答案中所述)等效的 AArch64 选项是 -mstrict-align (https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html) (2认同)