加載地址和運行時地址 & 代碼重定位 (2020)

2018年曾經寫過該內容,2020年回顧了一下,發現之前所述有些謬誤,加上排版有些問題,因此這裏就再開一篇再做一次記錄,也當是自己這些年的成長對比了。(該主題是對鏈接腳本中所用到的地址結合實際使用中的一些概念得出,鏈接腳本內容可以參考 http://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html#IDX237 )

2018的標題爲編譯地址和運行地址,這裏更加準確的應該爲加載地址運行時地址(或重定位地址),還需要引入一個存儲地址

首選需要知道的是裸機運行的程序需要存儲在存儲器中,可以是NorFlash或者NandFlash及各種可以掉電保存的靜態存儲器,當程序讀取存儲器保存的程序進行解碼執行時,程序就啓動了,一般裸板程序都是從0地址開始取代碼,而我們的程序也自然地需要從存儲器0地址開始存儲,這裏的0就是程序的存儲地址,存儲地址僅跟對存儲器的寫有關,可以任意確定,你也可以把程序寫到存儲器的中間位置,當然這樣仍需要0地址處存在引導程序,因此爲了裸板程序能夠正常運行,我們將程序保存到0地址處。

但是程序運行起來之後,因爲各種原因不能在原來的存儲地址處運行,這裏的原因可能是:

1.我們用的存儲器是NorFlash只讀存儲器(僅針對運行時而言,NorFlash使用芯片手冊提供命令也可寫),這會導致程序中用到的全局變量或者靜態局部變量等data和bss段數據都無法被修改,從而影響到程序的邏輯。

2.使用的是NandFlash,以S3C2440芯片爲例,使用NandFlash作爲boot Flash時,2440存在機制將NandFlash中的前4K內容複製到片內SRAM中,SRAM作爲0地址運行程序,此時如果我們的程序超過4K大小,將會導致程序無法運行。

正是因爲上述的原因存在,所以我們需要將程序重定位到一片可用的內存上,一般爲SDRAM,這裏假設SDRAM的base address爲0x3000,則我們程序需要通過一種機制,使得程序在運行之後在0x3000地址處運行,這種機制就叫做代碼重定位,0x3000爲程序的運行時地址

運行時地址是程序運行的地址,不管程序存儲在哪裏,以什麼地址開始運行,程序都會認爲自己在運行時地址處運行中,所有全局變量和靜態局部變量等data段或者bss段數據都以運行時地址編址進行訪問,如一個全局變量a,運行時地址爲0x301F,所有需要使用到該變量的代碼都會到0x301F這個地址去訪問取值或者賦值,此時就出現一個問題,我們的程序存儲在0地址處,未重定位前,0x3000及往後地址數據都是未知的,這時候去0x301F取值是未定義行爲。同樣如果存在一個函數functionA,他的運行時地址是0x321F,可能他的存儲地址在0x11FF,但是未定位前使用絕對跳轉指令跳轉到運行時地址也是未定義行爲。

簡單來說就是程序存儲在0地址爲起始的地方,程序運行起來是在0地址開始運行,但是程序自己覺得(實際上編譯時也確定了各個指令的地址,反彙編即可看到)已經在0x3000這一運行時地址處運行了,因此對全局變量的訪問也是通過運行時地址進行訪問,如果直接使用會出現問題。程序之所以能夠正常運行,是因爲使用了位置無關碼,進行了相對跳轉,如果使用的是絕對跳轉,直接跳轉也是會有問題。

代碼重定位就是在運行時地址處相應區域填充代碼和數據,這個是編譯時已經確定好的,存儲地址處有所有需要的“原材料”。一般代碼重定位包含1.將程序從存儲地址 我複製我自己 到運行時地址中 ;2.清除bss段 等。

最後是加載地址,對於裸板程序而言,編譯輸出的bin文件結構與NorFlash 0地址處存放的結構一樣,而加載地址即存儲地址處結構的相對位置地址,這也影響着bin文件的大小,一般可以緊湊着排放,重定位到運行時地址時再從對應的加載地址中複製數據到運行時地址處。

發現兩年過去自己的描述能力仍舊沒什麼進步,思緒萬千落實到文字全部變了樣,還是附上圖希望有些幫助把。

下圖採用鏈接腳本描述一個文件最終的內存分佈。

如圖中假設我們的代碼段加載地址爲0,數據段加載地址爲0x80,而運行時地址分別爲0x3000和0x31FF,同時假設代碼段長度爲0x80,則加載後代碼段和數據段緊挨着,bin的大小也爲段大小的總和沒有空洞,存儲到0地址NorFlash時(這裏並非加載地址爲0,存儲地址就爲0,存儲地址是我們自己確定的,想存哪裏存哪裏,加載地址只是一個相對的結構,只是統一會簡化代碼工作量,爲0則是芯片運行要求),如下:

 通過上圖可以清晰看到重定位所做的事情以及加載地址運行時地址的情況。

受表達能力所限,有些未能很好的描述清楚,如有疑問歡迎提出,也歡迎交流討論指出不正確指出。不忘初心 。

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