代码之家  ›  专栏  ›  技术社区  ›  Lou

使用指定初始值设定项时的不同gcc程序集

  •  5
  • Lou  · 技术社区  · 6 年前

    我检查了一些gcc生成的arm程序集,发现如果使用指定的初始值设定项,会得到奇怪的结果:

    例如,如果我有这个代码:

    struct test 
    {
        int x;
        int y;
    };
    
    __attribute__((noinline))
    struct test get_struct_1(void)
    {
        struct test x;
        x.x = 123456780;
        x.y = 123456781;
        return x;
    }
    
    __attribute__((noinline))
    struct test get_struct_2(void)
    {
        return (struct test){ .x = 123456780, .y = 123456781 };
    }
    

    我得到了 following output 对于ARM(ARM GCC 6.3.0),GCC-O2-Std=C11:

    get_struct_1:
        ldr r1, .L2
        ldr r2, .L2+4
        stm r0, {r1, r2}
        bx lr
    .L2:
        .word 123456780
        .word 123456781
    
    
    get_struct_2:     // <--- what is happening here
        mov r3, r0
        ldr r2, .L5
        ldm r2, {r0, r1}
        stm r3, {r0, r1}
        mov r0, r3
        bx lr
    .L5:
        .word .LANCHOR0
    

    我可以看到第一个函数的常量,但我不明白 get_struct_2 作品。

    如果我为x86编译,两个函数只在一条指令中加载相同的单个64位值。

    get_struct_1:
        movabs rax, 530242836987890956
        ret
    
    get_struct_2:
        movabs rax, 530242836987890956
        ret
    

    我是在挑起一些不明确的行为,还是这样? .LANCHOR0 不知何故与这些常数有关?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Peter Cordes    6 年前

    看起来GCC在将常量的负载合并到一个LDM之后,以一个额外的间接级别在脚下进行了自我射击。

    不知道为什么,但很明显是一个遗漏的优化错误。

    x86-64很容易优化;整个8字节常量可以立即进入。但是ARM经常使用PC相对负载来处理那些对于一个即时事件来说太大的常量。