執行時域和載入時域(執行位址和載入位址)
參考文獻: 雲邊日的空間
mr_raptor的專欄
在連線目標**時
,會提到執行位址和載入位址。載入時位址就是程式放置的位址,執行位址就是程式定位的絕對位址,也即在編譯連線時定位的位址。如果程式是在
flash
裡執行,
則執行位址和載入位址是相同的。如果程式是在
ram裡執行
,但程式是儲存在
flash裡,
則執行位址指向
ram,
而載入位址是指向
flash
。下面我們看看鏈結檔案。
對於.lds
檔案,它定義了整個程式編譯之後的連線過程,決定了乙個可執行程式的各個段的儲存位置。先看一下
gnu官方**上對
.lds
檔案形式的完整描述:
sections >region :phdr =fill
...
} sections >region :phdr =fill...}
secname
和contents
是必須的,其他的都是可選的。下面看看幾個常用的:1、
secname
:段名2
、contents
:決定哪些內容放在本段,可以是整個目標檔案,也可以是目標檔案中的某段(**段、資料段等)3、
startat(
ldadr
),本段儲存的位址也是
start
。gnu
**上說
start
可以用任意一種描述位址的符號來描述。4、
at(ldadr
看乙個簡單的例子:
sections
second 0x30000000 : at(4096)
}以上,
head.o
放在0x00000000
位址開始處,
init.o
放在head.o
後面,他們的執行位址也是
0x00000000
,即連線和儲存位址相同(沒有
at指定);
main.o
放在4096
(0x1000
,是at
指定的,儲存位址)開始處,但是它的執行位址在
0x30000000
,執行之前需要從
0x1000
(載入處)複製到
0x30000000
(執行處),此過程也就用到了讀取
nand flash
。這就是儲存位址和連線(執行)位址的不同,稱為載入時域和執行時域,可以在
.lds
連線指令碼檔案中分別指定。
編寫好的
.lds
檔案,在用
arm-linux-ld
連線命令時帶
-tfilename
來呼叫執行,如
arm-linux-ld –tnand.lds x.o y.o –o xy.o
。也用-ttext
引數直接指定連線位址,如
arm-linux-ld –ttext 0x30000000 x.o y.o –o xy.o
。總之:
連線位址
<==>
執行位址
儲存位址
<==>
載入位址
既然程式有了兩種位址,就涉及到一些跳轉指令的區別,下面就來具體看看這些跳轉指令。
arm彙編中,常有兩種跳轉方法:
b跳轉指令、
ldr指令向
pc賦值。(1
)b step1 :b
跳轉指令是相對跳轉,依賴當前
pc的值,偏移量是通過該指令本身的
bit[23:0]
算出來的,這使得使用
b指令的程式不依賴於要跳到的**的位置,只看指令本身。(2
)ldr pc, =step1
:該指令是從記憶體中的某個位置(
step1
)讀出資料並賦給
pc,同樣依賴當前
pc的值,但是偏移量是那個位置(
step1
)的連線位址(執行時的位址),所以可以用它實現從
flash
到ram
的程式跳轉。
我們以後會經常用到
「儲存位址和連線位址不同
」(術語上稱為載入時域和執行時域)0
開始執行的,但是從位址
0執行程式在效能方面總有很多限制,(執行位址和載入位址不同時,只能用相對跳轉)所以一般在開始的時候,使用與位置無關的指令將程式本身複製到它的連線位址處,然後使用向
pc暫存器賦值的方法跳到連線位址開始的記憶體上去執行剩下的**。
此外,有必要回味一下
adr偽指令,
u-boot
中那段relocate
**就是通過
adr實現當前程式是在
ram中還是
flash
中。仍然用我當時的注釋:
relocate: /* 把u-boot重新定位到
ram */
adr r0, _start /* r0是**的當前位置
*/ /* adr
偽指令,彙編器自動通過當前
pc的值算出
如果執行到
_start時pc
的值,放到
r0中:
當此段在flash中執行時r0 = _start = 0;當此段在ram中執行時_start = _text_base(在board/smdk2410/config.mk中指定的值為0x33f80000,即u-boot在把**拷貝到ram中去執行的**段的開始
) */
ldr r1, _text_base /* 測試判斷是從flash啟動,還是
ram */
/* 此句執行的結果r1始終是0x33ff80000,因為此值是又編譯器指定的(ads中設定,或-d設定編譯器引數
) */
cmp r0, r1 /* 比較r0和r1,除錯的時候不要執行重定位 */
注:ads中 ro base address設定的是ro的執行位址,如果沒有指定這個選項,則預設為ro基位址為0x8000。image ro base is the address of the read-only execution region (usually contains code and read-only data).;rw base address設定的是rw段的執行位址, image rw base is the address of the read-write execution region (usually contains data).;這兩個位址必須是字對齊的。
執行時域和載入時域(執行位址和載入位址)
看乙個簡單的例子 sections second 0x30000000 at 4096 以上,head.o放在0x00000000位址開始處,init.o放在head.o後面,他們的執行位址也是0x00000000,即連線和儲存位址相同 沒有at指定 main.o放在4096 0x1000,是at指...
執行位址和載入位址
在連線目標 時,會提到執行位址和載入位址。這兩者有什麼區別呢?載入時位址就是程式放置的位址,執行位址就是程式定位的絕對位址,也即在編譯連線時定位的位址 如果程式是在flash裡執行,則執行位址和載入位址是相同的。如果程式是在ram裡執行,但程式是儲存在flash裡,則執行位址指向ram,而載入位址是...
執行位址和載入位址
在連線目標 時,會提到執行位址和載入位址。這兩者有什麼區別呢?載入時位址就是程式放置的位址,執行位址就是程式定位的絕對位址,也即在編譯連線時定位的位址 如果程式是在flash裡執行,則執行位址和載入位址是相同的。如果程式是在ram裡執行,但程式是儲存在flash裡,則執行位址指向ram,而載入位址是...