作業系統核心

系統呼叫快速路徑(syscall/sysret)

/ SIS-call /

系統呼叫是使用者程式請求核心去做某件它自己無權做的事的方式——讀檔案、在通訊端上送出、建立行程。但從不具特權的使用者模式跨進具特權的核心並非免費;它需要切換特權、找到進入點,並儲存狀態。因為程式會發出數以百萬計的系統呼叫,CPU 為這次跨越加上了一條專用、精簡的路線:一條快速指令進去(syscall),與一條相配的指令出來(sysret)。這一對就是系統呼叫快速路徑——使用者空間與核心之間最佳化過的高速公路。

以下是發生的事,為 x86-64 簡化。程式把系統呼叫的號碼放進一個暫存器(rax),把它的引數放進約定好的暫存器(rdi、rsi、rdx 等等——這是系統呼叫的呼叫慣例),然後執行 syscall 指令。CPU 一步之內切換到特權模式,並跳到一個事先註冊好的核心進入點(核心在開機時把進入位址寫進一個特殊暫存器)。核心進入程式碼儲存使用者暫存器,用 rax 裡的號碼去索引系統呼叫表並呼叫正確的處理常式,然後把結果放進 rax 並執行 sysret,後者原子地降回使用者特權,並在 syscall 指令的正後方恢復程式。快速路徑裡的「快」,是相對於較舊、較慢、透過軟體中斷進入核心的方式(32 位元上的 int 0x80),那方式做了多得多的簿記。

為何它重要:一次系統呼叫的成本主要被這個邊界跨越所支配,而不只是裡面的工作,這正是為何減少系統呼叫的次數(用 writev 批次處理、用 io_uring)能大幅加快真實程式。它也澄清一個常見的誤解:像 read() 這樣的「系統呼叫」並不是進入某個函式庫的普通函式呼叫——它是透過這個硬體機制、進入一個不同特權領域的受控轉換,這正是為何它能做你自己的程式碼做不到的事。

使用者:mov rax, 1(write);設定 rdi/rsi/rdx 引數;'syscall' -> CPU 進入核心進入點、儲存暫存器、透過系統呼叫表呼叫 sys_write、把 rax 設為寫入的位元組數、'sysret' -> 回到使用者模式、就在 syscall 的正後方。

syscall 一步快速進入核心;sysret 返回。rax 裡的號碼透過系統呼叫表選出處理常式。

系統呼叫不是普通的函式呼叫——它是透過專用硬體(syscall/sysret)的特權轉換,這正是為何它的成本遠高於呼叫一個區域函式。是那個固定的邊界成本、而非裡面的工作,才使得批次處理系統呼叫或使用 io_uring 對效能有意義。

又称
syscall instructionfast system callsyscall/sysret系統呼叫快路徑