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

标签 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 };
}

我使用 gcc -O2 -std=C11 for ARM (ARM GCC 6.3.0) 获得了 following output:

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 与这些常量有某种关联?

最佳答案

在将常量的负载合并到 ldm 之后,看起来 gcc 用额外的间接级别射击自己。

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

x86-64 很容易优化;整个 8 字节常量可以放在一个立即数中。但是 ARM 经常使用 PC 相对负载来处理对于一个立即数来说太大的常量。

关于c - 使用指定初始值设定项时不同的 gcc 程序集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53481048/

相关文章:

c - 我的程序不会按条件停止

c++ - 使用大于为 src 分配的内存的计数调用 memcpy 是否安全?

c - 写入与标准输出末尾不同的位置

c++ - GCC:__attribute__ ((format (printf, x, y)) 在使用可变参数宏调用函数时似乎不起作用

c++ - 与 nvidia 链接的 gcc 版本错误

assembly - 汇编-shr指令打开进位标志?

c - C 中函数的多重定义,原型(prototype)设计

c++ - 段错误 - 使用 getopt 时发生核心转储错误

c - 解密 x86 汇编函数

assembly - 在 DOS 中获取没有回显的键盘输入