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

ELF 格式(Executable and Linkable Format)

/ elf, like the storybook elf /

當編譯器把你的程式碼變成完成的程式時,它不能只是把原始的機器指令傾倒進一個檔案,然後期望作業系統知道該怎麼辦。這些位元組需要一個容器:一種已知的版面配置,說明程式碼在哪裡、已初始化的資料在哪裡、程式定義或需要哪些符號,以及如何修正位址。在 Linux 與大多數類 Unix 系統上,這個容器格式叫做 ELF。同一個格式用於目的檔(編譯器產生的 .o 檔)、用於完成的可執行檔,也用於共享函式庫(.so 檔)。

ELF 檔案總是以一個固定大小的 ELF 標頭開頭,標頭起始是四個魔術位元組 0x7f 'E' 'L' 'F'(常寫成 0x7f 0x45 0x4c 0x46)。從這個標頭可以找到兩張表。節區標頭表(section header table)把檔案描述成一組具名的節區(.text 放程式碼、.data 放已初始化資料、.symtab 放符號表等等)——這是連結器在意的視角。程式標頭表(program header table)把檔案描述成一組區段(segment),告訴載入器要把檔案的哪些範圍映射進記憶體、以及用什麼權限。一個實體檔案,兩種切法:節區供連結、區段供載入。

ELF 之所以重要,是因為它是編譯器、連結器、動態連結器與核心對一個程式所共用的唯一通用語言。你可以用 readelf 或 objdump 檢視任何 ELF 檔,看清裡面究竟有什麼。一個常見的誤解是:ELF 可執行檔內含一整塊扁平的程式碼——實際上它是一個有結構的封存檔,各部分都被排好版、命名並彼此交叉參照,而這正是分離編譯與動態連結之所以可能的原因。

$ readelf -h ./a.out Magic: 7f 45 4c 46 02 01 01 00 ... Class: ELF64 Type: DYN (Position-Independent Executable) Entry point address: 0x1060

前幾個位元組 7f 45 4c 46 就是 ELF 魔術數字;標頭接著說明類別(64 位元)、檔案型別,以及執行從哪裡開始。

ELF 是 Linux/Unix 的格式;Windows 用 PE/COFF,macOS 用 Mach-O。位元組無法互換,但底層概念——標頭、節區、符號、重定位——到處都一樣。

又称
Executable and Linkable FormatELF 檔可執行與可連結格式