系统调用之sys_call_table(系统调用表)

sys_call_table中保存了系统调用的处理地址,该表的初始化过程非常巧妙。
系统调用程序system_call会查找系统调用表以获得系统调用号对应的系统调用,并执行。

sys_call_table
初始化sys_call_table的代码
// 定义位置:arch/x86/kernel/syscall_32.c
#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ;
#include <asm/syscalls_32.h>
#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 <asm/syscalls_32.h>
};
代码分析
头文件#include <asm/syscalls_32.h>

该文件是在编译时生成的。编译内核的时候,当执行/arch/x86/syscalls/Makefile编译规则时,该文件会执行/arch/x86/syscalls/syscalltbl.sh,该脚本将同目录下的syscall_32.tbl文件作为输入,然后生成文件arch/x86/include/generated/asm/syscalls_32.h,这个文件正是sys_call_table定义中包含的文件。

  • syscall_32.tbl的部分代码如下(其中定义了系统调用号及系统调用):
#
# 32-bit system call numbers and entry vectors
#
# The format is:
# <number> <abi> <name> <entry point> <compat entry point>
#
# 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
  • syscalltbl.sh代码如下:
#!/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)"。

  • syscalls_32.h中的生成的部分内容如下:
__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)
...
sys_call_table的展开

__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),即可转入系统调用函数进行真正处理。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值