將各種**段和資料段收集組合成為乙個單一檔案的過程。
鏈結器的出現使得構建大型軟體系統成為可能,因為它使得各個模組可以單獨完成編譯。當需要改進模組時,單獨的修改相應的模組並編譯,通過鏈結器重新鏈結生成新版本的軟體系統。
sum.cpp中定義乙個函式
int sum(int a,int b)
main.cpp中宣告並使用
int sum(int,int);
int main()
編譯系統通常包含預處理器、編譯器、彙編器、鏈結器。通過這些不同部分完成程式從源**到最終可執行程式的過程。
gnu編譯系統對上述程式的過程為:
g++ main.cpp sum.cpp -o prog
①符號解析:symbol resolution 目標檔案中定義和引用符號。每個符號可能對應於乙個函式、乙個全域性變數、或者乙個靜態變數(區域性變數在執行時棧中建立) 符號解析就是將符號引用與符號定義關聯起來。
②重定位:relocation 編譯器和彙編器生成的位址是從0開始的邏輯位址。鏈結器通過把每個符號定義與記憶體中乙個位置關聯起來,從而重定位這些部分。具體做法是使用彙編器產生的重定位條目資訊執行重定位。
目標檔案存在三種類別:
【目標檔案格式】
目標檔案是對程式二進位制**和資料的組織,貝爾實驗室第乙個unix系統使用a.out格式,windows使用可移植可執行的pe格式(如最常見的可執行程式.exe格式) 而linux中使用的是elf (executable and linkable format)格式。
目標檔案通常包含以下這些節:
.text
程式的機器**
.rodata
read only data 唯讀資料,如printf 中格式串
.data
已經初始化的全域性或靜態變數(區域性變數執行期建立在棧中)
.bss
未初始化的全域性或靜態變數,不佔據實際空間,僅僅為乙個佔位符
.symtab
符號表:存放程式中定義和引用的函式和全域性(靜態)變數資訊
.rel.text
對應與.text中位置的列表,呼叫外部函式或者引用全域性變數時修改
.rel.data
被模組引用或者定義的所有全域性變數的重定位資訊
objdump -x add.o linux中採取objdump才看elf目標檔案資訊
可以看到目標檔案中,主要包含**段、資料段等節,同時以及最重要的符號表(symbol_tab)
自定義函式 add_funii (已經被編譯期重新修改函式名 典型的加上i i 對應引數描述) 在符號表最後乙個。
【符號與符號表】
符號表包含所在可重定位模組定義和引用的符號的資訊,通常包含三種不同的符號:
類別對應於源程式
全域性符號:由本模組定義,能被其它模組引用的符號
對應於c++源**中定義的全域性變數和函式
區域性符號:由本模組定義,但不能被其它模組引用的符號
對應於c++源**中定義的本檔案可見的static 變數和函式
外部符號:由其它模組定義並被本模組引用的全域性符號
本檔案宣告使用,在其它原始檔定義的全域性變數和函式
注意:符號表中不包含任何區域性非靜態變數的任何符號,這是因為這些區域性變數都是在執行時棧中建立和銷毀。
因此,static關鍵字最重要的用途:使得被修飾的函式或變數只能在本模組(檔案)中可見。
目標檔案格式
unix 最早的可執行檔案格式為a.out格式,它的設計非常的簡單,以至於後來共享庫這個概念出現的時候,a.out格式就變得捉襟見肘 於是人們設計了coff格式來解決這個問題,coff是由unix system v release 3首先提出並使用的格式規範,後來微軟公司基於coff格式,制定了pe...
目標檔案格式
在linux 0.12 系統中,gnu gcc 或gas 編譯輸出的目標模組檔案和鏈結程式生成的可執行檔案都使用了unix傳統的a.out格式。這是一種被稱為彙編與鏈結輸出 assembly linker editor output 的目標檔案格式。對於具有記憶體分頁機制的系統來說,這是一種簡單有效...
目標檔案格式
程式從原始碼編譯為目標 的時候,這個目標檔案的格式是怎麼樣的?elf目標檔案有 段,資料段和bss段。elf目標檔案的標頭檔案,段表,重定位表,字串表,符號表,除錯表。無論是可執行檔案,目標檔案或庫,它們實際上都是一樣基於段的檔案或是基於這種檔案的集合。程式的源 經過編譯後,按照 和資料分別存放到相...