本章主要內容:數據結構
連接——靜態連接、動態連接(連接又包括兩個主要任務:符號解析和重定位)
符號——全局符號和本地符號、符號表、符號解析
連接文件的建立及引用——gcc、ar rcs、sharedj及fPIC命令參數
重定位——重定位條目、重定位符號引用(PC相對引用和絕對引用)
目標文件——可重定位目標文件(其中又詳細介紹了ELF可重定位文件的結構及格式)、可執行目標文件、共享目標文件
連接(linking)是將各類代碼和數據部分收集起來並組合成爲一個單一文件的過程,這個文件可被加載(或被拷貝)到存儲器並執行。
連接能夠執行於編譯時,即源代碼被翻譯成機器代碼時;也可執行於加載時,即在程序被加載器加載到存儲器並執行時;甚至執行於運行時,由應用程序來執行。
大多數編譯系統提供編譯器驅動程序(compiler driver),它表明用戶在須要時調用語言預處理器、編譯器、彙編器和連接器。函數
GNU編譯系統編譯源碼:工具
Unix的靜態連接器(static linker)ld,以一組可重位目標文件和命令行參數做爲輸入,生成一個徹底連接的能夠加載和運行的可執行目標文件做爲輸出。輸入的可重定位目標文件由各類不一樣的代碼和數據節(section)組成。指令在一個節中,初始化的全局變量在另外一個節中,而未初始化的變量又在另一個節中。編碼
爲了構造可執行文件,連接器必須完成兩個主要任務:spa
目標文件有三種形式:可重定位目標文件。能夠在編譯時與其它可重定位目標文件合併起來,建立一個可執行目標文件。操作系統
編譯器和彙編器生成可重定位目標文件(包括共享目標文件)。連接器生成可執行目標文件。
現代Unix系統使用可執行和可連接格式(ELF)。
可重定位目標文件命令行
一個典型的可重定位目標文件包含下面幾個節:
.text:已編譯程序的機器代碼。
.rodata:只讀數據。
.data:已初始化的全局C變量。局部C變量在運行時保存在棧中,既不出如今.data節中,也不出如今.bss節中。
.bss:未初始化的全局C變量。翻譯
每一個可重定位目標模塊m都有一個符號表,它包含m所定義和引用的符號的信息。3d
弱符號:未初始化的全局變量code
規則:
規則1:不容許有多個強符號。 規則2:若是有一個強符號和多個弱符號,那麼選擇強符號。 規則3:若是有多個弱符號,那麼從這些弱符號中任意選擇一個。
全部的編譯系統都提供一種機制,將全部相關的目標模塊打包成爲一個單獨的文件,稱爲靜態庫(Linux下是存檔文件,Windows下是lib),能夠用作連接器的輸入。
C程序開始時是一組ASCII文本文件,已經被轉化爲一個二進制文件,且這個二進制文件包含加載程序到存儲器並運行它所需的全部信息。
段頭部表:可執行文件的連續片被映射到連續的存儲器段,段頭部表描述了這種關係。
加載器將可執行目標文件中的執行代碼和數據從磁盤拷貝到存儲器中,而後經過跳轉到程序的第一條指令或入口點來運行該程序。這個將程序拷貝到存儲器並運行的過程叫作加載。
用戶棧老是最大的合法用戶地址開始,向下增加的(向低存儲器地址方向增加)。從棧的上部開始的段是爲操做系統駐留存儲器的部分(也就是內核)的代碼和數據保留的。
接下來,加載器跳轉到程序的入口點,也就是符號_start的地址。在_start地址處的啓動代碼(startup code)是在目標文件ctrl.o中定義的,對全部的C程序都是同樣的。
編譯庫代碼,使得不須要連接器修改庫代碼就能夠在任何地址加載和執行這些代碼。
-fPIC
選項指示GNU生成PIC代碼