過程分析:
1、系統調用需要一個用戶空間到內核空間的轉換,不同的平台有不同的指令來完成這樣的轉換,這個指令也叫做操作系統陷入(operating systemtrap)指令。在linux中對於x86來說是用軟中斷0x80,也即是int $0x80。軟中斷由軟件指令觸發,硬中斷由硬件觸發。
通過軟中斷,系統會跳到一個預定的內核空間。它指向了系統調用處理程序(不是系統調用服務程序)system_call函數(arch/x86/kernel/entry32.h)。如上圖。
2、system_call到服務程序
顯然所有的系統調用都會跳到這個地址執行system_call函數。在執行int 0x80時系統調用號會被放入eax寄存器中。因為sys_call_table每個項占用4個字節。所以sys_call_table作為基地址,eax*4作為偏移量就可以找到對應的服務程序的地址。
系統調用的參數通過其他寄存器來傳遞。如
write(unsignedint fd,const char *buf,size_t count)
寄存器ebx,ecx,esi,edx來傳遞。但是前面我們說過,asmlinkage表示內核從堆棧中提取參數,而不是寄存器。因為在system_call執行時首先把這些寄存器壓入堆棧了。從下面的代碼中就可找到答案~~~
ENTRY(system_call) RING0_INT_FRAME # can't unwind into user spaceanyway pushl_cfi%eax # save orig_eax SAVE_ALL GET_THREAD_INFO(%ebp) #system call tracing in operation / emulation testl$_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) jnzsyscall_trace_entry cmpl$(nr_syscalls), %eax jaesyscall_badsys syscall_call: call*sys_call_table(,%eax,4)
系統服務程序從堆棧中獲取參數,並修改,最後再通過堆棧返回修改後的數值。
不是所有的系統調用都有實際內容,如sys_ni_syscll在kernel/sys_ni.c中定義:
asmlinkage long sys_ni_syscall(void){ return -ENOSYS; }
你會發現在sys_call_table中sys_ni_syscall占據了很多內容,其實它代表著已被淘汰的系統調用。
.longsys_ni_syscall /* old stty syscallholder */ .longsys_ni_syscall /* old gtty syscallholder */ .longsys_access .longsys_nice .longsys_ni_syscall /* 35 - old ftime syscallholder */ .longsys_sync .longsys_kill .longsys_rename .longsys_mkdir .longsys_rmdir /* 40 */ .longsys_dup .longsys_pipe .longsys_times .longsys_ni_syscall /* old prof syscallholder */
如上面可知sys_ni_syscall代替了不用的stty和gtty和prof。其實只要是被內核淘汰的系統調用都會被sys_ni_systcall代替。之所以這樣是為了老的程序在新的內核上運行時不至於出現大的問題。如不應調用這個系統調用卻調用了那個系統調用了。
查看本欄目更多精彩內容:http://www.bianceng.cn/OS/unix/