天天看點

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

這幾天看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代碼翻譯成為彙編指令),彙編(将彙編代碼翻譯成機器指令,也叫可重定位目标檔案),

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

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

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

連結過程中會把多個檔案的相同類型資料段代碼段放在一起,是以需要将裡面的符号變量重新安置在一個确定的記憶體位址中,這就是重定位,