可執行檔(executable)
當你編譯一個 C 程式,你會得到一個能直接啟動、讓程式跑起來的單一檔案。那個檔案就是可執行檔:一個自成一體的包裹,內含機器碼,加上作業系統把它載入記憶體並啟動所需的那些資訊。它是程式「就緒可跑」的形態,相對於你寫的那份原始碼文字。
可執行檔不只是機器碼的原始傾印。它是一個有特定格式的結構化檔案(Linux 上的 ELF、macOS 上的 Mach-O、Windows 上的 PE),帶有各個區段:程式碼(指令)、初始資料(預設值)、為變數保留的空間、一張說明執行該從何處開始的表,以及中介資料。當你啟動它,作業系統的載入器讀這個檔案,把相關部分複製進記憶體,設好起始狀態,再把 CPU 指向進入點,好讓取指─執行週期得以開始。在 Unix 上你通常以 ./prog 執行它。
為何重要:可執行檔是編譯的具體交付物——你要交付與執行的東西,而不是你的原始碼。因為它含有針對某個 CPU 家族的機器碼、並預期某個特定作業系統,在一個平台上建出的可執行檔,通常無法不重新從原始碼建構,就在一個差異很大的平台上跑。理解可執行檔裡有什麼,也打開了通往關鍵系統主題的門:程式如何在記憶體中排佈、如何連結到函式庫,以及除錯器與工具如何檢查它們。
執行 gcc hello.c -o hello 之後,檔案 hello 就是你的可執行檔。在 Linux 上對它執行 file hello,會回報類似「ELF 64-bit executable」的訊息——作業系統知道如何載入並啟動它;而純文字編輯器打開它,只會顯示一堆亂碼位元組。
那個編譯好、就緒可跑的成品——結構化的機器碼,而非可讀的文字。
可執行檔在差異很大的機器之間並不可攜:它含有針對某一種 CPU 的機器碼,並假設了某個作業系統。可攜的東西是原始碼;你針對每個目標重新編譯它,得到一個新的可執行檔。(連結與載入的細部運作日後再談。)