编写一个系统调用
2014-07-31 20:04
162 查看
如何往内核中添加自己写的系统调用?其实步骤非常简单:
原文:http://edsionte.com/techblog/archives/2086
1.编写一个系统调用;
2.在系统调用表末尾加入一个新表项;
3.在< asm/unistd.h >中添加一个新的系统调用号;
4.重新编译内核;
上述工作完成后,就可以在用户程序中使用自己所编写的系统调用了。接下来,我们将逐步分析如何上述步骤。
与普通函数不同的是,这个系统调用的函数名前有asmlinkage修饰符。这个修饰符使得GCC编译器从堆栈中取该函数的参数而不是寄存器中。另外,系统调用函数的命名规则都是sys_XXX的形式。
接下来,我们的要做的是将这个函数放于何处。一种方法是,将上述函数放于/kernel/下的某个文件中;另一种方式是,将这个函数单独存放在/kernel/下的一个新建的.c文件中。不管何种方法,所做的目的都是为了在重新编译内核时将上述我们所编写的系统调用函数编译进内核。
我们所要做的就是在该表的末尾添加我们刚编写的系统调用:.long sys_getpid。我们并不需要显式的指定系统调用号,从0开始算起,我们所编写的函数的系统调用号为341。
当用户进程调用一个系统调用时,其实是通过一个中断号为128的软中断来通知内核的。此时,内核会由用户态切换到内核态转而去执行这个软中断对应的中断处理程序。而这个中断处理程序恰好就是系统调用处理程序。也就是说,任何系统调用都会引发CPU去执行这个系统调用处理程序。因此,必须通过系统调用号来识别不同的系统调用。系统调用号通常会存储在eax寄存器中。
现在我们就在yoursource/arch/x86/include/asm/unistd_32.h文件中添加新的系统调用号。在上一步我们所添加的sys_mygetpid系统调用对应的编号为341,因此我们在该文件的末尾添加下面的语句:#define __NR_mygetpid 341。注意这里的宏命名规则,以__NR_开头。
上述用户程序可能与我们平日里所写的稍有不同。主要区别是增加了_syscall0(int,mygetpid)这个宏。因为我们现在直接在程序中调用系统调用,而我们平时则是通过调用C库中的API来间接调用系统调用。在unistd.h文件中有_syscallN()宏的定义,这里的N可取0~6。N代表的是需要传递给系统调用的参数个数。由于mygetpid系统调用需传递的参数个数为0,因此选取_syscall0。另外,这组宏的内部参数分布有如下特点:第一个参数是系统调用返回值的类型,第二个参数是系统调用函数的名称,接下来的参数按照系统调用参数的次序依次是参数类型和参数名称。对于每个宏来说,都有2+2*N个参数。
OK,上述方法即可以将我们自己编写的系统调用函数加入到内核。try!
原文:http://edsionte.com/techblog/archives/2086
1.编写一个系统调用;
2.在系统调用表末尾加入一个新表项;
3.在< asm/unistd.h >中添加一个新的系统调用号;
4.重新编译内核;
上述工作完成后,就可以在用户程序中使用自己所编写的系统调用了。接下来,我们将逐步分析如何上述步骤。
1.编写系统调用
我们将要实现一个获得当前进程pid的的系统调用。对于一个进程,我们可以直接通过current->pid来获得。为了使得这个系统调用同样适用于一个线程,我们使用current->tgid。这么做的原因是同一个线程组内的所有线程TGID均相同;而一个进程的PID和TGID是相同的。1 | asmlinkage long sys_mygetpid( void ) |
2 | { |
3 | return current->tgid; |
4 | } |
接下来,我们的要做的是将这个函数放于何处。一种方法是,将上述函数放于/kernel/下的某个文件中;另一种方式是,将这个函数单独存放在/kernel/下的一个新建的.c文件中。不管何种方法,所做的目的都是为了在重新编译内核时将上述我们所编写的系统调用函数编译进内核。
2.在系统调用表中添加新的表项
linux中为每一个系统调用都分配一个系统调用号。也就是说,每一个系统调用号都唯一的对应着一个系统调用。内核中使用系统调用表来记录所有已经注册过的系统调用,这个系统调用表存储在sys_call_table中。在yoursource/arch/x86/kernel/syscall_table_32.S中可以看到系统系统调用表。我们所要做的就是在该表的末尾添加我们刚编写的系统调用:.long sys_getpid。我们并不需要显式的指定系统调用号,从0开始算起,我们所编写的函数的系统调用号为341。
01 | ENTRY(sys_call_table) |
02 | . long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ |
03 | . long sys_exit |
04 | . long ptregs_fork |
05 | . long sys_read |
06 | . long sys_write |
07 | . long sys_open /* 5 */ |
08 | …… …… |
09 | . long sys_perf_event_open |
10 | . long sys_recvmmsg |
11 | . long sys_fanotify_init |
12 | . long sys_fanotify_mark |
13 | . long sys_prlimit64 /* 340 */ |
14 | . long sys_mygetpid |
3.在< asm/unistd.h >中添加一个新的系统调用号
上一步,在系统调用表中添加新的表项是为了将系统调用号和系统调用关联起来。现在,我们需要在unistd.h文件中添加具体的系统调用号,这样使得系统可以根据这个系统调用号在系统调用表中查找具体的系统调用。当用户进程调用一个系统调用时,其实是通过一个中断号为128的软中断来通知内核的。此时,内核会由用户态切换到内核态转而去执行这个软中断对应的中断处理程序。而这个中断处理程序恰好就是系统调用处理程序。也就是说,任何系统调用都会引发CPU去执行这个系统调用处理程序。因此,必须通过系统调用号来识别不同的系统调用。系统调用号通常会存储在eax寄存器中。
现在我们就在yoursource/arch/x86/include/asm/unistd_32.h文件中添加新的系统调用号。在上一步我们所添加的sys_mygetpid系统调用对应的编号为341,因此我们在该文件的末尾添加下面的语句:#define __NR_mygetpid 341。注意这里的宏命名规则,以__NR_开头。
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_fanotify_mark 339 |
8 | #define __NR_prlimit64 340 |
9 | #define __NR_mygetpid 341 |
4.编译内核
如果上述三个步骤都完成后,那么接下来重新编译内核即可。具体可参见这里。5.编写用户态的程序
1 | #include < linux/unistd.h > |
2 |
3 | _syscall0( int ,mygetpid) |
4 |
5 | int main() |
6 | { |
7 | printf ( "The current process's pid is %d\n" ,mygetpid()); |
8 | return 0; |
9 | } |
OK,上述方法即可以将我们自己编写的系统调用函数加入到内核。try!
相关文章推荐
- 将编写的系统调用注册为一个正式的系统调用步骤
- Linux系统调用的一个列表(zz)
- 阅读笔记:如何给OpenSolaris增加一个系统调用
- 习题10:参照Windows系统“附件”中的“计算器”,自行编写一个简易的计算器。要求:可以实现由0~4构成的整数的加减运算。
- 实现一个系统调用来进行系统调用计数
- 一个系统调用(SCI)的简化流程
- 一个简单控件的编写--系统托盘
- 添加一个系统调用,遍历内核进程
- 急需一个asp.net(C#)编写的网上论坛系统
- Delphi编写系统服务四:如何限制系统服务和桌面程序只运行一个
- 编写一个文件,读取 src 下面day12包 下面的my.properties 文件,文件内容如下, className=day12.User 结合 IO、反射知识,完成 配置文件中对象的创建和方法调用。并编写方法,列举出 Student 类中所有的属性、
- 进行DOS系统调用,删除一个当前目录下的文件
- 如何调用MFC中的函数打开一个系统资源面板,获取文件
- [转]提供一个C#编写的基类源码(用于操作WINDOWNS系统的服务)
- 问一个调用VC下编写的dll的问题???好怪哦
- 用 c编写的一个学生成绩管理系统
- 使用windows系统调用编写shellcode
- 向OpenSolaris内核中添加一个系统调用
- Delphi编写系统服务四:如何限制系统服务和桌面程序只运行一个
- 用Delphi编写一个Svchost.exe调用的DLL模块