arm彙編指令:ldr和adr的區別

在分析uboot源碼時,遇到adr、ldr指令,卻分不清這2者的區別,網上很多解釋含糊不清,現對adr與ldr指令做解釋。

首先給出一段彙編代碼:

ldr     r0, _start
        adr     r0, _start
        ldr     r0, =_start
        nop
        mov     pc, lr
_start:
        nop

設置代碼的起始地址爲 0x0c008000,用 ADS1.2編譯後的反彙編如下所示:

0c008000 <_start-0x14>:
c008000:       e59f000c        ldr     r0, [pc, #12]   ; c008014 <_start>
c008004:       e28f0008        add     r0, pc, #8      ; 0x8
c008008:       e59f0008        ldr     r0, [pc, #8]    ; c008018 <_start+0x4>
c00800c:       e1a00000        nop                     (mov r0,r0)
c008010:       e1a0f00e        mov     pc, lr

0c008014 <_start>:
c008014:       e1a00000        nop                     (mov r0,r0)
c008018:       0c008014        stceq   0, cr8, [r0], -#80

分析: 
1、ldr     r0, _start;
這裏ldr是一個指令,把內存地址 _start(0c008014)對應的值(可能是數據或指令對應的機器碼)讀入。執行這個後,r0 = 0xe1a00000。

2、adr     r0, _start;小範圍的地址讀取僞指令
adr是一個僞指令,通過指令“add  r0, pc, #8 ”把_start標號對應的地址加載到 r0,因爲地址是相對程序的,因此adr產生依賴於位置的代碼。這裏這段代碼在 0x0c008000 運行,那麼 adr r0, _start 得到 r0 = 0x0c008014;如果在地址 0 運行,那麼r0 = 0x00000014。

通過這條僞指令就可以得知當前程序在內存的什麼位置運行。這是一條僞指令,但是功能卻如此強大,需要相應的編譯器功能才能實現。

3、ldr     r0, =_start;大範圍的地址讀取
這裏ldr是一個僞指令,用於加載32位的立即數或一個地址值到指定寄存器。這條指令取得的是標號_start 的絕對地址。這個絕對地址是在編譯器編譯完後進行 link(鏈接)的時候確定的。看上去這只是一個指令,但是它要佔用 2 個 32bit 的空間,一條是指令,另一條是 _start 的數據(因爲在編譯階段不能確定 _start 的值(要等到link時才確定),而且也不能用 mov 指令來給 r0 賦一個 32bit 的常量,所以需要多出一個空間存放 _start標號對應的地址數據,這裏就是 0x0c008014,r0=0x0c008014)。

參考:

https://www.cnblogs.com/amanlikethis/p/3419710.html 

https://www.cnblogs.com/jack739x/articles/2060762.html

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