本文共 3138 字,大约阅读时间需要 10 分钟。
前提知识(系统调用如何执行) 先看文章
c
,有相对应的开源的标准库glibc
,(2.23的glibc中还是有很多缺陷的
)其中的头文件unistd.h
就包含了许多的系统调用,如read/write/open
等等eax
的值,然后通过触发 软中断使系统进入内核空间,比如32位下经典的int 80
以及64位的syscall
。如果你想更清楚的了解系统调用可以查看我之前写的 。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
文件。include/linux/syscalls.h
中,因为汇编代码到C代码的参数传递是通过栈实现的,所以可以看到所有系统调用的函数前面都使用了asmlinkage
宏,它意味着编译时限制只使用栈来传递参数。kernel/sys.c
中,当我们注册了相应的系统调用号以及定义了 系统调用的函数 之后,我们就可以在此文件的代码的最后添加自己的函数,这个文件中有很多已经实现的系统调用的函数作为参考。添加系统调用号
cd arch/x86/entry/syscalls/vi syscall_64.tbl
添加系统调用号
#上面省略328 64 pwritev2 sys_pwritev2329 common pkey_mprotect sys_pkey_mprotect330 common pkey_alloc sys_pkey_alloc331 common pkey_free sys_pkey_free332 common statx sys_statx333 common ps_counter sys_ps_counter# 下面的我们x32先不管,系统调用号,就在330左右,在此行上面添加# x32-specific system call numbers start at 512 to avoid cache impact# for native 64-bit operation.#
定义系统调用函数
编辑系统调用函数原型定义
vi include/linux/syscalls.h
添加函数原型(__user 是为了向用户空间传值)
#以上省略asmlinkage long sys_pkey_mprotect(unsigned long start, size_t len, unsigned long prot, int pkey);asmlinkage long sys_pkey_alloc(unsigned long flags, unsigned long init_val);asmlinkage long sys_pkey_free(int pkey);asmlinkage long sys_ps_counter(int __user *num);asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags, unsigned mask, struct statx __user *buffer);#endif
编写实现函数
实现函数文件
vi kernel/sys.c
实现函数(这里就只要统计task数量到用户空间,我顺便输出了内核相关的task的信息,可以做调试用)
SYSCALL_DEFINE1(ps_counter, int __user*, num){ struct task_struct *task; int counter=0; printk("[Syscall] ps_counter\n"); printk("Now pid = %ld",current->pid);#current是宏,指向当前task printk("Pid Parent->pid"); for_each_process(task){ counter++; printk(" %ld %ld\n",task->pid,task->parent->pid); } copy_to_user(num, &counter, sizeof(int)); #结果显示到用户空间 return 0;}
编写测试代码
vi test_syscall.c
#include#include #include int main(void){ int result; syscall(333,&result); //系统调用号,是你自己在`tbl`中注册的 printf("process number is %d\n",result); return 0;}
gcc -static -o get_ps_num get_ps_num.c
busybox
下的_install
下的tmp
文件夹中,重新压缩gpio
文件,这一步看之前的文章 find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz
运行测试程序
编译添加完系统调用号,定义了系统调用函数,完成了函数实现之后,编译linux
内核
sudo make -j8
使用新编译的内核以及刚打包的根文件系统,启动虚拟机
qemu-system-x86_64 -kernel ~/Desktop/linux-4.14/arch/x86/boot/bzImage -initrd ~/Desktop/busybox-1.32.1/initramfs.cpio
转载地址:http://jtugf.baihongyu.com/