「linux」linux進程管理方式之預編譯、編譯、鏈接

眾所周知進程是執行的二進制程序,而二進制需要預編譯、編譯、鏈接這幾個步驟。


跟我一起梳理一下預編譯、編譯、鏈接的作用吧

下圖是編譯成二進制文件的流程,這些步驟會生成一些列中間文件,統一稱為ELF(Executeable and Linkable Format)。下面一步一步解釋這張圖:

「linux」linux進程管理方式之預編譯、編譯、鏈接

1、預處理的作用

1.#define 宏文本替換

2.#include 遞歸展開頭文件

3.#if #endif #elif 刪除預編譯指令

4.刪除註釋

2、編譯的作用

進行詞法、語法、句法分析,產生彙編語言的程序,這一步也涉及代碼的優化。這一步生成了.o文件。這就是 ELF 的第一種類型,可重定位文件(Relocatable File)

這個文件的格式長這樣:

「linux」linux進程管理方式之預編譯、編譯、鏈接


- text:放編譯好的二進制可執行代碼
- .data:已經初始化好的全局變量
- .rodata:只讀數據,例如字符串常量、const 的變量
- .bss:未初始化全局變量,運行時會置 0
- .symtab:符號表,記錄的則是函數和變量
- .strtab:字符串表、字符串常量和變量名

「linux」linux進程管理方式之預編譯、編譯、鏈接

從名字來看,為什麼叫可重定位文件呢?


.o文件只是記錄了我要調用哪個函數,但是並不知道函數在哪定義,可重定位的意思是可以重新找到函數的位置,然後鏈接成可執行文件。


3、鏈接的作用

根據每個obj文件的信息尋找各obj文件之間的聯繫,並根據這種聯繫將所有的obj文件鏈接為一個整體,即最後的可執行文件exe或庫文件。

鏈接生成的二進制文件叫可執行文件,是 ELF 的第二種格式,如下圖:

「linux」linux進程管理方式之預編譯、編譯、鏈接


這個格式和.o 文件大致相似,還是分成一個個的 section(小長方形),並且被節頭表描述。只不過這些 section 是多個.o 文件合併過的。但是這個時候,這個文件已經是馬上就可以加載到內存裡面執行的文件了,因而這些 section 被分成了需要加載到內存裡面的代碼段、數據段和不需要加載到內存裡面的部分,將小的 section 合成了大的段 segment,並且在最前面加一個段頭表(Segment Header Table)。,這個要段裡含有 p_vaddr,這個是這個段加載到內存的虛擬地址。

4、動態鏈接庫
靜態鏈接庫一旦鏈接進去,代碼和變量的 section 都合併了,因而程序運行的時候,就不依賴於這個庫是否存在。但是這樣有一個缺點,就是相同的代碼段,如果被多個程序使用的話,在內存裡面就有多份,而且一旦靜態鏈接庫更新了,如果二進制執行文件不重新編譯,也不隨著更新。

因而就出現了另一種,動態鏈接庫(Shared Libraries),不僅僅是一組對象文件的簡單歸檔,而是多個對象文件的重新組合,可被多個程序共享。


當一個動態鏈接庫被鏈接到一個程序文件中的時候,最後的程序文件並不包括動態鏈接庫中的代碼,而僅僅包括對動態鏈接庫的引用,並且不保存動態鏈接庫的全路徑,僅僅保存動態鏈接庫的名稱。

當運行這個程序的時候,首先尋找動態鏈接庫,然後加載它。默認情況下,系統在 /lib 和 /usr/lib 文件夾下尋找動態鏈接庫。如果找不到就會報錯,我們可以設定 LD_LIBRARY_PATH 環境變量,程序運行時會在此環境變量指定的文件夾下尋找動態鏈接庫

動態鏈接庫,就是 ELF 的第三種類型,共享對象文件(Shared Object)。


分享到:


相關文章: