編譯鏈接淺析

概括、通過對編譯和鏈接的過程分析更加深刻的掌握程序運行的機制。

一、編譯

工程中的多個源文件經過預處理、詞法分析、語法分析、語義分析、彙編成多箇中間目標文件。

二、靜態鏈接

2.1、隨着工程量的增加不太可能用一個c文件實現整個工程的功能,需要把工程分成很多個模塊,再把模塊分解成很多個功能函數,一些具有相近功能的函數被放到一個c文件中。這樣一個工程中就可能含有很多個c文件,他們分別進行編譯,所以就需要把這些分別編譯所生成的中間目標文件進行鏈接生成可執行文件。較爲簡單的是靜態鏈接。

2.1、中間目標文件的結構是段式的結構,一般有代碼段,數據段,bss段等。中間目標文件的格式和可執行文件的格式幾乎一樣,只不過是中間目標文件中函數和全局變量的地址無法確定而已。

2.2、每個中間目標文件中的函數和全局變量的地址是無法確定的,所以在對應的代碼段中的地址函數地址對應-4,變量地址是0,我們需要在鏈接時對他們進行重定位。

2.3、重定位函數和全局變量的地址需要兩個步驟,第一步是確定整個工程中所有函數和全局變量的虛擬地址,這個步驟是通過計算整個程序中一共含有多少個段,每個段的大小,段對齊設置,以及函數和全局變量在段中的偏移來獲得。(代碼段和數據段等在特定的操作系統下被裝載到的虛擬地址的起始地址是固定的)

2.4、在獲得了所有的函數和全局變量的虛擬地址以後,就要對代碼段中的地址進行重定位,這是根據重定位表來的,重定位表就是需要重定位的地址和符號(函數和全局變量)的虛擬地址的索引表,這樣就可以實現地址的重定位。

三、動態鏈接

3.1、系統的庫函數等模塊被應用程序調用的機率非常之大,如果都採用靜態鏈接的話,每個可執行文件都含有相應的庫模塊的一個副本,無論是存儲時還是運行時都極大的浪費空間,而且如果庫文件版本升級的話就需要對整個工程進行編譯,這就需要採用動態鏈接的方式來解決此問題。

3.2、動態鏈接顧名思義就是在裝載時再確定模塊的地址,這種情況下,動態模塊的地址是隨機的可變的,因爲應用程序可能需要鏈接多個動態鏈接庫模塊,而隨機的動態鏈接的模塊地址帶來的問題就是動態鏈接模塊在不同的進程中是不一樣的(地址不一樣),這樣的話就無法實現動態鏈接庫代碼的共享,爲了使動態鏈接庫的代碼和數據的訪問不隨其被裝載的地址不同而不同就需要使用地址無關代碼技術。

3.3、對於模塊內部的函數調用和靜態變量的訪問是採用相對地址的方式來進行的,所以就不需要地址的重定位。

3.4、而對於模塊間的函數調用和全局變量的訪問是採用間接訪問的方式來進行的,也就是說訪問函數和全局變量的間接地址,而這個間接地址是不變的,間接地址裏的值就是函數和全局變量的真正地址是可變的。



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