作業系統核心

系統呼叫表(system-call table)

一旦 syscall 指令把程式帶進核心,核心仍得弄清楚被請求的究竟是它數百項服務中的哪一項——這是 read、write、open,還是 fork?系統呼叫表就是它做決定的方式:一個簡單的函式指標陣列,每個系統呼叫一格,由程式傳入的系統呼叫號碼索引。它是核心的總機,把一個數字轉成正確的處理常式。

機制上它就是一次普通的查表。每個系統呼叫都有一個由核心 ABI 定義的穩定號碼——在 Linux x86-64 上,read 是 0、write 是 1、open 是 2,依此類推——這些號碼基本上永不更動,因為舊的二進位檔把它們寫死了。程式在執行 syscall 之前,把它選定的號碼載入一個暫存器(x86-64 上的 rax);核心的進入程式碼取得那個號碼、檢查它在範圍內、把它當作索引查表,並呼叫存在那裡的函式指標。所以請求「write」其實就是「呼叫表中第 1 格的函式」。號碼必須先對照表的大小檢查,因為一個超出範圍的號碼,否則就會索引到陣列之外——一個記憶體安全漏洞。

為何理解這張表令人豁然開朗:它把「核心/使用者介面是一份固定、編號的契約,而非你在執行期協商的彈性 API」這件事具體化了。新增一個系統呼叫意味給它下一個空號碼並加上一個表項,而那個號碼此後就為了相容性而永遠凍結。一個值得標記的歷史註腳:這張表曾是 rootkit 最愛的目標,它們會覆寫一個表項,把某個系統呼叫重導向到惡意程式碼——這正是為何現代核心在開機後把系統呼叫表設為唯讀,使它無法被悄悄劫持。

系統呼叫號碼(Linux x86-64):0=read、1=write、2=open、57=fork。核心進入:if (nr < NR_syscalls) sys_call_table[nr](args); ——號碼索引一個函式指標陣列;超出範圍者先被拒絕。

這張表把一個固定的系統呼叫號碼對應到它的處理常式。號碼先做邊界檢查,再當作陣列索引使用。

系統呼叫號碼是核心 ABI 中被凍結的一部分——它們無法重新排序或重複使用,否則會破壞那些把它們寫死的既有二進位檔。又因為覆寫一個表項曾讓 rootkit 劫持呼叫,這張表在開機後被設為唯讀;把它當成不可變的契約,而非你可以修補的可變分派。

又称
syscall tablesys_call_tablesystem call dispatch table系統呼叫分派表