編譯—連結—載入工具鏈

可執行檔格式(ELF、Mach-O、PE)

/ ELF; MACK-oh; P-E /

可執行檔不是處理器從第一個位元組開始讀的原始機器碼傾印。它是一個有嚴格佈局的結構化檔案:前面有標頭、一份目錄,然後是排列在具名區段裡的程式碼與資料。可執行檔格式就是那個檔案約定好的形狀,是連結器(寫它的一方)與載入器(讀它的一方)都遵循的規則書,好讓它們能彼此理解。沒有共同的格式,載入器就不知道哪些位元組是程式碼、哪些是資料、或該從哪裡開始執行。

有三種格式主導,每個主要平台一種,它們以不同方言描述同樣的概念。ELF(Executable and Linkable Format)用於 Linux 與多數 Unix 系統。Mach-O 用於 macOS 與其他蘋果系統。PE(Portable Executable)用於 Windows(熟悉的 .exe 與 .dll 檔案)。每一種都以一個含有魔術數字的標頭開頭,那是幾個一眼就能辨識格式的位元組,後面接著載入器所需的資訊:開始執行的進入點位址、各區段或段的清單以及每一個該被放進記憶體何處、每個區域需要什麼權限(可讀、可寫、可執行),以及必須一併載入哪些共享函式庫。

這就是為什麼為某個作業系統建構的程式不會就這樣在另一個作業系統上執行的主要原因,即使在同一個處理器上:Linux 的 ELF 二進位檔與 Windows 的 PE 二進位檔包裝的是同一種機器指令,但外圍的格式與它們期望的作業系統服務完全不同。你通常從不直接讀這些檔案,但像 readelf 與 objdump(用於 ELF)、otool(用於 Mach-O)、dumpbin(用於 PE)這類工具能讓你檢視標頭與區段,使完成品程式原本看不見的結構變得具體。

$ readelf -h app # 讀取 ELF 標頭 Magic: 7f 45 4c 46 ... # 位元組 0x7f 'E' 'L' 'F' -> 這是一個 ELF 檔 Type: EXEC (Executable file) Entry point address: 0x401050 # 載入器跳去開始執行的位置

標頭的魔術數字辨識格式,而進入點告訴載入器從哪裡開始。

相同的機器指令,不同的包裝:Linux 的 ELF 與 Windows 的 PE 裝著相近的程式碼,但它們假設的格式與作業系統服務不同,所以其中一個無法不經修改就在另一個上執行。

又稱
binary formatobject file format可執行檔格式