让我们用一个简单的 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/