Linux系统调用过程(Linux0.11内核实验)
什么是系统调用呢?
系统调用和普通函数调用得区别:
普通函数调用:调用自定义函数是通过call指令直接跳转到该函数的地址,继续运行。
系统调用:调用一个系统得API(Application programming Interface)应用程序接口,通过API调用真正的系统调用;
API调用系统调用的过程:
1. 把系统调用的编号存入EAX
2. 把函数参数存入其它通用寄存器
3. 触发0x80号中断(int 0x80)
有点迷糊了吧,来看一下实验;
首先,需要将两个函数原型改变一下:
int iam(const char * name);
int whoami(char* name, unsigned int size);
变成:
_syscall1(int,iam,char*,name);
_syscall2(int,whoami,char*,name,int,size);
以便于_systemcall*宏展开;
不知道什么是_system*宏展开;那就来看一下unistd.h中定义的_system1宏:
#define _syscall1(type,name,atype,a) \
type name(atype a) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(a))); \
if (__res >= 0) \
return (type) __res; \
errno = -__res; \
return -1; \
}
这里先定义了一个long变量__res;
之后把中断号__NR_##name(name是参数要替换)传入寄存器EAX,参数a存入寄存器EBX,__res用来承载中断返回值,int 80就是我们熟知的中断调用,后面就是返回值分析判断;
因此,我们需要在unistd.h中添加中断号的宏的定义,在开头写入:
#define __NR_iam 72
#define __NR_whoami 73
之后,我们就进入了int 80所进入了系统调用,经过一重重调用啊我们终于到了system_call.s文件,也就是我们的系统调用处理到达我们需要的函数得代码,纯汇编啊,看起来很蛋疼;
看啊看;看到一句:
nr_system_calls = 72;
这个是什么?系统调用总数啊,一句话改之~~~~
之后:
system_call:
...
call sys_call_table(,%eax,4)
...
这句话就很牛逼了,翻译过来就是
call sys_call_table + 4 * %eax
记不记得,EAX是我们之前在宏展开时存放中断号的地方,这里乘以4后加上一个值,其实就是在计算函数指针的地址啊!!!!
而sys_call_table是什么值呢?
我们看sys.h中,发现了吗?中断函数表,那上面的语句就是很明显在通过数组首地址计算数组元素的地址了,也就是函数指针的地址。
这样,我们在数组中添加:
fn_ptr sys_call_table[] = { ...,sys_iam,sys_whoami};
因为函数原型不知在这里申明的,之前需要加上:
extern int sys_whoami();
extern int sys_iam();
这样,编译器就会去别的文件中寻找函数定义。
其实到这步,我们依旧没有定义函数,现在去编译的话,就会出错。
接下来,就该我们写实实在在的函数来实现了,只要名字是sys_whoami(),int sys_iam();编译器就会找到,当然,前提是要编译到内核中。
新建who.c文件到kernel文件夹引入一大堆头文件后就可以开始写了,和一般的函数基本上一样不过要时刻记住在内核中运行;
写完:sys_iam,sys_whoami后就可以开始编译了;
但是怎么把我写得who.c编译到内核中呢?
主要就是要修改makefile文件这样的话,执行make命令之后,makefile文件会指向你想要得文件,就可以编译到内核了。
但是至今没看懂,就抄一下代码:
我们要修改的是kernel/Makefile。需要修改两处。一处是:
OBJS = sched.o system_call.o traps.o asm.o fork.o \
panic.o printk.o vsprintf.o sys.o exit.o \
signal.o mktime.o
改为:
OBJS = sched.o system_call.o traps.o asm.o fork.o \
panic.o printk.o vsprintf.o sys.o exit.o \
signal.o mktime.o who.o
另一处:
### Dependencies:
exit.s exit.o: exit.c ../include/errno.h ../include/signal.h \
../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \
../include/asm/segment.h
改为:
### Dependencies:
who.s who.o: who.c ../include/linux/kernel.h ../include/unistd.h
exit.s exit.o: exit.c ../include/errno.h ../include/signal.h \
../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \
../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \
../include/asm/segment.h