Linux 4.x 添加系统调用
学校学习操作系统,上机使用的环境是Ubuntu 10.4
,内核上也就是Linux 2.6
,但是现在Linux内核版本已经4.x了啊喂。主要更难过的是,上机给的示例代码在4.x的机子上根本就没法运行,因为系统调用的接口已经变了。就这样我也就忍了,自己找找新的接口定义也就完了。
结果接下来要求添加一个系统调用,这回好了,添加系统调用的文件夹直接就不存在。到网上去找也是各种最高才到3.x的教程,简直没有办法能做下去,幸而再后来还是找到了一两篇中文的教材,没至于沦落到啃英文手册的地步,不过看来自己是非总结一下不可了。
本机环境是
1 | $ uname -r |
首先需要进到/usr/src/linux/
,并确保你有root权限。
系统调用函数
这里需要修改的是include/linux/syscalls.h
,这里的最后加上你需要的系统调用的函数申明,比如:
1 | asmlinkage long sys_mycall(int number); |
需要加在最后一行#endif
的前面。
其中asmlinkage
是一个宏,定义在include/linux/linkage.h
中。它的意思是使C使用栈的方式来传递参数,而不是像一般的C程序一样使用寄存器。这样取用参数就可以通过push和pop语句直接进行了,不需要直接寄存器来传值。这种方式据说在很高度优化的程序当中存在着,无论怎么说,大部分系统调用都有这么一个前缀。
添加系统调用应该需要在kernel文件夹中新建一个文件,然后在里面写入函数,但是为了简单起见(不用修改Makefile),就只修改kernel/sys.c
这个文件即可。在文件的最后加上这么一个函数:
1 | asmlinkage long sys_mycall(int number) { |
这个函数唯一的功能就是使用printk
函数输出了一句话。
在系统调用表中添加函数
arch/x86/entry/syscalls/syscall_64.tbl
,这个文件对应2.6内核中的系统调用表arch/x86/kernel/syscall_table_32.S
。64是因为对应了64位的操作系统。
在文件尾部按照前面的格式添上你的系统调用就好了,注意第一个数字是系统调用号,不要覆盖原有的系统调用。
1 | 331 common pkey_free sys_pkey_free |
系统调用号需要记一下,等一下测试的时候会用到。
编译内核
在这之后,回到/usr/src/linux
,输入以下指令:
1 | make oldconfig |
重启
1 | reboot |
然后你就已经在内核中添加了你自己的系统调用了。
测试你的代码
1 |
|
这会使用你新加入的系统调用号为548的系统调用。传入参数10。这样就会调用sys_mycall
函数里面的printk
它输出的内容可以使用dmesg
来看到,但是如果不想跟其他系统调用输出的内容混在一起,最好使用grep:
1 | dmesg | grep "my call" |
如果一切正确,你应该能看到你的输出。
如果你传到系统调用的是一个指针,请务必小心,这可能会引起一个错误。因为内存的地址跟程序里的地址是不一样的。