Linux添加系统调用
-
前提知识(系统调用如何执行) 先看文章 裁剪Linux内核,用qemu进行调试
- 我们通常写的
c
,有相对应的开源的标准库glibc
,(2.23的glibc中还是有很多缺陷的
)其中的头文件unistd.h
就包含了许多的系统调用,如read/write/open
等等 - 系统调用是通过的修改寄存器
eax
的值,然后通过触发 软中断使系统进入内核空间,比如32位下经典的int 80
以及64位的syscall
。如果你想更清楚的了解系统调用可以查看我之前写的 ret2syscall 。 - 所以内核的中断处理函数是根据系统调用号来调用相应的内核函数,
c
中的read/write
,其实调用了内核函数sys_read/sys_write
- 因此,添加一个系统调用需要注册 系统调用号 以及相应的 中断处理函数,如此,内核才能找到这个系统调用和执行对应的内核函数。内核的汇编代码最终会在
include/generated/asm/syscalls_64.h
中查找调用号,不过我们并不修改这里,x86
平台提供了一个专门用来注册系统调用的文件/arch/x86/entry/syscalls/syscall_64.tbl
,在编译时会运行同目录下的syscalltbl.sh
脚本,将这个文件中登记过的系统调用都生成到前面的syscalls_64.h
文件中。因此我们后面要添加系统调用就是修改这个tbl
文件。 - 系统执行相应功能,调用的是C代码编写的函数,而不是汇编代码,减轻了编写实现系统调用的负担。系统调用的函数定义在
include/linux/syscalls.h
中,因为汇编代码到C代码的参数传递是通过栈实现的,所以可以看到所有系统调用的函数前面都使用了asmlinkage
宏,它意味着编译时限制只使用栈来传递参数。 - 系统调用函数的实现 在
kernel/sys.c
中,当我们注册了相应的系统调用号以及定义了 系统调用的函数 之后,我们就可以在此文件的代码的最后添加自己的函数,这个文件中有很多已经实现的系统调用的函数作为参考。
- 我们通常写的
-
添加系统调用号
- 编辑调用号注册表
cd arch/x86/entry/syscalls/ vi syscall_64.tbl
-
添加系统调用号
#上面省略 328 64 pwritev2 sys_pwritev2 329 common pkey_mprotect sys_pkey_mprotect 330 common pkey_alloc sys_pkey_alloc 331 common pkey_free sys_pkey_free 332 common statx sys_statx 333 common ps_counter sys_ps_counter # 下面的我们x32先不管,系统调用号,就在330左右,在此行上面添加 <