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.

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