システム呼び出しの詳細手順
2273 ワード
ユーザー状態:
まずシステム呼び出し番号を見つけてunistdを見てみましょう.hヘッダファイルのコード:#define __NR_restart_syscall 0
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
#define __NR_close 6
#define __NR_waitpid 7
......
#define _syscall0(type,name) \
type name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name)); \
__syscall_return(type,__res); \
}
このヘッダファイルでは、システム呼び出しペア用のシステム呼び出し番号、例えばforを定義し、nameをforkに置き換えて二次展開すればよい.NR_forkですので、前に定義します.NR_forkは2であるため、forkに対応するシステム呼び出し番号は2であり、システム呼び出しは0 x 80番の割り込み番号を通じて対応するシステム呼び出しサービスプログラムを見つけ、本当にシステム呼び出しサービスプログラムを実行するとすでにカーネル状態に陥っている.その前に、システム呼び出しの呼び出し番号、呼び出しパラメータを伝達する必要がある.カーネル状態に陥る前に、このようなアセンブリコードがある.(サンプルコードのシステム呼び出しには2つのパラメータがある)
0: 89 da mov %ebx,%edx
2: 8b 4c 24 08 mov 0x8(%esp,1),%ecx
6: 8b 5c 24 04 mov 0x4(%esp,1),%ebx
a: b8 4a 00 00 00 mov $0x4a,%eax
f: cd 80 int $0x80
まず2つのパラメータをレジスタに入力し、0 x 4 a号(例示的なシステム呼び出し関数のシステム呼び出し番号、異なるシステム呼び出しが異なり、前に得られたシステム呼び出し番号に基づいてeaxに入力される)システム呼び出しをeaxレジスタに入力し、最後にintを呼び出してコア状態に陥る.
カーネル状態:
システム呼び出しサービス:ENTRY(system_call)
pushl %eax # save orig_eax
SAVE_ALL
GET_THREAD_INFO(%ebp)
# system call tracing in operation
testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
jnz syscall_trace_entry
cmpl $(nr_syscalls), %eax
jae syscall_badsys
syscall_call:
call *sys_call_table(,%eax,4)
まずユーザ状態のレジスタ情報の一部を自分のスタック(カーネルスタック)に保存し、save_allはマクロで、彼は順番に押し込みます.
%es
%ds
%eax
%ebp
%edi
%esi
%edx
%ecx
%ebx,es,ds,eax,ebpはそれぞれの用途があるため,伝達を許容する最大パラメータの個数は後の5個であり,より多くの場合ポインタを伝達し,copy_を通過する.from_user関数はポインタでパラメータを取得し,ユーザ状態情報の保存が完了し,パラメータもcallの具体的なシステム関数について保存し,関数呼び出しジャンプテーブルは保存したシステム関数の関数ポインタであり,システム呼び出し番号によって具体的なシステム関数を見つけて実行を開始する.
システム関数ジャンプテーブル:ENTRY(sys_call_table)
.long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
.long sys_exit
.long sys_fork
.long sys_read
.long sys_write
.long sys_open /* 5 */
.long sys_close
.long sys_waitpid
.long sys_creat
.long sys_link
.long sys_unlink /* 10 */
.long sys_execve
#define __NR_restart_syscall 0
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
#define __NR_close 6
#define __NR_waitpid 7
......
#define _syscall0(type,name) \
type name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name)); \
__syscall_return(type,__res); \
}
0: 89 da mov %ebx,%edx
2: 8b 4c 24 08 mov 0x8(%esp,1),%ecx
6: 8b 5c 24 04 mov 0x4(%esp,1),%ebx
a: b8 4a 00 00 00 mov $0x4a,%eax
f: cd 80 int $0x80
システム呼び出しサービス:
ENTRY(system_call)
pushl %eax # save orig_eax
SAVE_ALL
GET_THREAD_INFO(%ebp)
# system call tracing in operation
testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
jnz syscall_trace_entry
cmpl $(nr_syscalls), %eax
jae syscall_badsys
syscall_call:
call *sys_call_table(,%eax,4)
まずユーザ状態のレジスタ情報の一部を自分のスタック(カーネルスタック)に保存し、save_allはマクロで、彼は順番に押し込みます.%es
%ds
%eax
%ebp
%edi
%esi
%edx
%ecx
%ebx,es,ds,eax,ebpはそれぞれの用途があるため,伝達を許容する最大パラメータの個数は後の5個であり,より多くの場合ポインタを伝達し,copy_を通過する.from_user関数はポインタでパラメータを取得し,ユーザ状態情報の保存が完了し,パラメータもcallの具体的なシステム関数について保存し,関数呼び出しジャンプテーブルは保存したシステム関数の関数ポインタであり,システム呼び出し番号によって具体的なシステム関数を見つけて実行を開始する.
システム関数ジャンプテーブル:
ENTRY(sys_call_table)
.long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
.long sys_exit
.long sys_fork
.long sys_read
.long sys_write
.long sys_open /* 5 */
.long sys_close
.long sys_waitpid
.long sys_creat
.long sys_link
.long sys_unlink /* 10 */
.long sys_execve