一.幾個重要的基本概念函數
連接:連接是將各類代碼和數據部分收集起來並組合成爲一個單一文件的過程,這個文件能夠被加載到存儲器中並執行。工具
編譯器驅動程序:編譯的過程能夠分爲如下幾個步驟:1.語言預處理器 2.編譯器 3.彙編器 4.連接器編碼
靜態連接:以一組可重定位目標文件和命令行參數做爲輸入,生成一個徹底連接的能夠加載和運行的可執行目標文件做爲輸出。輸入的可定位目標文件,包含二進制代碼和數據,其形式能夠在編譯時與其餘可重定位目標文件合併起來,建立一個可執行目標文件。spa
目標文件:1.可重定位目標文件 2.可執行目標文件 3.共享目標文件命令行
可重定位目標文件:一個典型的ELF可重定位目標文件格式,翻譯
ELFdebug |
.text進程 |
.rodataci |
.data字符串 |
.bbs |
.symtab |
.rel.text |
.debug |
.line |
.strtab |
節頭部表 |
符號和符號表:
每一個可重定位目標模塊m都有一個模塊表,它表示m所定義和引用的符號的信息,在連接的上下文中,有三種不一樣的符號:
1.由m定義並能被其餘模塊引用的全局符號2.由其餘模塊定義並能被模塊m引用的全局符號 3.只能被模塊m定義和引用的本地符號
二.重要的幾個過程
靜態庫連接:
在符號解析的階段,連接器從左到右按照它們在編譯器驅動程序命令行上出現的相同順序來掃描可重定位目標文件和存檔文件。(驅動程序自動將命令行中全部的.c文件翻譯成.o文件),在此次掃描中,連接器維持一個可重定位目標文件的集合E(這個集合中的文件會被合併起來造成可執行文件),一個未解析的符號(即引用了可是還沒有定義的符號)集合U,以及一個在前面輸入文件中已定義的符號集D,初始時,E、U和D都是空的。
重定位:
一旦連接器完成了符號解析這一步,它就把代碼中的每個符號引用和一個肯定的符號定義(跟它的一個輸入目標模塊中的一個符號表條目)聯繫起來,在這時,連接器就知道它的輸入目標模塊中的代碼節和數據節的確切大小,如今就能夠開始重定位了,在這個步驟中,將合併輸入模塊,併爲每一個符號分配運行時地址。重定位包括兩個步驟:1.重定位節和符號定義 2.重定義節中的符號引用
動態連接共享庫:共享庫是以兩種不一樣方式來「共享」的,首先在任何給定的文件系統中,對於一個庫只有一個.so文件,全部引用該庫的可執行目標文件共享這個.so文件中的代碼和數據,而不是像靜態庫的內容那樣被拷貝和嵌入到引用它們的可執行文件中,其次,在存儲器中,一個共享的.text節的一個副本能夠被不一樣正在運行的進程共享。
從應用程序中加載和連接共享庫:應用程序還有可能在它運行時要求動態連接器加載和連接任意共享庫,而無需在編譯時連接到那些庫到應用中。
處理目標文件的一些工具:
AR:建立靜態庫,插入、刪除、列出和提交成員
STRINGS:列出一個目標文件中全部可打印的字符串,
STRIP:從目標文件中刪除符號表信息
NM:列出一個目標文件的符號表中定義的符號
SIZE:列出目標文件中的節的名字和大小
READELF:顯出一個目標文件的完整結構,包括ELF頭中的編碼全部信息,包含SIZE和NM的功能
OBJDUMP:全部二進制工具之母,可以顯示一個目標文件中全部的信息,它最大的做用是反彙編.text中的二進制指令。
三.小結
連接能夠在編譯時由靜態編譯器來完成,也能夠在加載時和運行時由動態連接器來完成。連接器處理成爲目標文件的二進制文件,它有三種不一樣的形式:可重定位的、可執行的和共享的。可重定位的目標文件由靜態連接器合併成爲一個可執行的目標文件,它能夠加載到存儲器中並執行。共享目標文件(共享庫)是在運行時由動態連接器連接和加載的,或者隱含地在調用程序被加載和開始執行時,或者根據須要在程序調用dlopen庫的函數時。連接器的兩個主要任務是符號解析和重定位,符號解析將目標文件中的每一個全局符號都綁定到一個惟一的定義,而重定位肯定每一個符號的最終存儲地址,並修改對那些目標的引用。