【操作系统】实验楼操作系统实验三——系统调用
操作系统实验3——系统调用环境配置首先同样是配置环境cd /home/shiyanlou/oslabtar -zxvf hit-oslab-linux-20110823.tar.gz -C /home/shiyanlou实验步骤添加函数声明cd ~/oslab/linux-0.11/include/linuxgedit sys.h//添加内容:extern int sys_whoami();ex
操作系统实验3——系统调用
环境配置
首先同样是配置环境
cd /home/shiyanlou/oslab
tar -zxvf hit-oslab-linux-20110823.tar.gz -C /home/shiyanlou
实验步骤
添加函数声明
cd ~/oslab/linux-0.11/include/linux
gedit sys.h
//添加内容:
extern int sys_whoami();
extern int sys_iam();
fn_ptr_sys_call_table[]={...sys_whoami,sys_iam}
首先找到sys.h
,在其中加入函数声明和系统调用。添加后结果如下图:
挂载虚拟机添加函数调用
由于需要在unistd.h
中新增系统调用号,而该文件不能在oslab
中直接进行修改,因此首先运行sudo ./mount-hdc
把虚拟机硬盘挂载在oslab/hdc
目录下,然后在hdc/usr/include
目录下修改unistd.h
。
cd ../../../
sudo ./mount-hdc
cd ./hdc/usr/include
gedit unistd.h
//添加内容:
//系统调用声明:
#define __NR_whoami 72
#define __NR_iam 73
位置即结果如图2所示:
由于添加了两个系统调用,我们需要在system_call.s
中修改系统总调用使数量+2。
cd ../../../
cd ./linux-0.11/kernel/
gedit system_call.s
//添加内容:
nr_system_calls = 74
位置及结果如图3:
创建操作系统文件
通过前面的操作,我们已经可以从用户态的iam()
来调用sys_iam()
了,现在需要创建一个操作系统文件who.c
,在其中我们可以实现内核函数sys_iam()
。
//此时已经在kernel目录下
gedit who.c
//who.c代码:
#include <string.h>
#include <errno.h>
#include <asm/segment.h>
char msg[24];
int sys_iam(const char * name)
{
char tep[26];
int i = 0;
for(; i < 26; i++)
{
tep[i] = get_fs_byte(name+i);
if(tep[i] == '\0') break;
}
if (i > 23) return -(EINVAL);
strcpy(msg, tep);
return i;
}
int sys_whoami(char * name, unsigned int size)
{
int len = 0;
for (;msg[len] != '\0'; len++);
if (len > size)
{
return -(EINVAL);
}
int i = 0;
for(i = 0; i < size; i++)
{
put_fs_byte(msg[i], name+i);
if(msg[i] == '\0') break;
}
return i;
}
sys_iam
用get_fs_byte()
从name
指向的内存缓存区中获取数据,然后将这些数据按字节逐个存放在内核缓存区kernelname
中。因为name
中存放的名字是一段用户态内存缓存区,所以只能使用FS作为段寄存器,get_fs_byte()
用来从用户态内存缓存区中取出一个字节。
编译操作系统
在一切都准备好了之后,我们需要重新编译操作系统来产生系统镜像文件,并用新的镜像文件启动Bochs
。为了让who.c
文件可以和其它Linux代码编译链接到一起,我们需要修改Makefile
文件。其中此处需要修改的是kernel/Makefile
。
//修改内容:
//第一处:
OBJS=...who.o
//第二处:
who.s who.o: who.c ../include/linux/kernel.h ../include/unistd.h
exit.s exit.o: exit.c ../include/errno.h ...
修改位置如图4:
修改完后,退回linux-0.11
目录下,运行make all
指令编译内核,这样就能把who.c
加入到内核中。此时用新生成的镜像文件启动Bochs引导出的操作系统就拥有了iam
和whoami
两个系统调用。
//此时位置为~/oslab/linux-0.11/kernel
cd ../
make all
测试文件编译
在前面我们已经把虚拟机挂载在硬盘上了,为了测试新的操作系统,我们需要进入hdc/user/root
目录中(虚拟机开机所在目录)创建iam.c
和whoami.c
。
//进入目录cd ../cd ./hdc/usr/root
gedit iam.c//编写iam.c:#define __LIBRARY__ #include <unistd.h>_syscall1(int,iam,const char*,name);int main(int argc,char* argv[]){ iam(argv[1]); return 0;}
gedit whoami.c//编写whoami.c:#define __LIBRARY__#include <unistd.h>#include <stdio.h>_syscall2(int, whoami, char*, name, unsigned int, size);int main(int argc, char ** argv){ char t[30]; whoami(t, 30); printf("%s\n", t); return 0;}
此外,还可以把/home/teacher
目录下的两个测试的脚本文件testlab2.c
和testlab2.sh
加入测试,需要将其移入目录里。
//此时位置是./hdc/usr/rootcp /home/teacher/testlab2.c ./cp /home/teacher/testlab2.sh ./
此时设置文件已经全部处理好,可以运行虚拟机。
运行操作系统
运行操作系统需要回到~/oslab
目录下。
cd ../../.././run
在Bochs虚拟机中对文件进行编译并运行:
//编译文件gcc -o iam iam.cgcc -o whoami whoami.cgcc -o testlab2 testlab2.c//进行系统调用./iam zhoujinchunwhoami
系统调用运行结果如图5所示,成功输出我的名字:
此外,我们还可以运行脚本文件(实验给的评分用例,满分分别为50%和30%)来测试:
./testlab2./testlab2.sh
运行结果如图6所示,可见最后iam.c
满分,为50%,whoami.c
满分,为30%。实验完成。
问题回答
一. 从 Linux 0.11 现在的机制看,它的系统调用最多能传递几个参数?你能想出办法来扩大这个限制吗?
-
Linux-0.11的系统调用通过寄存器
ebx
、ecx
、edx
传递参数,最多能传递3个参数。 -
扩大传递参数的数量的方法:
(1)增加传参所用的寄存器,但现实不太适用;
(2)用这3个寄存器循环传值;
(3)将寄存器拆分为高位和低位传递一直比较小的参数;
(4)利用堆栈传递参数。
二. 用文字简要描述向 Linux 0.11 添加一个系统调用 foo()
的步骤。
- 在
include/unistd.h
中定义宏__NR_foo
,并添加函数声明和函数调用。 - 在
kernel/system_call.s
修改总调用数,使nr_system_calls
数值加1。 - 在
include/linux/sys.h
中添加函数声明extern void sys_foo()
,在系统调用入口表fn_ptr
末端添加元素sys_foo
; - 在内核文件中添加
kernel/foo.c
文件,实现sys_foo()
函数。 - 修改
kernel/Makefile
,在OBJS
中加入foo.o
,并添加生成foo.s
、foo.o
的依赖规则。 - 退回
linux-0.11
目录下,运行make all
指令编译内核,这样就能把foo.c
加入到内核中。
课后习题二
一.针对2.2.1节中输出A、B、C的思考题,仿照图2.1画出进程创建关系,并给出输出相应字符的位置。
答:
二.针对实践项目2,画出一个完整的工作流程图,即第一步做了什么,产生了什么;第二步做了什么,产生了什么,如此等等。
答:(由于本作业的实验步骤部分的部分步骤是根据蓝桥云课实验楼的特殊环境添加的,单纯针对书上的实践项目2的步骤在流程图中仅写出了必需的步骤。)
更多推荐
所有评论(0)