增加系统调用
在实际编程中,尤其是当我们需要增加或完善系统功能的时候,我们经常会用到系统调用函数。系统调用函数通常由用户进程在用户态下调用,内核通过system_call 函数响应系统调用产生的软中断,在正确访问核心栈、系统调用开关表之后陷入到操作系统内核中进行处理。
系统调用是用户进程由用户态切换到核心态的一种常见方式。利用编写系统调用函数来直接调用了部分操作系统内核代码,也是Linux内核编程者必修之功。下面笔者以在Linux中创建一个名为print_info的系统调用函数为例,来说明如何为内核增加系统调用。
需要以下几个基本步骤:
1、编写系统调用函数 编辑sys.c文件: # cd /usr/src/linux/kernel # vi sys.c 在文件的最后增加一个系统调用函数: asmlinkage int sys_print_info(int testflag) { printk(" Its my syscall function!n"); return 0; } 该函数有一个int型入口参数testflag,并返回整数0。
2、修改与系统调用号相关的文件 编辑入口表文件: # cd /usr/src/linux/arch/i386/kernel # vi entry.S 把函数的入口地址加到sys_call_table表中: arch/i386/kernel/entry.S中的最后几行源代码修改前为: ...... .long SYMBOL_NAME(sys_sendfile) .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ .long SYMBOL_NAME(sys_vfork) /* 190 */ rept NR_syscalls-190 .long SYMBOL_NAME(sys_ni_syscall) .endr 修改后为: ...... .long SYMBOL_NAME(sys_sendfile) .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ .long SYMBOL_NAME(sys_vfork) /* 190 */ .long SYMBOL_NAME(sys_print_info) /* added by I */ .rept NR_syscalls-191 .endr 修改相应的头文件: # cd /usr/src/linux/include/asm # vi unistd.h 把增加的sys_call_table表项所对应的向量,在include/asm/unistd.h中进行必要申明,以供用户进程和其他系统进程查询或调用。 #define __NR_putpmsg 189 #define __NR_vfork 190 #define __NR_print_info 191 /* added by I */
3、编译内核,再重启动
4、测试 编写用户测试程序(test.c): # vi test.c #include #include extern int errno; _syscall1(int,print_info,int,testflag) main() { int i; i= print_info(0); if(i==0) printf("i=%d , syscall success!n",i); } 如果要在用户程序中使用系统调用函数,那么在主函数main前必须申明调用_syscall,其中1 表示该系统调用只有一个入口参数,第一个int 表示系统调用的返回值为整型,print_info为系统调用函数名,第二个int 表示入口参数的类型为整型,testflag为入口参数名。 编译测试程序: # gcc -o test test.c 执行测试程序: # ./test Its my syscall function! i=0, syscall success! ok!!!增加系统调用函数成功! 以上步骤在pentium Ⅲ/64M/20G、Red Hat Linux 6.0(2.2.5-15)机上测试通过。
|