先上运行结果:
可以看到,是成功实现所需功能的了
一、实验目的
建立对系统调用接口的深入认识;
掌握系统调用的基本过程;
能完成系统调用的全面控制;
为后续实验做准备。
二、实验步骤
1.修改unistd.h
其中新增代码为
#define __NR_iam 72
#define __NR_whoami 73
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.修改kernel/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;
}
三、注意事项
1)进入/home/shiyanlou/oslab/linux-0.11
目录中才能执行make all
指令
2)/home/shiyanlou/oslab/linux-0.11/include/asm/segment.h
中的put_fs_XXX
和get_fs_XXX
是用户空间和内核空间之间沟通的桥梁,以后还会用到
3)我在who.c
里用string.h
中的strlen
函数时会在运行iam
可执行文件时出现段错误,不清楚原因
4)sys_XXX(type arg1,...)
是内核态,而其参数arg1
是用户态的地址数据,要在内核态中获得参数中的地址数据,就需要通过get_fs_byte(arg1)
函数获取,此时.c文件需要包含头文件asm/segment.h
四、实验结果
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的宏定义
六、补充
1.我们通过open()来分析一下,用户和内核是怎么传数据的:
1)系统调用是用eax,ebx,ecx,edx
来传递参数的
2)open所传递的文件名指针是由ebx
传递。也就是说,进入内核后,我们通过ebx
取出文件名字符串。但是,open
的ebx
指向的数据在用户空间,而当前要执行的是内核空间的代码,如何把用户空间中的ebx
中的数据传到内核空间中?
3)然后接着看open
的处理,获取用户地址空间(用户数据段)中的数据靠的是fs段寄存器,然后就通过sys_call_table
表,跳转去执行sys_open()
4)在sys_open()
中,将参数依次传递给了open_namei(),dir_namei(),get_dir()
,最后,我们在get_dir()
中可看到以下代码:
static struct m_inode * get_dir(const char * pathname)
{
……
if ((c=get_fs_byte(pathname))=='/') {
……
}
……
}
get_dir
再往后,就没有函数了,所以一定是在这里完成了用户空间和内核空间的数据传送,这个传送,用的就是get_fs_byte
,这个方法能够获取用户空间中一个字节的数据
5)所以,用户空间往内核空间传数据,用的是get_fs_byte
;顺带一提,内核往用户空间传数据,用的是put_fs_byte()
七、参考博客
1.https://www.cnblogs.com/XiangfeiAi/p/4745548.html
2.https://blog.csdn.net/ccshijtgc/article/details/60327339
3.https://blog.csdn.net/wangyi_lin/article/details/6921110