linux系统调用简要分析


最近又看linux的0.11版本内核,看main.c函数的时候,发现在一个函数调用fork()。竟找不到它的定义,仔细一看,原来都是宏搞的鬼。
在main.c里有这样一句:
static inline _syscall0(int,fork)
查找它的定义,在unistd.h里找到:
#define __NR_setup      0       /* used only by init, to get system going */
#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 __NR_creat      8
#define __NR_link       9
#define __NR_unlink     10
#define __NR_execve     11
#define __NR_chdir      12
#define __NR_time       13
#define __NR_mknod      14
//略过N行.....

#define _syscall0(type,name) /
type name(void) /
{ /
long __res; /
__asm__ volatile ("int $0x80" /
        : "=a" (__res) /
        : "0" (__NR_##name)); /
if (__res >= 0) /
        return (type) __res; /
errno = -__res; /
return -1; /
}

现在分析一下,unistd.h应该就是定义了unix操作系统的标准。所以__NR_setup、__NR_exit、__NR_fork等宏应该就是一些标准。而在宏_syscall0里的__NR_##name也就是将“__NR_”和“name”连结起来。
对于“static inline _syscall0(int,fork)”进行面预处理后就会变成:
int fork(void)
{
long __res;
__asm__ volatile ("int $0x80"
        : "=a" (__res)
        : "0" (2));
if (__res >= 0)
        return (type) __res;
errno = -__res;
return -1;
}
这个函数的关键代码就是下面三行:
__asm__ volatile ("int $0x80"
        : "=a" (__res)
        : "0" (2));
从代码可以看到2就是系统调用的参数,__res就是返回值,而且参数和返回值都存放在eax里。int是中断指令,那一定存在着设置中断门的语句,在sched.c里找到:
set_system_gate(0x80,&system_call);
而在文件system_call.s里,找到它的定义:
system_call:
        cmpl $nr_system_calls-1,%eax
        ja bad_sys_call
        push %ds
        push %es
        push %fs
        pushl %edx
        pushl %ecx              # push %ebx,%ecx,%edx as parameters
        pushl %ebx              # to the system call
        movl $0x10,%edx         # set up ds,es to kernel space
        mov %dx,%ds
        mov %dx,%es
        movl $0x17,%edx         # fs points to local data space
        mov %dx,%fs
        call sys_call_table(,%eax,4)
        pushl %eax
        movl current,%eax
        cmpl $0,state(%eax)             # state
        jne reschedule
        cmpl $0,counter(%eax)           # counter
        je reschedule

关键这是一句“call sys_call_table(,%eax,4)”,在文件sys.h里可以找到它的定义:
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
sys_setreuid,sys_setregid };
很明显sys_call_table[2]就是sys_fork,而它的定义是这样的:
sys_fork:
        call find_empty_process
        testl %eax,%eax
        js 1f
        push %gs
        pushl %esi
        pushl %edi
        pushl %ebp
        pushl %eax
        call copy_process
        addl $20,%esp
1:      ret
于是又调用到copy_process,而copy_process则是fork.c里的函数。

总结一下linux系统的主要线路:
首先使用set_system_gate(0x80,&system_call)设置中断门。这样这后使用int指令时就会调用到system_call,在它里面又调用到了sys_call_table,而sys_call_table存放着各个系统调用的指针。

你可能感兴趣的:(linux,table,System,Access,Parameters,Signal)