新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 偽指令A(yù)DR和LDR的區(qū)別

偽指令A(yù)DR和LDR的區(qū)別

作者: 時(shí)間:2016-11-21 來(lái)源:網(wǎng)絡(luò) 收藏
ARM匯編有l(wèi)dr指令以及l(fā)dr、adr偽指令,他門(mén)都可以將標(biāo)號(hào)表達(dá)式作為操作數(shù),下面通過(guò)分析一段代碼以及對(duì)應(yīng)的反匯編結(jié)果來(lái)說(shuō)明它們的區(qū)別。 ldr r0, _start
adr r0,_start
ldr r0, =_start
_start:
b _start
編譯的時(shí)候設(shè)置 RO 為 0x30000000(運(yùn)行地址,runaddress),下面是反匯編的結(jié)果: 0x00000000: e59f0004 ldr r0, [pc, #4] ; 0xc 0x00000004: e28f0000 add r0, pc, #0 ; 0x0 0x00000008: e59f0000 ldr r0, [pc, #0] ; 0x10 0x0000000c: eafffffe b 0xc 0x00000010: 3000000c andcc r0, r0, ip -------------------------------------- 1.ldr r0, _start: 簡(jiǎn)單的說(shuō)就是把 _start地址存放的值讀出來(lái)。匯編程序計(jì)算出當(dāng)前位置執(zhí)行到_start(這里是一個(gè)標(biāo)號(hào),相對(duì)程序的位置表達(dá)式)位置pc所要增加的數(shù)值#4,然后由當(dāng)前pc(其實(shí)是當(dāng)前地址+2個(gè)指令字節(jié)長(zhǎng))加上偏移量#4,得到_start所在內(nèi)存地址,然后將內(nèi)存地址的值去出來(lái)放在r0中。只要此指令和標(biāo)號(hào)_start的相對(duì)位置不變,R0的值相同 0xeafffffe 2.adr r0, _start 簡(jiǎn)單的說(shuō)就是把 _start地址讀出來(lái),而且這個(gè)地址是相對(duì)當(dāng)前pc的,所以和當(dāng)前程序運(yùn)行地址相關(guān),如果在0x30000000運(yùn)行,r0 = pc(0x30000004 + 0x08) + #0 = 0x3000000C;如果在0x00000000運(yùn)行, r0 = pc(0x00000004 + 0x08) + #0 = 0x0000000C,所以在不同的位置運(yùn)行,r0所得到的結(jié)果是不一樣的,唯一確定的相對(duì)偏移量。 U-boot中那段relocate代碼就是通過(guò)adr實(shí)現(xiàn)當(dāng)前程序是在RAM中還是flash中,下面進(jìn)行簡(jiǎn)要分析。 -------------------------------------------------------------------------------- relocate: // 把U-Boot重新定位到RAM // adr r0, _start // r0是代碼的當(dāng)前位置 // // adr偽指令,匯編器自動(dòng)通過(guò)當(dāng)前PC的值算出 如果執(zhí)行到_start時(shí)PC的值,放到r0中: 當(dāng)此段在flash中執(zhí)行時(shí)r0 = _start = 0;當(dāng)此段在RAM中執(zhí)行時(shí)_start = _TEXT_BASE(在board/smdk2410/config.mk中指定的值為0x30000000,即u-boot在把代碼拷貝到RAM中去執(zhí)行的代碼段的開(kāi)始) // ldr r1, TEXT_BA_SE // 測(cè)試判斷是從Flash啟動(dòng),還是RAM // // 此句執(zhí)行的結(jié)果r1始終是0x30000000,因?yàn)榇酥凳怯志幾g器指定的(ads中設(shè)置,或-D設(shè)置編譯器參數(shù)) // cmp r0, r1 // 比較r0和r1,調(diào)試的時(shí)候不要執(zhí)行重定位 // -------------------------------------------------------------------------------- 3. ldr, r0, =_start 這是一條偽指令,取得得是_start的絕對(duì)地址,不管在身地方運(yùn)行,r0 = 0x3000000C ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 看《嵌入式linux應(yīng)用開(kāi)發(fā)》第六章實(shí)例中看到個(gè)句: adrl r2,men_cfg_val 最初對(duì)adr1相當(dāng)不解,后來(lái)發(fā)現(xiàn),那個(gè)不是數(shù)字1,而是字母l(認(rèn)真看頭部,有點(diǎn)區(qū)別的) 這里記錄下ADRL的用法:功能:將相對(duì)于程序或相對(duì)于寄存器的地址載入寄存器中。 與 ADR 指令相似。ADRL 生成兩個(gè)數(shù)據(jù)處理指令,因此它比 ADR 加載的地址范圍要寬。 語(yǔ)法 ADRL{cond} Rd,label 其中: cond:是一個(gè)可選的條件代碼。Rd:是要加載的寄存器。label:是相對(duì)于程序或寄存器的表達(dá)式。上面給出的范圍是相對(duì)于位于當(dāng)前指令地址后的、距離當(dāng)前指令四個(gè)字節(jié)(在 Thumb 代碼中)或兩個(gè)字(在 ARM 代碼中)遠(yuǎn)的點(diǎn)而言的。如果對(duì)齊為 16 字節(jié),或與此點(diǎn)的相關(guān)性更高,則遠(yuǎn)程地址的范圍可更大。查看ADRL的同時(shí),看到篇講述ldr與adr的區(qū)別的博文,感覺(jué)寫(xiě)的很好,摘錄下來(lái)。 http://coon.blogbus.com/logs/2738861.html ldr r0, _start adr r0, _start ldr r0, =_start nop mov pc, lr _start: nop 編譯的時(shí)候設(shè)置 RO 為 0x0c008000 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 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 分析: ldr r0, _start 從內(nèi)存地址 _start 的地方把值讀入。執(zhí)行這個(gè)后,r0 = 0xe1a00000 adr r0, _start 取得 _start 的地址到 r0,但是請(qǐng)看反編譯的結(jié)果,它是與位置無(wú)關(guān)的。其實(shí)取得的時(shí)相對(duì)的位置。例如這段代碼在 0x0c008000 運(yùn)行,那么 adr r0, _start 得到 r0 = 0x0c008014;如果在地址 0 運(yùn)行,就是 0x00000014 了。 ldr r0, =_start 這個(gè)取得標(biāo)號(hào) _start 的絕對(duì)地址。這個(gè)絕對(duì)地址是在 link 的時(shí)候確定的??瓷先ミ@只是一個(gè)指令,但是它要占用 2 個(gè) 32bit 的空間,一條是指令,另一條是 _start 的數(shù)據(jù)(因?yàn)樵诰幾g的時(shí)候不能確定 _start 的值,而且也不能用 mov 指令來(lái)給 r0 賦一個(gè) 32bit 的常量,所以需要多出一個(gè)空間存放 _start 的真正數(shù)據(jù),在這里就是 0x0c008014)。 因此可以看出,這個(gè)是絕對(duì)的尋址,不管這段代碼在什么地方運(yùn)行,它的結(jié)果都是 r0 = 0x0c008014 看此文最大的收獲不在于說(shuō)懂了這幾個(gè)命令的用法,關(guān)鍵卻在于反匯編的運(yùn)用,有反匯編看出不同用法的具體差別。注:反匯編用arm—linux_objdump就可以實(shí)現(xiàn)了。


關(guān)鍵詞: 偽指令A(yù)DRLD

評(píng)論


技術(shù)專區(qū)

關(guān)閉