ldr和adr的區別

作者:孫曉明,華清遠見嵌入式學院講師。

同學們在學習ARM指令時,多數都會對adr和ldr這兩個命令產生疑惑,那他們究竟有什麼區別呢?

其實這兩個都是僞指令:adr是小範圍的地址讀取僞指令,ldr是大範圍的讀取地址僞指令。可實際上adr是將基於PC相對偏移的地址值或基於寄存器相對地址值讀取的爲指令,而ldr用於加載32爲立即數或一個地址到指定的寄存器中。到這兒就會看到其中的區別了。如果在程序中想加載某個函數或者某個在聯接時候指定的地址時請使用adr,例如在lds中需要重新定位的地址。當加載32爲的立即數或外部地址時請用ldr。

我給大家先舉個例子:

AREA test,CODE,READONLY
        ENTRY

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

        
_start
        nop
        END

這段代碼並無實際意義,只是爲了方便說明。我們反彙編一下看看:

4:                 ldr      r0,_start
        0x00000000          E59F0008      LDR       R0,[PC,#0x0008]
        5:                  adr      r0,_start
        0x00000004          E28F0004       ADD      R0,PC,#0x00000004
        6:                  ldr      r0,=_start
        0x00000008          E59F0004      LDR       R0,[PC,#0x0004]
        7:                  nop
        8:
        9:
        10: _start
        0x0000000C           E1A00000           NOP
        11:           nop

ldr           r0, _start

從內存地址 _start 的地方把值讀入。執行這個後,r0 = 0xe1a00000

adr         r0, _start

取得 _start 的地址到 r0,但是請看反編譯的結果,它是與位置無關的。其實取得的時相對的位置。例如這段代碼在 0x00000000 運行,那麼 adr r0, _start 得到 r0 = 0x00000010;

ldr          r0, =_start

這個取得標號 _start 的絕對地址。這個絕對地址是在 link 的時候確定的。看上去這只是一個指令,但是它要佔用 2 個 32bit 的空間,一條是指令,另一條是 _start 的數據(因爲在編譯的時候不能確定 _start 的值,而且也不能用 mov 指令來給 r0 賦一個 32bit 的常量,所以需要多出一個空間存放 _start 的真正數據,在這裏就是 0x0000000c)。

因此可以看出,這個是絕對的尋址,不管這段代碼在什麼地方運行,它的結果都是 r0 = 0x0000000c。

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