執行時域和載入時域(執行位址和載入位址)

2021-06-08 20:58:41 字數 3343 閱讀 1229

執行時域和載入時域(執行位址和載入位址)

參考文獻:   雲邊日的空間

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,而載入位址是...