给 Ubuntu 16.04 64bit(4.4内核)添加一个最简单的系统调用
以前虽然知道原理,但是没真的实践过,这次就留个记录吧
获取内核源码
apt-get提供了一个非常便捷的方式下载内核源码
apt-get source linux-image-$(uname -r)
完成后将会在你的当前目录下产出对应的压缩包及解压后的目录linux-x.x
向 syscall table 添加入口
用你最喜欢的编辑器打开 arch/x86/entry/syscalls/syscall_64.tbl,追加一行
322 64 execveat stub_execveat
323 common userfaultfd sys_userfaultfd
324 common membarrier sys_membarrier
325 common mlock2 sys_mlock2
326 common hello sys_hello <---- 加在这一行
实现 syscall
打开 include/linux/syscalls.h,追加一行
asmlinkage long sys_membarrier(int cmd, int flags);
asmlinkage long sys_mlock2(unsigned long start, size_t len, int flags);
asmlinkage long sys_hello(void); <---- 加这一行
在内核源码根目录下
mkdir hello
touch hello/hello.c
touch hello/Makefile
打开 hello/hello.c,写入
#include <linux/kernel.h>
asmlinkage long sys_hello(void)
{
printk("Hello world\n");
return 0;
}
打开 hello/Makefile,写入
obj-y := hello.o
打开 Makefile,将
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
改为
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ hello/
编译内核 先
make menuconfig
如果你不需要改参数的话直接保存退出就好了
接着开始编译
make -j4 #根据你的逻辑CPU数调整
编译完成后安装
sudo make modules_install install
重启咯,注意下grub选单,免得引导的内核版本不是这次编译的
PS: 如果之前没编译过内核,编译过程中可能会报错,一般都是缺依赖,对应装一下就好
测试
随便在哪新建一个 test.c,内容如下
#include <stdio.h>
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <unistd.h>
#define __NR_hello 326
long hello_syscall(void)
{
return syscall(__NR_hello);
}
int main(int argc, char *argv[])
{
long int a = hello_syscall();
printf("System call returned %ld\n", a);
return 0;
}
然后
gcc test.c
./a.out
这时候应该输出
System call returned 0
那怎么知道确实执行了添加的系统调用呢?从dmesg里找,因为printk会把信息打印到这里
dmesg | tail -n 100
就能看到 hello 系统调用的输出
[ 137.317782] Hello world
棒