一、实验目的
建立对系统调用接口的深入认识;
掌握系统调用的基本过程;
能完成系统调用的全面控制;
为后续实验做准备。
二、实验步骤
1.修改unistd.h 图片描述 其中新增代码为
2.修改include/linux/sys.h 进入/home/shiyanlou/oslab/linux-0.11/中修改,有两个点需要修改:
1)仿照前面各个系统调用的写法,添加如下代码
extern int sys_iam();
extern int sys_whoami();
2)在sys_call_table中新加两个系统调用:
sys_iam,sys_whoami()
3.修改system_call.s 把nr_system_call的值从72改成74,因为我们加了两个系统调用
4.修改Makefile Makefile 在代码树中有很多,分别负责不同模块的编译工作。我们要修改的是 kernel/Makefile。需要修改两处。
(1)第一处
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 添加了 who.o。
(2)第二处
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
5.编写3个.c文件
1)who.c
#define LIBRARY
#include<unistd.h>
#include <errno.h>
#include<asm/segment.h>
#include<linux/kernel.h>
char tmp[64] = {0};
int sys_iam(char * name){
int k = 0;
while(get_fs_byte(name+k)!=’\0’)
k++;
if (k>23){
return -EINVAL;
}
else{
int i = 0;
while((tmp[i]=get_fs_byte(name+i))!=’\0’)
i++;
return k;
}
}
int sys_whoami(char * name, unsigned int size){
int i = 0;
while(tmp[i]!=’\0’){
i++;
}
if (size<i){
return -EINVAL;
}
i = 0;
while(tmp[i]!='\0'){
put_fs_byte(tmp[i],name+i);
i++;
}
return i;
}
然后是两个测试程序
2)iam.c
#define LIBRARY
#include <unistd.h>
_syscall1(int,iam,char*,name)
int main(int argc,char * argv[])
{
iam(argv[1]);
return 0;
}
3)whoami.c
#define LIBRARY
#include <unistd.h>
#include<stdio.h>
_syscall2(int,whoami,char*,name,unsigned int,size)
char arr[24];
int main()
{
whoami(arr,24);
printf("%s",arr);
return 0;
}
6.挂载Linux,并在/usr/include/unistd.h文件中添加两个宏定义:
#define __NR_iam 72
#define __NR_whoami 73
三、实验结果
1.运行testlab2.c,得分为50% 图片描述
2.运行testlab2.sh,得分30% 图片描述
四.两个问答题:
1.从 Linux 0.11 现在的机制看,它的系统调用最多能传递几个参数?你能想出办法来扩大这个限制吗?
查看linux-0.11/include/unistd.h,可看到最多只能传递3个参数;
扩大限制的方法:
i)定义一个结构体,这个结构体里面可以有很多参数,然后把结构体的入口地址当作参数进行传递
ii)用ebx,edx,ecx循环传值
iii)再加几个寄存器,比如edi,esi,ebp等
2.用文字简要描述向 Linux 0.11 添加一个系统调用 foo() 的步骤.
主要分成三个部分
1)修改Linux内核文件
2)在kernel文件夹下实现系统调用,并执行make all指令把新的系统调用加入到内核中
3)挂载Linux,并修改/usr/include/unistd.h
下面是详细的步骤
1)修改Linux内核文件
a.修改linux-0.11/include/unistd.h,增加如下代码:
#define __NR_foo 72
b.修改linux-0.11/include/linux/sys.h
添加代码:
extern int sys_foo();
并在sys_call_table表中新增一个系统调用
sys_foo
c.修改linux-0.11/kernel/system_call.s中的nr_system_calls,使其增加1
d.修改linux-0.11/kernel/Makefile,在OBJS中添加foo.o,并添加生成foo.s和foo.o的依赖规则
2)在kernel文件夹下通过foo.c实现sys_foo()
3)在Ubuntu中挂载Linux系统,进入/usr/include/unistd.h中添加__NR_foo的宏定义
五、实验收获
了解了系统调用的详细过程,了解了数据在用户和内核之间传送的方法