在移植 uboot 時(shí),接觸到一個(gè)概念叫做 位置無(wú)關(guān)碼,那么與它對(duì)應(yīng)的就是位置有關(guān)碼。提到這兩個(gè)概念就還得提一提鏈接地址、加載地址
鏈接地址,鏈接腳本里指定的,理論上程序運(yùn)行時(shí)所處的地址。在編譯時(shí),編譯器會(huì)根據(jù)鏈接地址來(lái)翻譯位置有關(guān)碼。
加載地址,程序運(yùn)行時(shí),實(shí)際所處的地址。
位置無(wú)關(guān)碼,位置有關(guān)碼,是相對(duì)于一條指令的正常目的來(lái)說(shuō)的。比如 ldr r0 ,=標(biāo)號(hào),它的正常目的是取得標(biāo)號(hào)處的地址,對(duì)于這個(gè)目的,它是位置有關(guān)碼,運(yùn)行的地址不對(duì)就獲取不到正確的標(biāo)號(hào)地址,其實(shí)它無(wú)論在哪都是獲取的程序加載地址等于鏈接地址時(shí),標(biāo)號(hào)的地址,如果你就是想要這個(gè)值,那么用這條指令是非常正確的,就不用理會(huì)什么位置無(wú)關(guān)碼,位置有關(guān)碼的概念了,這一點(diǎn)非常重要。
因此,當(dāng)加載地址不等于鏈接地址時(shí),并不是不可以用位置無(wú)關(guān)碼,而是要看你用位置無(wú)關(guān)碼是否達(dá)到了你想要的目的。
位置無(wú)關(guān)碼,依賴于程序當(dāng)前運(yùn)行的PC值,進(jìn)行相對(duì)的跳轉(zhuǎn),導(dǎo)致的結(jié)果就是,無(wú)論代碼在哪,總能達(dá)到指令的正常目的,因此是位置無(wú)關(guān)的。
位置有關(guān)碼,不依賴當(dāng)前PC值,是絕對(duì)跳轉(zhuǎn),只有程序運(yùn)行在鏈接地址處時(shí),才能達(dá)到指令的正常目的,因此是位置有關(guān)系的。
下面,我們來(lái)看常用的匯編指令以及C語(yǔ)言中哪些操作是位置有關(guān)碼,哪些是位置無(wú)關(guān)碼。
如果加載地址為 0 ,那么代碼將按照下面的順序排放
如果加載地址為0x33f80000 則按照下邊的順序排放
?
一、B BL指令
- bl close_watch_dog
33f80000:eb000006bl33f80020
b 是相對(duì)跳轉(zhuǎn):PC + 偏移值 (PC值等于當(dāng)前地址+8)
偏移值:機(jī)器碼 0xeb000006 低 24位 0x000006 按符號(hào)為擴(kuò)展為 32 位 0x00000006 正數(shù),向后跳轉(zhuǎn) 0x6 個(gè) 4字節(jié) 也就是 0x1c
- bl _start
33f80004:ebfffffdbl33f80000
偏移值:機(jī)器碼 0xebfffffd 低 24位 fffffd 按符號(hào)位擴(kuò)展為 32 位 0xfffffffd 負(fù)數(shù)(-3),向前跳轉(zhuǎn) 0x3 個(gè) 4字節(jié) 也就是 0xc
通過(guò)以上分析,我們知道B是相對(duì)跳轉(zhuǎn),位置無(wú)關(guān)碼,也可以知道為什么32為arm指令集,B的范圍為正負(fù)32M了,24位去掉1位符號(hào)位,恰好等于32M。
二、ADR
- adr r0, close_watch_dog /* 獲取標(biāo)號(hào)處的地址,位置無(wú)關(guān) */
33f80008:e28f0010addr0, pc, #16
adr 獲取的是標(biāo)號(hào)處的“實(shí)際”地址,標(biāo)號(hào)在哪就是哪個(gè)地址,跟位置無(wú)關(guān),總能獲得想要的值。
三、LDR
- ldr r0, SMRDATA /* 獲取標(biāo)號(hào)處的值,位置無(wú)關(guān) */
33f8000c:e59f0018ldrr0, [pc, #24]; 33f8002c
- ldr r0, =0x12345678 /* 常數(shù)賦值,位置無(wú)關(guān)*/
33f80010:e59f0018ldrr0, [pc, #24]; 33f80030
- ldr r0, =SMRDATA /* 獲取標(biāo)號(hào)地址,位置有關(guān) */
33f80014:e59f0018ldrr0, [pc, #24]; 33f80034
- ldr r0, =main/* 獲取函數(shù)名的地址,位置有關(guān) */
- ldr r0 ,=__bss_start /* 獲取鏈接腳本里標(biāo)號(hào)的地址,位置有關(guān) */
這倆和ldr r0, =SMRDATA 一致,位置有關(guān),在0地址處運(yùn)行不正確。
四、C函數(shù)
1、全局變量
?
?
?
?
r3 為全局變量 a 的地址,a 是存放在 0起始的地址還是0x33f80000起始的地址,它都認(rèn)為 a 的地址是 0x33f800a0 。因此,C函數(shù)中調(diào)用全局變量是位置有關(guān)碼。
2、函數(shù)調(diào)用
33f80084:ebffffedbl33f80040
由于 main 函數(shù)和 abc 函數(shù)挨得比較近,在32M范圍之內(nèi),因此被翻譯成了一條 bl 指令,那么與位置無(wú)關(guān)。
如果,調(diào)用的函數(shù)比較遠(yuǎn),大于32M的話,我認(rèn)為是與位置有關(guān)系的,這個(gè)不再驗(yàn)證了。
3、局部變量
局部變量在函數(shù)剛開(kāi)始的地方被壓入棧,賦值語(yǔ)句被翻譯成:
33f8007c:e3a03001movr3, #1
33f80080: e50b3008 str r3, [fp, #-8]
位置無(wú)關(guān)。
評(píng)論
查看更多