| 1 系統呼叫
使用者程式要顯示字串訊息,就要呼叫系統函式 printf。
使用者程式要使用設備驅動程式,就要呼叫 open、close 等系統函式。
沒有呼叫任何系統程式的使用者程式,大概也不能做任何事。
系統函式通常是透過系統呼叫,系統呼叫通常是軟體中斷,用於實現使用者模式和核心模式的轉換。
80x86 使用 int 0x80,實現系統呼叫。ARM 是用 SWI 實現系統呼叫。
這裡筆者會說明 SWI 實現系統呼叫的過程。
中斷向量表,當各種中斷發生時,程式計數器會自動跳躍到中斷表內,再跳躍到中斷處理程序開頭,準備執行中斷處理函式。
這裡的重點是軟體中斷向量,即 ldr pc,.LCvswi + stubs_offset。
符號 .LCvswi 的位址上存放軟體中斷處理程序的開頭位址 vector_swi。
vector_swi 放在 entry-common.S,是真正執行軟體中斷的地方。
ARM 中斷向量表。
.LCvswi 存放軟體中斷處理程序入口點位址 vector_swi。
軟體中斷處理程序。
1.備份所有暫存器值。
2.取得 SWI 指令值,因為指令內容存有軟體中斷號碼。
3.取得系統呼叫向量表 sys_call_table 位址,其內容就是 calls.S 的展開。
4.設定中斷處理函式的回返位址。當處理函式結束後,回返到 ret_fast_syscall,而不是這裡的下一行(add r1,sp,#S_OFF)。
5.跳躍到中斷處理函式所在位址,執行該系統呼叫。
系統呼叫向量表 sys_call_table。
1.定義 OBSOLETE(syscall)。舊系統使用 syscall,新系統使用 sys_ni_syscall。
2.設定向量表的入口點符號名稱 sys_call_table。
3.填入向量表內容,即 calls.S。
向量表內容 calls.S。
1.第0個系統呼叫是 sys_restart_syscall,重新啟動系統。
2.第1個系統呼叫是 sys_exit,結束行程。
3.第2個系統呼叫是 sys_fork_wrapper,行程建立。
4.第3個系統呼叫是 sys_read,設備讀取。
5.第4個系統呼叫是 sys_write,設備寫入。
6.第4個系統呼叫是 sys_open,設備開啟。
7.第4個系統呼叫是 sys_open,設備關閉。
這裡以系統呼叫 sys_open 為例,說明系統呼叫建立過程。
程式檔案 linux/fx/open.c
sys_open 的函式實作。
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode) 會轉譯成
asmlinkage long sys_open(const char __user * filename,int flags,int mode)
其中,sys_open 就是 open 系統呼叫的入口點符號。
當 sys_open 執行完畢,回返時,程式就會回返到先前在 vector_swi 設置的 ret_fast_syscall。
ret_fast_syscall 可以立即回到原本的使用者程序,或者切換到其它程序,端看行程的參數設定值。
就算切換到其它程序,還是會再切換回來,只是需要花一些時間慢了一點。這就是 ARM LINUX 系統呼叫的整個執行過程。
|