本篇是接着上一篇<编译Linux Kernel – Version 4.9.13>写的。
在下载了kernel的源代码并且解压后,进入根目录下的kernel
文件夹,在里面创建文件hello.c
#include
#include
#include
#include
asmlinkage long sys_hello(long a, long b){
long sum = a + b;
printk("hello world\n");
printk("the sum is %d\n",sum);
return 0;
//return -EINVAL;
}
解释:
asmlinkage
是所有定义system call需要使用的关键字sys_
是所有 system call 函数的约定命名前缀linux/kernel.h
头文件能够使用 printk
,他会在 kernel log内打印内容,使用 sudo dmesg
查看linux/errno.h
中包含了错误代码,system call的约定是:
0
, 如果调用失败则返回负数;errno
,然后返回-1
在同目录(kernel
文件夹)中的Makefile内添加编译目标,保证编译kernel的时候能够产生我们hello
这个system call的目标文件:
obj-y := hello.o
因为本来的Makefile内已经有了很多指定的编译目标文件,所以直接在后面添加上我们的hello.o
, 大概结果是:
kernel
文件夹下网上有些教程,是在 kernel根目录下创建一个文件夹,叫做 hello
, 内部写这个 hello.c
。 这样的话,需要的操作和上面有点不一样:
kernel
文件夹下的Makefile
,而是在hello
这个目录中创建单独的 Makefile
上面第一条, 在kernel根目录下的Makefile
中,找到core-y
这么一行,加上刚才hello的目录路径:
上面第二条,在 刚才创建的hello
文件夹中,创建Makefile,内容写上
obj-y := hello.o
在内核根目录下的include/linux
文件夹中的syscalls.h
的最后面、#endif
之间,添加我们system call的原型:
...
asmlinkage long sys_pkey_alloc....;
// 在这添加自己的 prototype
asmlinkage long sys_hello(long a, long b);
#endif
解释:
asmlinkage
is a key word used to indicate that all parameters of the function would be available on the stack.想要最终能够调用添加的system call,需要在对应机器的 architecture 的 system call table中添加,并且指定 system call 的编号。 所有system call 最终被调用的时候都是通过指定的编号来找到的。
我的机器是x86_64
架构的,可以在uname -a
中查看到。
在内核根目录下的arch
文件夹下有很多不同的 architecture文件夹,如果需要让自己的system call能够在某个architecture的系统中调用,就需要在对应的文件夹下的 systme call table中添加。
以本机来说: arch/x86/entry/syscalls
中的 syscall_64.tbl
中添加:
400 common hello sys_hello
解释:
运行前可以先确定已经安装了需要的工具:
sudo apt-get install gcc
sudo apt-get install libncurses5-dev
sudo apt-get install bison
sudo apt-get install flex
sudo apt-get install libssl-dev
sudo apt-get install libelf-dev
sudo apt-get update
sudo apt-get upgrade
然后回到linux根目录,运行(前提是之前已经有了.config,之前那篇文章有讲,使用make olddefconfig
)
make -jN # N 代表执行编译的内核数,数字越大编译越快
sudo make module_install # 如果之前执行过一次完整的编译内核并且安装,这里不需要重新编译内核
sudo make install # 这句话一定要执行
编译结束后重新启动(一定要重启)
sudo reboot
写一个新的文件:testhello.c
#include
#include
#include
#include
int main()
{
long result = syscall(400, 12, 30);
printf("The result is %ld\n", result);
return 0;
}
然后
gcc testhello.c -o testhello
./testhello
The result is 0
检查系统log
sudo dmesg
解释:
syscall
函数可以用来调用 system call,第一个参数是 system call 编号,之后可以传入对应的system call 的参数大功告成!!