使用指定的初始化程序时,不同的gcc程序集

时间:2018-11-26 12:22:34

标签: c gcc assembly arm

我正在检查一些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 };
}

对于ARM(ARM GCC 6.3.0),我得到了following output,带有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 个答案:

答案 0 :(得分:2)

看起来像gcc在将常量的负载合并到ldm中之后,它会以一种额外的间接方式在脚上射击。

不知道为什么,但是很明显错过了优化错误。

x86-64易于优化;整个8字节常数可以立即进入。但是ARM经常使用相对于PC的负载来加载常量,而这些常量对于一个立即数而言太大。