对于编译内核的方法,我在这篇文章:中有介绍,其中最重要的就是以下这几步:
点击(此处)折叠或打开
- make menuconfig #或者 make defconfig
- make -jn
- make modules
- make modules_install
- make install
以这种方法添加系统调用主要和两个文件相关。
arch/x86/kernel/syscall_table_32.S
这个文件为系统调用表总管,所有的系统调用对应的应该在该表中有所记录,先来看下这个文件的结构:
点击(此处)折叠或打开
- ENTRY(sys_call_table)
- .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
- .long sys_exit
- .long ptregs_fork
- ...
- .long sys_rt_tgsigqueueinfo /* 335 */
- .long sys_perf_event_open
- .long sys_recvmmsg
我们经常会听到系统调用号,这个在文件:arch/x86/include/asm/unistd_32.h中对每个系统调用都安了个号。
他的结构如下:
点击(此处)折叠或打开
- #define __NR_restart_syscall 0
- #define __NR_exit 1
- #define __NR_fork 2
- #define __NR_read 3
- #define __NR_write 4
- ...
- #define __NR_perf_event_open 336
- #define __NR_recvmmsg 337
- #ifdef __KERNEL__
- #define NR_syscalls 338
首先在unistd_32.h文件中添加mycall:
点击(此处)折叠或打开
- ...
- #define __NR_perf_event_open 336
- #define __NR_recvmmsg 337
- #define __NR_mycall 338
- #ifdef __KERNEL__
- #define NR_syscalls 339
点击(此处)折叠或打开
- ...
- .long sys_rt_tgsigqueueinfo /* 335 */
- .long sys_perf_event_open
- .long sys_recvmmsg
- .lang sys_mycall /*338*/
这里用两种方法,一种是让自己的系统调用例程寄存在内核原有的文件中,例如:arch/x86/kernel/sys_i386.c文件中添加:
点击(此处)折叠或打开
- asmlinkage lang sys_mycall(void)
- {
- printk("my sys call ...\n");
- return current->pid;
- }
点击(此处)折叠或打开
- #include <linux/sched.h>
- asmlinkage long sys_mycall(void)
- {
- printk("my sys call ...\n");
- return current->pid;
- }
点击(此处)折叠或打开
- ...
- GCOV_PROFILE_tsc.o := n
- GCOV_PROFILE_paravirt.o := n
- obj-y := process_$(BITS).o signal.o entry_$(BITS).o mycall.o
- obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
- ...
在用户态下还要修改一下:/usr/include/asm/unistd_32.h 文件,添加
#define __NR_mycall 338
在 /usr/include/bits/syscall.h 文件中添加
#define SYS_mycall __NR_syscall
上面的操作都是为了使用户态下用起来比较方便。
一个简单的测试程序:
点击(此处)折叠或打开
- #include <linux/unistd.h>
- #include <stdio.h>
- #include <syscall.h>
- #include <sys/types.h>
- int main(void)
- {
- int res;
- res = syscall(SYS_mycall);
- //res = syscall(338);
- printf("res is %d\n", res);
- return 0;
- }
这里所说的是不带参数的调用方法,带参数的方法和这个是一样的,用户态下的调用程序有所改变:
点击(此处)折叠或打开
- #include <linux/unistd.h>
- #include <stdio.h>
- #include <syscall.h>
- #include <sys/types.h>
- int main(void)
- {
- int res;
- MYTYPE data = INIT;
- res = syscall(SYS_mycall, MYTYPE);
- //res = syscall(SYS_NUMBER, MYTYPE);
- printf("res is %d\n", res);
- return 0;
- }
到此,简单的一个系统调用就添加完毕了。大家有兴趣了可以用这种方法做一些比较有意义的事。
转自: