gcc - GCC 生成的 ARM 和 x86 汇编代码的区别

标签 gcc assembly compiler-construction x86 arm

让我们用一个简单的 C 代码来设置寄存器:

int main()
{
    int *a = (int*)111111;
    *a = 0x1000;
    return 0;
}

当我使用 1 级优化为 ARM (arm-none-eabi-gcc) 编译此代码时,汇编代码类似于:

mov     r2, #4096
mov     r3, #110592
str     r2, [r3, #519]
mov     r0, #0
bx      lr

看起来地址 111111 被解析到最近的 4K 边界 (110592) 并移动到 r3,然后通过将 519 添加到 110592 (=111111) 来存储值 4096(0x1000)。为什么会这样?

在 x86 中,汇编很简单:

movl    $4096, 111111
movl    $0, %eax
ret

最佳答案

这种编码背后的原因是因为 x86 具有可变大小的指令——从 1 字节到 16 字节(甚至可能更多带有前缀)。

ARM 指令是 32 位宽(不包括 Thumb 模式),这意味着不可能在单个操作码中编码所有 32 位宽常量(立即数)。

固定大小的架构通常使用几种方法来加载大常量:

1)  movi  #r1, Imm8  ; // Here Imm8 or ImmX is simply X least significant bits
2)  movhi #r1, Imm16 ; // Here Imm16 loads the 16 MSB of the register
3)  load  #r1, (PC + ImmX);  // use PC-relative address to put constant in code
4)  movn  #r1, Imm8 ;  // load the inverse of Imm8 (for signed constants) 
5)  mov(i/n) #1, Imm8 << N;       // where N=0,8,16,24

可变大小的架构 OTOH 可以将所有常量放在一条指令中:

xx xx xx 00 10 00 00 11 11 11 00 ; // assuming that it takes 3 bytes to encode
                                 ; // the instruction and the addressing mode
; added with 4 bytes to encode the 4096 and 4 bytes to encode 0x00111111

关于gcc - GCC 生成的 ARM 和 x86 汇编代码的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21968256/

相关文章:

c# - 如何在C#中实现泛型(可能与C++和Java有关)?

java - 为什么 `Class` 和 `Class<?>` 的实例具有不同的行为,而它不应该如此?

-O3 与 -Ofast 优化之间的 gcc 差异

c++ - 使用 gcc 是否可以链接库,但前提是它存在?

c++ - 从地址位置加载 XMM 寄存器

c++ - 使用内联 x86 C++ 程序集将寄存器内容移动到变量时出现错误 C2403

windows-mobile - 获取 ARM 汇编中的 PC 值

compiler-construction - 将上下文无关文法转换为 LL(1)

c - Linux 和 Windows 上的 malloc_size 替代方案

c++ - 如何正确地将 OpenCV 库链接到 Windows 上的 Eclipse?