連結器、載入器與目的檔格式

Mach-O 與 PE/COFF

/ mock-OH; pee-ee, coff rhymes with cough /

ELF 是 Linux 上的二進位容器,但它不是唯一的。如果你在 Mac 上寫程式,編譯器產生 Mach-O 檔;如果你在 Windows 上建構,得到的是 PE/COFF 檔。它們外表不同——魔術數字不同、欄位名稱不同、工具不同——但它們回答的是與 ELF 相同的問題:程式碼在哪、資料在哪、定義或需要哪些符號、位址如何被修正。

Mach-O(macOS 與 iOS 所用的格式)以一個魔術數字開頭,例如 0xfeedface(32 位元)或 0xfeedfacf(64 位元),接著是一連串的載入命令(load command)。每個載入命令告訴載入器一件具體的事:映射這個區段、這是符號表、這是要用的動態連結器(dyld)。ELF 是節區被分組到區段裡,Mach-O 則是區段(像 __TEXT 與 __DATA)各自包含節區(像 __text 與 __data)——注意雙底線命名。PE/COFF(Portable Executable,建立在較舊的 COFF 之上)是 Windows 的世界:檔案以舊的 DOS 'MZ' 標頭開頭,它指向一個 'PE' 簽章,之後 COFF 節區標頭描述 .text、.data、.rdata,以及一張匯入表(import table),列出程式需要的 DLL 與函式,由 Windows 載入器解析。

為什麼要認識這三種?因為觀念是可移轉的。一旦你以 ELF 的詞彙理解了節區、區段、符號表、重定位與動態連結器,你就能讀任何一種格式——詞彙變了,但機制沒變。一個常見錯誤是以為工具或 .o 檔可跨作業系統移植:它不行,因為容器在位元組層級就不同。C 原始碼可移植;連結後的二進位檔則綁定於單一格式。

每種格式開頭的魔術數字: ELF : 7f 45 4c 46 (\x7fELF) Mach-O : cf fa ed fe (0xfeedfacf,64 位元,位元組互換後) PE/COFF : 4d 5a ... 50 45 ('MZ' ... 'PE')

三個作業系統、三種容器、三個魔術數字——但每一個都裝著程式碼、資料、符號與重定位。

在 Linux 上建構的 .o 或 .so 無法在 macOS 或 Windows 上載入,反之亦然;只有原始碼可移植,連結後的物件不行。但觀念能乾淨地對應到三者之間。

又称
Mach objectPortable ExecutableCommon Object File FormatWindows 與 macOS 的執行檔格式