linux5 syscall 流程_Linux 執行 System Call 流程圖

System Call 流程圖

當User application呼叫一個時, 會先執行glibc.so中Wrapper Routine. Wrapper Routine會產生一個trap(在Linux下會跳到int 0x80),此時系統將mode bit由user mode改成monitor mode(1->0)並查尋trap vector找尋相對應trap service routine(此時可做context switch 0->1)

執行完此routine發出interrupt告訴os已經完成:

流程:

User program 與 wrapper routine 是 user space 的 code

system call handler 與 service routine 則是屬於 kernel space

從 User space 切換到 kernel space 是透過中斷

以下的用link這個system call當例子,解釋程式碼

syscall_table.S

PATH : /usr/src/linux/arch/i386/kernel/syscall_table.S

在 Linux 中, 每個 system call 都有自己獨有的號碼。

當 user-space 執行一個 system call 時,process是去參考 syscall 的號碼而不是名字。

unistd.h

PATH : /usr/src/linux/include/asm/unistd.h

unistd.h 是一個重要的標頭檔,裡頭是 system call 編號的定義,當 system call 發生時,system call 的號碼將透過 register (EAX) 傳給 kernel。

#define _syscall2(type,name,type1,arg1,type2,arg2) \

type name(type1 arg1,type2 arg2) \

{ \

long __res; \

__asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" \

: "=a" (__res) \

: "0" (__NR_##name),"ri" ((long)(arg1)),"c" ((long)(arg2)) \

: "memory"); \

__syscall_return(type,__res); \

}

unistd.h 也定義了不同參數的 system call handler,上面的程式碼是處理 2 個參數的 handler

這是一個 macro,當遇到系統呼叫的時候,就會被展開。

參數傳遞與傳回值

system call 的編號透過 %eax 暫存器來指定;若要傳遞參數,則是透過其它暫存器來傳遞(最上面的流程圖上有標示)

Linux system call 最多可傳遞6個參數,參數的傳遞是透過以下的暫存器來完成:

%ebx:第1個參數。

%ecx:第2個參數。

%edx:第3個參數。

%esi:第4個參數。

%edi:第5個參數。

%ebp:第6個參數(做臨時用途)。

x86 的 Interrupt

x86 的interrupt(中斷)可分為系統定義與使用者自訂:

中斷向量0~8、10~14、16~18:predefined interrupts and exceptions。

中斷向量19-31:保留。

中斷向量32-255:user-defined interrupts(maskable interrupts)。

當從 shell 執行 link 時,0x80 號中斷向量會指到 system_call 進入點的位址,由於 link 有兩個參數,const char* oldfile 和 const char* newfile,因此 shell 會執行 syscall2(int link, const char* oldname, const char* newname),執行 sys_link(),sys_link()會呼叫linkat()。在 linux 中,目錄和檔案在系統中被視為同樣。

int link(const char* oldname, const char* newname)

{

long _res;

_asm_  volatile(“int $0x80”

:”=a”(_res)

:”0”(_NR_link),”b”((long)(oldname)),

“c”((long)(newname)));

do{

if((unsigned long)(_res)>=(unsigned long)(-(128+1))){

errno=-(_res);

_res=-1;

}

return (int)(_res);

}while(0);

}

下面這段組語是 system call 的進入點,也就是 system call table

PATH : /usr/src/linux/arch/i386/kernel/entry.S

ENTRY(system_call)

pushl %eax                      # save orig_eax

SAVE_ALL

GET_CURRENT(%ebx)

testb $0x02,tsk_ptrace(%ebx)    # PT_TRACESYS

jne tracesys

cmpl $(NR_syscalls),%eax

jae badsys

call *SYMBOL_NAME(sys_call_table)(,%eax,4)

movl %eax,EAX(%esp)             # save the return value

ENTRY(ret_from_sys_call)

cli                             # need_resched and signals atomic test

cmpl $0,need_resched(%ebx)

jne reschedule

cmpl $0,sigpending(%ebx)

jne signal_return

syscalls.h

PATH : /usr/src/linux/include/linux/syscalls.h

這個檔案包含了 system call 的宣告。

asmlinkage 是在i386 system call實做中,gcc 很重要的一個標籤。他是一個macro,會被展開成

#define asmlinkage __attribute__((regparm(0)))

這是/usr/include/asm/linkage.h 裡頭的定義,regparm(0)表示不使用register傳遞參數

如此一來所有的參數就會被強迫放在stack當中

這麼做的原因是因為system call handler是assembly code,但是system call routine是C code

為了要保證當system call handler呼叫相對應的system call routine時,符合C語言參數傳遞的規則

是以 stack 方式傳參數,在C function的 prototype前面就要加上 "asmlinkage"。

System call 結束

當 system call 執行完的時候,最後會執行 ret_from_sys_call() 離開。

最後回到 syscallX() 中去。在 syscallX() 中,檢測是否有錯誤碼,然後返回。

(秩名)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值