1. 程式人生 > >編譯與連結(二)——靜態連結

編譯與連結(二)——靜態連結

         連線通過編譯過程,一個原始檔(.c)就生成了一個對應的目標檔案(.o)。一個工程,不可能是一個檔案組成,從幾十個到幾百個,大的專案工程有成千上完個檔案,這些檔案通過編譯,只是從原始檔變成了目標檔案,但是這些檔案不能單獨執行,各個檔案(模組)之間存在一定的關係,要使工程正常工作,各個目標檔案和庫必須連線在一起,形成一個最終的可執行的檔案。下面就詳細介紹連結工作的過程。連結過程簡單描述連結過程分為靜態連結和動態連結,動態連結以後將詳細介紹,本文主要介紹靜態連結過程。從原始檔到可執行檔案的過程如圖1表示:

把各個目標檔案看成一個個的積木,連結過程就是拼積木的過程。模組之間如何組合的問題可以歸結為模組之間如何通訊的問題,最常見的通訊方式有兩種:一種是模組之間的函式呼叫,另一種是模組之間的變數訪問。連結的主要內容就是把各個模組之間相互引用的部分都處理好,使得各個模組之間能夠正確地銜接。從原理上講,連結的工作無非就是把一些指令對其他符號地址的引用加以修正。符號是用來表示一個地址的,這個地址可以是一段子程式(

函式)的起始地址,也可以是一個變數的起始地址,也就是函式名和變數都可以看做一個符號。

除了目標檔案,連結過程還有庫檔案,最常見的庫就是執行時庫,它是支援執行程式的基本函式集合。連結過程主要包括了地址和空間分配,符號決議和重定位。

地址和空間分配過程實際在編譯的最後一步:從彙編檔案編譯成目標檔案過程已經完成了一部分,各個目標檔案模組內部的變數、函式以本檔案為基準分配地址,即檔案內的偏移地址。除了引用的外部符號,模組內的符號都有明確的地址。編譯器也會根據變數的型別為其分配相應的空間。連結過程的地址和空間分配,可以看做是從目標檔案到可執行檔案對映過程,目標檔案的地址在可執行檔案中應該是怎樣的地址;目標檔案沒有確定地址的外部符號在可執行檔案中確定了下來。

符號決議也叫符號繫結、名稱繫結、名稱決議,甚至還有叫做地址繫結、指令繫結的。決議和繫結有細微的差別,決議傾向於靜態連結,繫結更傾向於動態連結。

重定位的過程,主要是對外部符號的地址進行重定位,各個目標檔案和庫檔案的外部符號在連結之前地址沒有確定,編譯過程把外部符號的地址暫時擱置,連結過程才確定下外部符號的地址,並在執行檔案中儲存。

以簡單的例子講述連結過程。例如兩個模組main.cfunc.cmain.c中要使用func.c中的函式foo(),main.c模組中每一處呼叫foo的時候都要知道foo這個符號的地址,但是模組單獨編譯,編譯main.c的時候不知道foo的地址,編譯器暫時擱置,到連結時再去確定。聯結器在連結的時候會根據所引用的符號foo

,自動去相應的func.o模組中查詢foo的地址,然後將main.o模組中所有引用到foo的指令重新修正,是得獲取真正的foo函式的地址。

連結過程詳細描述。

上面簡單描述了連結過程,真正要了解連結過程,需要知道目標檔案的格式——目標檔案到底有哪些東西。

目標檔案從結構上講,它已經是編譯後的可執行檔案格式,是按照可執行檔案格式(ELF)儲存的。ELF檔案的開頭是一個“檔案頭”,檔案頭描述了整個檔案的屬性,包括1 是否可執行,2是靜態連結還是動態連結,3入口地址,4目標硬體,5目標作業系統和6段表偏移等資訊。段表描述了檔案中各個段在檔案中的偏移位置及段的屬性。檔案頭後面就是各個段的內容。圖2更直觀的描述ELF檔案的格式。

對於連結器來說,整個連結過程中,就是將幾個輸入目標檔案加工合併成一個輸出檔案。上面提到的連結有三個步驟:空間與地址分配、符號決議和重定位。

空間地址分配可以分為兩種,按序疊加和相似段合併。按序疊加十分簡單,就是將所有的目標檔案按照順序依次疊加到一起成為一個輸出檔案。輸出檔案的段數等於所有檔案段數的總和。這種方法得到的最後輸出檔案可能有成千上萬個段,每個段由於地址和空間對齊的需要,造成很多記憶體碎片,十分浪費空間。如圖3表示:

相似段合併是將性質相同的段合併到一起,這種方法可以有效的避免記憶體碎片的問題,節省空間,如圖4所示。地址和空間分配,包含第一輸出的可執行檔案中的空間,第二是裝載後的虛擬地址中的虛擬地址空間。連結過程一般採用兩步連結的方法。

第一步空間與地址分配,掃描所有的輸入檔案,獲得它們的各個段的長度、屬性和位置,並將輸入目標檔案中的符號表中所有的符號定義和符號引用收集起來,統一放到一個全域性符號表。連結器將能夠獲得所有輸入檔案的段長度,並且將它們合併,計算出輸出檔案中各個段合併後的長度與位置,並建立對映關係。

第二步 符號解析與重定位,使用第一步收集到的所有資訊,讀取輸入檔案中段的資料、重定位資訊,並且進行符號解析與重定位 、調整程式碼中的地址等。該步驟是連結過程的核心,特別是重定位過程。

上面主要講述了靜態連結過程。動態連結以後的文章介紹。