Linux内核编程实战经验谈[2]

[入库:2005年9月19日] [更新:2007年3月24日]

本文简介:

   在实际编程中,尤其是当我们需要增加或完善系统功能的时候,我们经常会用到系统调用函数。系统调用函数通常由用户进程在用户态下调用,内核通过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

本文关键:Linux内核编程实战经验谈
  相关方案
Google
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top