哈工大操作系统(李治军)实验课实验三,添加系统调用

本文详细介绍了如何在Linux0.11操作系统中添加名为iam()和whoami()的自定义系统调用,包括修改系统调用号、实现API、更新系统调用表、编写内核函数以及编译和运行程序的步骤。iam()用于将字符串复制到内核,whoami()则将内核中的字符串复制回用户空间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 实验内容

在Linux 0.11下添加两个系统调用,并编写两个应用程序测试他们

iam()

	原型:
	int iam(const char* name);

功能为将字符串参数name的内容拷贝到内核中保存下来,要求name的长度不能超过23个字符,返回拷贝的字符数。若name的字符超过了23,返回“-1”,并置errno为EINVAL。

whoami()

原型:
int whoami(char* name,unsigned int size);

功能为将内核中由iam()保存的名字拷贝到name指向的用户地址空间中。返回值是拷贝的字符数。若size小于需要的空间,则返回“-1”,并置errno为EINVAL。

二.系统调用的过程

1. 应用程序调用API
2. API将系统调用号存入EAX,然后启用中断进入内核态
3. 中断处理函数根据系统调用号,调用对应的系统调用
4. 系统调用完成后,将返回值存入EAX,返回到中断处理函数,再返回到API
5. API将返回值返回给应用程序

三.API

3.1 API的调用过程

将系统调用的编号存入EAX,将函数参数存入其他通用寄存器,触发0x80号中断

3.2 研究close()的API

#define __LIBRARY__
#include<unistd.h>
_syscall1(int,close,int,fd)
_syscall1是一个宏,在include/unistd.h中定义

unistd.h中的syscall1
另外还有_syscall0,_syscall2,_syscall3;分别可以传递0个参数,两个参数,三个参数。所以从linux0.11 的机制来看,它的系统调用最多能传递三个参数。

其中__NR_##name会被宏替换为__NR_close,放入EAX中,这个__NR_close就是系统调用的编号,在/oslab/linux-0.11/include/unistd.h中定义
系统调用号定义
所以我们需要在include/unistd.h中添加__NR_iam()和__NR_whoami()

3.3 添加iam()的API

//iam.c
#define __LIBRARY__ //有这个_syscall1等才有效
#include<unistd.h> //帮助编译器获得系统调用的编号
_syscall1(int,iam,const char*,name);
int main(int argc,char* argv[])
{
	int len=0;
	len = iam(argv[1])//传入第一个参数
	return len;
}

3.4 添加whoami()的API

//whoami.c
#define __LIBRARY__
#include<unistd.h> 
syscall2(int,whoami,char*,name,unsigned int,size);
int main()
{
	char arr[30];
	int len=0;
	len = whoami(arr,30);
	printf("%s\n",arr);
	return len;
}

3.5 保存文件

通过挂载来实现文件交换:

在linux 0.11未在bochs下运行时,在oslab目录下,在终端输入 sudo ./mount-hdc 。挂载内核的根文件目录
系统镜像文件到ubuntu,然后在hdc目录下进行文件交换。 

注意:linux 0.11的文件系统是minix,实测cenos7不支持,建议使用ubuntu

将iam.c和whoami.c保存在oslab/hdc/usr/root目录下。

四.添加iam()和whoami()的系统调用

4.1 添加系统调用号

在oslab/hdc/include/unistd.h中添加

//这里的系统调用号,需要和后面系统调用表system_call.s中的位置相对应
#define __NR_iam	72
#define __NR_whoami	73

4.2 修改系统调用总数

在添加系统调用后,需要在kernel/system_call.s中修改nr_system_calls
system_call.s
我们添加了iam和whoami两个系统调用,所以需要将72改为74

五 在系统调用表中添加函数

在/kernel/system_call.s中,有一句代码:call sys_call_table(,%eax,4)
  根据汇编寻址方法,实际上为:call sys_call_table+4*%eax
  其中eax放的是__NR_xxname,也就是系统调用号

sys_call_table是一个函数指针数组,定义在include/linux/sys.h中

sys_call_table
我们需要在这个数组的末尾,添加72号sys_iam和73号sys_whoami,与他们的系统调用号__NR_xxname相对应。同时还要在sys.h中添加:

extern int sys_iam();
extern int sys_whoami();

六.实现sys_iam()和sys_whoami()

最后,我们需要在内核中实现系统调用的函数,并且将修改后的内核重新编译。

get_fs_byte()可以从用户态内存处取得一个字节的内容。
put_fs_byte()把一个字节的内容放到用户态内存空间中
//who.c
#include<unistd.h>
#include<string.h>
#include<errno.h>
#define __LIBRARY__

char msg[24]; //作为存放name的容器,在这里创建,处于内核态空间
int len =0;

int sys_iam(const char* name)
{
	int i =0;
	char tmp[30];
	for(i=0;i<30;i++)
	{
		tmp[i] = get_fs_byte(name+i);
		if(tmp[i]=='\0')
		{
			break;
		}
		len++;
	}
	if(len>23)
	{
		return -(EINVAL);
	}
	else
	{
		strcpy(msg,tmp);
	}
	return i;
}

sys_whoami(char* name,unsigned int size)
{
	int i =0;
	int len =0;
	if(len>size)
	{
		return -(EINVAL);
	}
	else
	{
		while(msg[i]!='\0')
		{
			put_fs_byte(msg[i],name+i);
			i++;
		}
	}
	return i;
}

我们将who.c放在oslab/linux-0.11/kernel下

七.修改Makefile文件

为了让上面的who.c可以和其他的Linux代码编译链接到一起,必须要修改Makefile文件,这个文件里记录了
所有源程序文件的编译、链接规则,make指令按照Makefile的规则编译整个代码树

添加who.o
修改OBJS下的内容

添加who.s who.o: who.c …/include/linux/kenel.h …/include/unistd.h
在这里插入图片描述

修改完毕后,在linux-0.11目录下,在终端输入make all编译内核,在显示sync时,表明编译正确完成。

八.编译运行程序

8.1编译

1 返回到oslab目录,输入 sudo umount hdc 取消挂载,
2 输入 ./run 在bochs中启动linux-0.11
3 编译程序:在bochs中输入:gcc -o iam iam.c -Wall 和 gcc -o whoami whoami.c -Wall

8.2 运行程序

输入:

./iam yunhun
./whoami

输出结果为:
在这里插入图片描述
至此实验内容完结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值