關於編譯連接階段指定連接地址的做用

首先,記住一句話:程序的連接地址必須等於運行地址!學習

在學習exynos 4412的啓動過程時,發現本身對連接地址的做用不是很瞭解,因而上網查找了資料作了基本瞭解,在此作個總結。spa

上圖是exynos 4412啓動時iROM、BL1和BL2在iRAM中的分佈狀況。由圖中能夠看出,BL2會被加載到0x020_3400的起始地址處(由BL1加載),照理來講,在BL2代碼編譯連接過程當中應該將連接地址指定到0x0202_3400纔是正確的,可是在實際作led實驗(此處BL2的代碼功能便是按鍵控制led亮滅)過程當中發現,將連接地址指定爲0x0202_0000也照常運行。如下爲連接腳本的內容:blog

SECTIONS
{
. = 0x02020000;  #注:此處正確的連接地址應該爲0x0202_3400
.text : { *(.text) }
.rodata ALIGN(4) : {*(.rodata*)}
.data ALIGN(4) : { *(.data*) }
.bss ALIGN(4) : { *(.bss) *(COMMON) }
}內存

要想明白緣由,就得理解連接地址的做用。編譯

先看連接器的做用:遍歷

  當連接器進行連接的時候,首先決定各個目標文件在最終可執行文件裏的位置。而後訪問全部目標文件的地址重定義表,對其中記錄的地址進行重定向   (加上一個偏移量,即該編譯單元在可執行文件上的起始地址)。而後遍歷全部目標文件的未解決符號表,而且在全部的導出符號表裏查找匹配的符號,   並在未解決符號表中所記錄的位置上填寫實現地址。最後把全部的目標文件的內容寫在各自的位置上,再做一些另的工做,就生成一個可執行文件。程序

在上述連接腳本中指定的連接地址,便是告訴連接器將程序的起始地址設置爲0x0202_0000,由此,連接器會根據這個設定的起始地址設定程序中位置相關代碼的地址。假設連接地址是0x0202_0000,而程序的起始地址實際是在0x0202_3400,當運行位置無關代碼時(即要跳轉的運行地址爲當前PC的值加上一個相對偏移量),CPU能夠正確找到程序的存放位置,所以運行不會出錯。可是若是存在位置相關代碼(即連接時指定好的固定具體地址,非當前PC值加相對偏移量得到的相對地址),那麼當CPU跳轉到對應的運行地址處運行時,因爲實際的代碼存放地址運行地址(運行地址由連接時根據連接地址計算獲得不一樣,那麼運行就會出錯了。im

舉個例子:假設當將連接地址指定爲0x0202_0000,由今生成的可執行程序中有條位置相關代碼是 goto 0x0202_1000 ,而實際可執行程序存放在0x0202_3400的起始地址處,那麼實際 goto 0x0202_1000 對應的代碼就不在0x0202_1000處了,而CPU經過執行 goto 0x0202_1000 跳轉到0x0202_1000處,到那裏去運行代碼,卻找不到對應的代碼,所以程序運行就出錯了。總結

若是連接地址與程序在內存中的實際存放起始地址不一樣,當沒有位置相關代碼時程序運行不會出錯,這就是前面說的led程序能夠正常運行的緣由。可是若是程序中有位置相關代碼,那麼當運行到位置相關代碼時,便會發生錯誤。腳本

所以,程序的連接地址必須等於運行地址。

相關文章
相關標籤/搜索