Chinaunix首页 | 论坛 | 博客
  • 博客访问: 569677
  • 博文数量: 61
  • 博客积分: 2438
  • 博客等级: 大尉
  • 技术积分: 871
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-28 08:04
文章分类
文章存档

2013年(1)

2012年(8)

2011年(15)

2010年(37)

分类: LINUX

2012-07-01 15:27:48

上次说过了以内核模块插入方式给系统添加系统调用,其实,在实际的使用中一般都是要将系统调用添加到系统中,要使它的操作和平时没用什么区别,这就到了这次要说的这次这种方法,修改内核文件,然后重新编译内核。
对于编译内核的方法,我在这篇文章:中有介绍,其中最重要的就是以下这几步:

点击(此处)折叠或打开

  1. make menuconfig #或者 make defconfig
  2. make -jn
  3. make modules
  4. make modules_install
  5. make install
这样就可以使用自己的系统调用了,说了这么多,现在我们进入主题 ^_^
以这种方法添加系统调用主要和两个文件相关。
arch/x86/kernel/syscall_table_32.S
这个文件为系统调用表总管,所有的系统调用对应的应该在该表中有所记录,先来看下这个文件的结构:

点击(此处)折叠或打开

  1. ENTRY(sys_call_table)
  2. .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
  3. .long sys_exit
  4. .long ptregs_fork
  5. ...
  6. .long sys_rt_tgsigqueueinfo /* 335 */
  7. .long sys_perf_event_open
  8. .long sys_recvmmsg
这样显示我的当前系统有338个系统调用。
我们经常会听到系统调用号,这个在文件:arch/x86/include/asm/unistd_32.h中对每个系统调用都安了个号。
他的结构如下:

点击(此处)折叠或打开

  1. #define __NR_restart_syscall 0
  2. #define __NR_exit 1
  3. #define __NR_fork 2
  4. #define __NR_read 3
  5. #define __NR_write 4
  6. ...
  7. #define __NR_perf_event_open 336
  8. #define __NR_recvmmsg 337

  9. #ifdef __KERNEL__

  10. #define NR_syscalls 338
下来我们要做的就是在两个文件先添加相应的系统调用号。
首先在unistd_32.h文件中添加mycall:

点击(此处)折叠或打开

  1. ...
  2. #define __NR_perf_event_open 336
  3. #define __NR_recvmmsg 337
  4. #define __NR_mycall 338

  5. #ifdef __KERNEL__

  6. #define NR_syscalls 339
修改syscall_table_32.S文件:

点击(此处)折叠或打开

  1. ...
  2. .long sys_rt_tgsigqueueinfo /* 335 */
  3. .long sys_perf_event_open
  4. .long sys_recvmmsg
  5. .lang sys_mycall /*338*/
下来就是我们要给系统添加自己的系统调用服务例程了sys_mycall函数。
这里用两种方法,一种是让自己的系统调用例程寄存在内核原有的文件中,例如:arch/x86/kernel/sys_i386.c文件中添加:

点击(此处)折叠或打开

  1. asmlinkage lang sys_mycall(void)
  2. {
  3.     printk("my sys call ...\n");
  4.     return current->pid;
  5. }
另外的一种方法就是在在kernel目录下创建一个新的文件mycall.c:

点击(此处)折叠或打开

  1. #include <linux/sched.h>

  2. asmlinkage long sys_mycall(void)
  3. {
  4.     printk("my sys call ...\n");
  5.     return current->pid;
  6. }
然后在Makefile文件中添加mycall.o

点击(此处)折叠或打开

  1. ...
  2. GCOV_PROFILE_tsc.o := n
  3. GCOV_PROFILE_paravirt.o := n

  4. obj-y := process_$(BITS).o signal.o entry_$(BITS).o mycall.o
  5. obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
  6. ...
这样该添加的都已经添加了,下来就是测试自己的系统调用了。
在用户态下还要修改一下:/usr/include/asm/unistd_32.h 文件,添加
#define __NR_mycall 338
在 /usr/include/bits/syscall.h 文件中添加
#define SYS_mycall __NR_syscall
上面的操作都是为了使用户态下用起来比较方便。
一个简单的测试程序:

点击(此处)折叠或打开

  1. #include <linux/unistd.h>
  2. #include <stdio.h>
  3. #include <syscall.h>
  4. #include <sys/types.h>

  5. int main(void)
  6. {
  7.     int res;
  8.     res = syscall(SYS_mycall);
  9.     //res = syscall(338);
  10.     printf("res is %d\n", res);
  11.     return 0;
  12. }
上面的两种调用方法都是一样的。
这里所说的是不带参数的调用方法,带参数的方法和这个是一样的,用户态下的调用程序有所改变:

点击(此处)折叠或打开

  1. #include <linux/unistd.h>
  2. #include <stdio.h>
  3. #include <syscall.h>
  4. #include <sys/types.h>

  5. int main(void)
  6. {
  7.     int res;
  8.     MYTYPE data = INIT;
  9.     res = syscall(SYS_mycall, MYTYPE);
  10.     //res = syscall(SYS_NUMBER, MYTYPE);
  11.     printf("res is %d\n", res);
  12.     return 0;
  13. }
这里的MYTYPE是你系统调用服务例程的参数类型,INIT为初始化的数据,在syscall()函数中的第一个参数为系统调用号。
到此,简单的一个系统调用就添加完毕了。大家有兴趣了可以用这种方法做一些比较有意义的事。

转自:
阅读(3114) | 评论(0) | 转发(0) |
0

上一篇:GCC语言特性

下一篇:系统调用分析-sysinfo()

给主人留下些什么吧!~~