LDR与ADR伪指令的区别

在学习ARM汇编指令的时候,经常会使用到ldr与adr两条指令,相信大部分初学的人曾经都对这两个命令产生过疑惑。

其实这两条指令都是伪指令:

  • ldr指令是大范围的地址读取伪指令,相对于PC寄存器或其他寄存器的大范围跳转;
  • adr指令是小范围的地址读取伪指令,相对于PC寄存器或其他寄存器的小范围跳转。

要想清楚的说明这两条指令的区别,还是得从实际的例子中来解释,空谈泛泛,难以实际掌握。

    ldr r0, _start
    nop
    nop
    adr r0, _start
    nop
    nop
    ldr r0, =_start
    nop
    nop
_start:
    nop

反汇编后的结果如下:

1   0x00000000: e59f001c ... LDR r0, [pc, #28]; [0x24]=e1a00000
2   0x00000004: e1a00000 ... MOV r0, r0
3   0x00000008: e1a00000 ... MOV r0, r0
4   0x0000000c: e28f0010 ... ADD r0, pc, 0x10; r0=x00000024
5   0x00000010: e1a00000 ... MOV r0, r0 
6   0x00000014: e1a00000 ... MOV r0, r0
7   0x00000018: e59f0008 ... LDR r0, [pc, #8]; [0x28]=00000024
8   0x0000001c: e1a00000 ... MOV r0, r0
9   0x00000020: e1a00000 ... MOV r0, r0
_start:
10  0x00000024: e1a00000 ... MOV r0, r0
    $d  存放_start地址值
11  0x00000028: 00000024 ... DCD 36

第一行,寄存器间接寻址,获取_start的地址,此时,r0=0xe1a00000.
第四行,此时,r0=0x00000024.
第七行,取得标号_start的绝对地址,这个绝对地址是在link的时候确定的,看上去这只是一条指令,但是它要占用2个32bit的空间,一条是指令,另一条是_start的数据。因为在编译的时候不能够确定_start的值,而且也不能够用mov指令来给r0赋一个32bit的常量,所以需要多出一个空间来存放_start的真正数据,在这里就是0x00000024,由此可以看出,这个是绝对寻址,不管代码在什么地方运行,它的结果都是r0=0x00000024.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章