实验过程
- 修改
include/unistd.h
,增加iam
和whoami
系统调用号。
- 修改
kernel/system_call.s
,将系统调用总数由72改为74。
- 修改
include/linux/sys.h
,添加sys_whoami
和sys_iam
。
- 在
kernel/
目录下创建who.c
文件。who.c
见code/
目录。 - 修改
kernel/
目录下的Makefile
文件。
- 在
linux-0.11
目录下执行make all
命令,重新编译内核。 - 编写
whoami_test.c
和iam_test.c
测试文件,见code/
目录。 - 挂载
Linux 0.11
的文件系统hdc
,将whoami_test.c
、iam_test.c
、testlab2.c
和testlab2.sh
共4个文件移动到hdc/usr/root/
。 - 运行
Bochs
,进入Linux 0.11
。编译运行 C语言测试文件,运行Shell测试文件。 - 若报错:
则是因为Linux 0.11
文件系统中的/usr/include/unistd.h
没有对应调用号,添加即可。
实验结果
实验报告
从 Linux 0.11
现在的机制看,它的系统调用最多能传递几个参数?
从include/unistd.h
可以看出,总共有4个系统调用的宏定义:
_syscall0
:无参数。_syscall1
:1个参数。_syscall2
:2个参数。_syscall3
:3个参数。
所以,如果不算系统调用的编号的话,最多能传递 3个参数,分别通过寄存器ebx
,ecx
,edx
传递。
你能想出办法来扩大这个限制吗?
我的想法是,3个参数可以分别用来存放 指向参数的指针、指向参数大小的指针和参数的数量。
这样,参数的大小可以用一个字节来表示,因此,可以通过递增第二个参数的值来获取每个参数的大小。同时,第一个参数(参数指针)会根据第二个参数(参数大小)所指示的值进行移动,以便获取每个参数的值。最终,在第三个参数(参数数量)的限制下,取得所有的参数。
这种设计使得系统调用能够接收任意数量和类型的参数。
用文字简要描述向 Linux 0.11
添加一个系统调用 foo()
的步骤。
- 在
include/unistd.h
中为foo()
增加系统调用号。例如,如果当前系统调用的数量为72
,那么foo()
的系统调用号可以定义为73
。 - 修改
kernel/system_call.s
中的系统调用总数。例如,如果当前系统调用的数量为72
,那么添加foo()
后,系统调用的总数应该修改为73
。 - 在
include/linux/sys.h
中的sys_call_table
函数表中增加foo()
的函数引用,使用extern
声明系统调用函数,比如extern int sys_foo();
。 - 在
kernel/
目录下创建foo.c
文件,实现foo()
函数。这个函数将会在系统调用foo()
时被执行。 - 修改
kernel/
目录下的Makefile
文件,使得在编译内核时能够编译foo.c
文件。 - 在
linux-0.11
目录下执行make all
命令,重新编译内核。
源代码
iam_test.c
#define __LIBRARY__
#include <unistd.h>
_syscall1(int, iam, const char*, name);
int main(int argc, char* argv[])
{
iam(argv[1]);
return 0;
}
who.c
#include <string.h>
#include <asm/segment.h>
#include <errno.h>
#include <linux/kernel.h>
char my_name[24] = {0};
int sys_iam(const char* name)
{
printk("<sys_iam>\n");
char temp_name[24];
unsigned int i = 0;
for (i = 0; i < 24; i = i + 1)
{
temp_name[i] = get_fs_byte(name + i);
if (temp_name[i] == '\0') break;
}
if (i == 24 && temp_name[23] != '\0')
{
return -EINVAL;
// _syscall1
}
strcpy(my_name, temp_name);
return i;
}
int sys_whoami(char* name, unsigned int size)
{
printk("<sys_whoami>\n");
unsigned name_len = strlen(my_name);
if (name_len > size) {
return -EINVAL;
}
unsigned int i = 0;
for (i = 0; i < name_len; i = i + 1)
{
put_fs_byte(my_name[i], name + i);
}
return name_len;
}
whoami_test.c
#define __LIBRARY__
#include <unistd.h>
#include <stdio.h>
_syscall2(int, whoami, char*, name, unsigned int, size);
int main()
{
char username[32] = {0};
int username_len = whoami(username, 31);
printf("%s\n",username);
}