1. 程式人生 > >編譯連結中的-可重定位目標檔案

編譯連結中的-可重定位目標檔案

這幾天看linux程式設計,發現很多專有名詞,

可重定位目標檔案理解

資料一:

彙編器所產生的目標檔案至少包括三個區,即文字區(text),資料區(data)和bss區。文字區一般包括程式的程式碼和常量,資料區通常存放全域性變數等內容,bss區用於存放未初始化的變數或作為公共變數儲存空間。在一個目標檔案中,其text區從地址0開始,隨後是data區,再後面是bss區。而要執行程式,必須裝載到記憶體中,所以這些區的地址需要在記憶體中重新安排,也就是重定位。

資料二:

編譯器編譯後產生的目標檔案是可重定位的程式模組,並不能直接執行,連結就是把目標檔案和其他分別進行編譯生成的程式模組(如果有的話)及系統提供的標準庫函式連線在一起,生成可執行的可執行檔案的過程。


重定位是連結器在完成符號解析後(知道了各個輸入模組的程式碼段和資料段的大小)的一個步驟,其作用顧名思義就是重新定位,確定比如指令,全域性變數等在執行時的儲存器地址。       

資料三:

比如說兩個編譯後的可重定位目標檔案obj1.o和obj2.o
在obj1.o裡面定義了一個全域性變數glob(在obj1裡面記錄了glob相對於該檔案資料段的相對地址), 而obj2.0裡面又引用了這個全域性變數glob。
連結的重定位就是要確定在連結後的可執行程式中glob的地址,而不是相對於obj1的地址,從而使obj2也能通過地址呼叫glob。

當然重定位並不只是全域性變數,還包括外部函式,指令等執行時地址的確定


資料四:

當你在程式中寫上一個全域性變數或者是一個函式時,這個定位過程會經歷幾個階段:
1.在這個目標檔案中的相對定位,一個目標檔案中會此檔案中的所有函式,變數進行符號描述,比如一個變數A,它所佔的相對地址是多少?是全域性的?或者是靜態的,或者是外部的??
2.在連線多個目標成一個可執行檔案時,會再次對這個變數進行重定位,也就是在這個可執行檔案中進行對此變數進行描述,同目標檔案中的描述差不多,只不過此變數不再有外部,內部之分,都成了本地變數,並且會將所有全域性變數存放在一定的邏輯地址中,這是通過連線指令碼檔案與各個目標檔案中的相對地址共同決定的
3.最終的作業系統載入這個可執行檔案時,會對這些變數與函式地址再次進行重定位,其方式就是首先分析這個可執行檔案中的不同段,讀出相應的描述表,然後通過邏輯地址與實體地址進行映射出,最終就將可執行的二進位制碼加進了真實的實體記憶體了,關於分析可執行檔案格式與實體地址的轉換,不同的CPU與作業系統的實現方式會有不同之處


綜上一些資料,自己有了一個大概的理解,畢竟沒學過編譯原理這方面,只能有個感性的認識,

編譯器把程式碼檔案編譯處理為一個可執行的二進位制檔案,在window上字尾為exe的可執行檔案,linux上生成的可執行檔案沒有後綴來標示,

比如,從一個c原始碼檔案變成一個可執行檔案,這期間編譯器做了很多事情

這些事情依次是:預處理(巨集展開等),編譯(將c程式碼翻譯成為彙編指令),彙編(將彙編程式碼翻譯成機器指令,也叫可重定位目標檔案),

連結(連結由彙編產生的目標檔案)。關於這幾個事情具體詳細的起到了什麼作用,可參閱博主其他文章或谷歌一下,你全知道!

經過彙編後的目標檔案可以被連結成為二進位制可執行檔案。主題來了,連結做了什麼?

請看上面的資料三,把多個檔案連結成為一個檔案,之前的各個檔案中的 符號,變數在記憶體中的地址是相對的,

連結過程中會把多個檔案的相同型別資料段程式碼段放在一起,所以需要將裡面的符號變數重新安置在一個確定的記憶體地址中,這就是重定位,