作業系統介面

系統呼叫介面與系統呼叫編號(system-call interface and syscall number)

想像一家老派餐廳,菜單上的菜色是編號的。你不會用一整段文字向廚房描述你的餐點;你說「27 號」,而廚房有一張清單把 27 對應到某道特定食譜。核心也是這樣運作的:它不認得「read」這個名字,它認得一個編號,並維護一張表把每個編號對應到負責處理它的常式。

系統呼叫介面是程式與核心交換這些請求時雙方約定好的契約:哪個暫存器放系統呼叫編號、哪些暫存器放引數、回傳值從哪裡回來、錯誤如何回報。核心提供的每一項服務都有一個固定的系統呼叫編號——在 Linux x86-64 上,read 是 0 號、write 是 1 號、open 是 2 號,以此類推。核心保存著一張系統呼叫表:本質上是一個以該編號為索引的陣列,每個格子放著實作該呼叫的函式位址。當程式帶著放在正確暫存器裡的編號陷入核心時,核心就用它當作這張表的索引,跳到對應的處理常式。這些編號是平台二進位契約(也就是它的 ABI)的一部分,所以一旦指派就會保持穩定,這正是為什麼多年前編譯的程式至今仍能運作。

為何重要:這說明了為什麼同一份 C 原始碼能在不同機器上跑,而一個已編譯的二進位檔卻常常無法在不同作業系統間搬移——它們的編號與呼叫規則不同。這也是為什麼像 strace 這樣的工具能把程式進行的每一個系統呼叫以名稱與引數顯示給你看:它們用一張已知的表把編號解碼回來。身為初學者,你很少親手寫這些編號(C 函式庫替你做了),但知道它們存在,能讓「系統呼叫介面」到底是什麼變得不再神祕。

在 Linux x86-64 上,read 系統呼叫是 0 號。一個把 0 放進 rax、把有效的檔案描述符放進 rdi、把緩衝區放進 rsi、把長度放進 rdx,然後執行 syscall 的程式,就是在請核心讀取——它從頭到尾沒有在任何地方寫出「read」這個字。

核心是依編號分派、而非依名稱;那個編號是系統呼叫表的索引。

系統呼叫編號因作業系統、甚至因架構而異:read 在 Linux x86-64 上是 0,但在 32 位元 x86 或別的作業系統上是別的編號。不要把它們寫死;用函式庫的包裝,它知道該平台正確的編號。

又稱
syscall tablesyscall ABIsystem call number系統呼叫表系統呼叫號