鏈接地址

位置無關碼:CPU取指時,總是相對於本條執行指令的相對地址去取指。比如指行一個ADD指令時,PC要取下一指令的地址,就在原來的基礎上+4。這就不管你代碼放在存儲器的任何位置,只要他們的相對地址沒有改變,就能正常執行程序。一般上電覆位那幾條語句就必須是位置無關碼指令。


位置相關碼:可以這樣來說,就是CPU每次取指都從絕對位置去取,而不是上面的相對位置。這個絕對地址就是相對起始地址0來說的。這樣,就要求你在存放程序時,必須給連接腳本所規定的一樣,把代碼放到指定位置。



應用程序必須經過編譯、彙編和鏈接後才變成可執行文件,在鏈接時,要對所有目標文件進行重定位(relocation),建立符號引用規則,同時爲變量、函數等分配運行地址。當程序執行時,系統必須把代碼加載到鏈接時所指定的地址空間,以保證程序在執行過程中對變量、函數等符號的正確引用,使程序正常運行。在具有操作系統的系統中,重定位過程由操作系統自動完成。  在設計Bootloader程序時,必須在裸機環境中進行,這時Bootloader映像文件的運行地址必須由程序員設定。通常情況下,將Bootloader程序下載到ROM的0x0地址進行啓動,而在大多數應用系統中,爲了快速啓動,首先將Bootloader程序拷貝到SDRAM中再運行。一般情況下,這兩者的地址並不相同。

首先來看下面的鏈接腳本文件:

ENTRY(_start)
 ;指定輸出可執行文件的起始代碼段爲_start.
SECTIONS
{
 .= BOOTADDR ; bootloader的開始地址/
 .= ALIGN(4); 代碼以4字節對齊
 .text :;指定代碼段
 {
 cpu/arch/start.o (.text) ; bootloader中的text段
 *(.text)                 ;其它text段   
 }
 .= ALIGN(4)
 .rodata :{*(.rodata)};指定只讀數據段
 .= ALIGN(4);
 .data :{*(.data)};指定讀/寫數據段
 .= ALIGN(4);
 __bss_start =.; 把__bss_start賦值爲當前位置,即bss段的開始位置
 .bss :{*(.bss)}; 指定bss段
 _end =.; 把_end賦值爲當前位置,即bss段的結束位置
}

需要指出的是,鏈接腳本中所描述的輸出段地址爲虛擬地址VMA(VirtualMemoryAddress)。這裏的“虛擬地址”僅指映像文件執行時,各輸出段所重定位到相應的存儲地址空間,與映像文件燒寫到的實際的地址無關(即映像的加載地址)。因此,上面的鏈接腳本實際上指定了Bootloader映像在執行時,將被重定位到BOOTADDR開始的存儲地址空間,以保證在相關位置對符號進行正確引用,使程序正常運行。

假設這裏指定BOOTADDR= 0x0。以ARM爲例,ARM處理器復位後總是從0x0地址取第1條指令,因此只需把BOOTADDR設置爲0,再把編譯後生成的可執行二進制文件下載到ROM的0x0地址開始的存儲空間,程序便可正常引導;但是,一旦在鏈接時指定映像文件從0x0地址開始,那麼Bootloader就只能在0x0地址開始的ROM空間內運行,而無法拷貝到SDRAM空間運行實現快速引導。當然,搬運代碼最後的跳轉語句可以寫成絕對地址,如jmp 0x10000,這樣可以正確的跳到RAM中的0x10000地址處,但當執行繼續執行碰到其他符號地址計算,或全局數據訪問的時候,由於此時不是位置無關代碼,此時地址的計算需要查詢map表,但是map表中的地址仍然在ROM空間中,所以還會跳回ROM空間,另外,還會有其他問題,如動態內存申請等。

有了位置無關代碼,只需修改鏈接腳本文件的BOOTADDR=0x10000即可,即將整個鏡像文件都映射到RAM空間,但是bootloader最開始的搬運代碼必須是位置無關的代碼,這樣雖然搬運代碼被映射到RAM地址空間,但它在0x0開始的ROM中也能正確執行,搬運代碼最後的跳轉語句就可以跳轉到某個標號了,因爲此時標號的地址已經被映射到了ram空間,之後的代碼執行將沒有任何問題。

當然,可以將搬運代碼和搬運完成跳轉到的代碼分段映射,即搬運代碼映射到ROM地址空間,其他代碼映射到RAM空間。但是這樣會存在一個問題:生成的bin文件變得非常大。生成的bin文件將會按照映射到地址空間來生成,如果ROM空間與RAM空間地址不連續,假設ROM地址空間爲0x0 ~ 0x1000 , RAM地址空間爲0x10000~0x20000,那麼, 0x1000~0x10000之間的地址空間都被填充爲0,除非在生成bin文件時重新進行拼裝。

如何編寫位置無關代碼呢?

引用同一位置無關段或相對位置固定的另一位置無關段中的符號時,必須是基於PC的符號引用,即使用相對於當前PC的偏移量來實現跳轉或進行常量訪問。

1.位置無關的程序跳轉。使用相對跳轉指令實現程序跳轉。指令中所跳轉的目標地址用基於當前PC的偏移量來表示,與鏈接時分配給地址標號的絕對地址值無關,因而代碼可以在任何位置進行跳轉,實現位置無關性。

2.位置無關的常量訪問。在應用程序中,經常要讀寫相關寄存器以完成必要的硬件初始化。爲增強程序的可讀性,利用EQU僞指令對一些常量進行賦值,但在訪問過程中,必須實現位置無關性。

3. 使用絕對地址進行跳轉,一般是在不同的位置無關代碼段之間跳轉。

最後,總結一下位置無關代碼段的優點:

1.簡化設計,方便實現系統的快速引導。位置無關代碼可以避免在引導時進行地址映射,並方便地跳轉到RAM中實現快速引導

2.實現復位處理智能化。位置無關的代碼可以被加載到任意地址空間運行

3.便於調試。Bootloader的調試通常也是一個繁瑣的過程,使用位置無關代碼,則可以將映像文件加載到RAM中進行調試,這既能真實地反映程序從ROM中   進行系統引導的情況,又可以避免頻繁燒寫程序存儲器。

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