如何在linux0.11上添加内核函数
原理不多说了,直接进入正题
编写内核函数
这里就简单的编写一个打印函数,用到内核中的printk()函数,所以加上头文件
1 | /* linux0.11/kernel/who.c */ |
编写好了一个.c文件,但是这样还是不够的,在最终make的时候还需要将其编译为.o文件,以供链接。
修改同目录下的Makefile文件,在OBJS下添加who.o,并在结尾处添加who相关的规则
1 | OBJS = sched.o system_call.o traps.o asm.o fork.o \ |
这样就可以将.c文件变成二进制文件编入操作系统中了
注册内核函数
上面还只是定义内核函数,并没有告诉操作系统有这么个函数,所以还需要在系统调用表中注册这个函数。所谓注册,其实就是在头文件中添加函数的声明,这样我们在后面编写的系统调用函数能够通过这个头文件中的sys_call_table[]函数调用表链接到前面写的函数定义。
写在数组上面的声明主要是写给数组看的。
1 | /* linux0.11/include/linux/sys.h */ |
编写系统调用函数前的准备
由于系统调用函数是通过输入一个常量符号作为sys_call_table[]数组的下标去调用内核函数的,所以还需要将这个常量符号定义一下。
1 | /* linux0.11/include/unistd.h */ |
在int 0x80中程序会比较系统调用号和系统调用总数的关系,所以还需要修改一下这个总数的数值
1 | /* linux0.11/kernel/system_call.s */ |
编写系统调用函数
系统调用函数是作为调用内核函数的接口提供给用户使用的,它的作用就是走int 0x80然后调用相应的内核函数
这一块其实很简单,linux中已经为我们提供好了函数模板。就是linux0.11/include/unistd.h下的_syscall0、_syscall1、_syscall3宏函数
我们只需要调用这个宏函数就可以完成系统调用函数的定义
起初我本来想像write()函数一样定义在linux0.11/lib目录下的,但是不知道为什么会出现error: undefined symbol _whoami referred from texe segment报错。
没办法只能在测试程序中定义了。
1 | /* ~/test.c */ |
注意一定要在测试程序中定义_LIBRARY_,否则是找不到unistd.h文件中的宏定义和系统调用号
不过可能会出现系统调用号未定义的行为,这是因为Bochs虚拟机中的unistd.h没有定义,在/usr/include/unistd.h里面再加上就好了
