sys_call_table中保存了系统调用的处理地址,该表的初始化过程非常巧妙。
系统调用程序system_call会查找系统调用表以获得系统调用号对应的系统调用,并执行。
// 定义位置:arch/x86/kernel/syscall_32.c
#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ;
#include
#undef __SYSCALL_I386
#define __SYSCALL_I386(nr, sym, compat) [nr] = sym,
typedef asmlinkage void (*sys_call_ptr_t)(void);
extern asmlinkage void sys_ni_syscall(void);
// sys_call_table是一个数组,其值为typedef void (*sys_call_ptr_t)(void)类型的函数指针
__visible const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
/*
* Smells like a compiler bug -- it doesn't work
* when the & below is removed.
*/
// 先对表中所有 __NR_syscall_max+1 项初始化为指向 sys_ni_syscall 的函数,该函数只返回 -ENOSYS,表示该系统调用未实现
[0 ... __NR_syscall_max] = &sys_ni_syscall,
// syscalls_32.h是在编译时生成的
#include
};
该文件是在编译时生成的。编译内核的时候,当执行/arch/x86/syscalls/Makefile编译规则时,该文件会执行/arch/x86/syscalls/syscalltbl.sh,该脚本将同目录下的syscall_32.tbl文件作为输入,然后生成文件arch/x86/include/generated/asm/syscalls_32.h,这个文件正是sys_call_table定义中包含的文件。
#
# 32-bit system call numbers and entry vectors
#
# The format is:
#
#
# The abi is always "i386" for this file.
#
0 i386 restart_syscall sys_restart_syscall
1 i386 exit sys_exit
2 i386 fork sys_fork stub32_fork
3 i386 read sys_read
4 i386 write sys_write
5 i386 open sys_open compat_sys_open
6 i386 close sys_close
#!/bin/sh
in="$1"
out="$2"
grep '^[0-9]' "$in" | sort -n | (
while read nr abi name entry compat; do
abi=`echo "$abi" | tr '[a-z]' '[A-Z]'`
if [ -n "$compat" ]; then
echo "__SYSCALL_${abi}($nr, $entry, $compat)"
elif [ -n "$entry" ]; then
echo "__SYSCALL_${abi}($nr, $entry, $entry)"
fi
done
) > "$out"
in和out分别代表的就是syscall_32.tbl和syscalls_32.h文件的路径。脚本读取syscall_32.tbl内容,然后构造语句__SYSCALL_abi(nr, entry,entry)"。
__SYSCALL_I386(0, sys_restart_syscall, sys_restart_syscall)
__SYSCALL_I386(1, sys_exit, sys_exit)
__SYSCALL_I386(2, sys_fork, stub32_fork)
__SYSCALL_I386(3, sys_read, sys_read)
__SYSCALL_I386(4, sys_write, sys_write)
__SYSCALL_I386(5, sys_open, compat_sys_open)
__SYSCALL_I386(6, sys_close, sys_close)
__SYSCALL_I386(7, sys_waitpid, sys32_waitpid)
__SYSCALL_I386(8, sys_creat, sys_creat)
__SYSCALL_I386(9, sys_link, sys_link)
__SYSCALL_I386(10, sys_unlink, sys_unlink)
__SYSCALL_I386(11, sys_execve, stub32_execve)
...
__SYSCALL_I386 是一个宏定义:#define __SYSCALL_I386(nr, sym, compat) [nr] = sym
const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
[0 ... __NR_syscall_max] = &sys_ni_syscall,
[0] = sys_restart_syscall,
[1] = sys_exit,
[2] = sys_fork,
[3] = sys_read,
//...
};
系统调用处理程序system_call执行call *sys_call_table(,%rax,4),即可转入系统调用函数进行真正处理。