系统调用

发布时间 2024-01-09 23:05:31作者: 江水为竭

实验过程

  1. 修改include/unistd.h ,增加iamwhoami系统调用号。

image

  1. 修改 kernel/system_call.s ,将系统调用总数由72改为74。

image

  1. 修改include/linux/sys.h ,添加sys_whoamisys_iam

image

image

  1. kernel/ 目录下创建 who.c 文件。who.ccode/目录。
  2. 修改kernel/目录下的Makefile文件。

image

  1. linux-0.11 目录下执行 make all 命令,重新编译内核。
  2. 编写whoami_test.ciam_test.c测试文件,见code/目录。
  3. 挂载Linux 0.11的文件系统hdc,将whoami_test.ciam_test.ctestlab2.ctestlab2.sh4个文件移动到hdc/usr/root/
  4. 运行Bochs,进入Linux 0.11。编译运行 C语言测试文件,运行Shell测试文件。
  5. 若报错:
    image

​ 则是因为Linux 0.11文件系统中的/usr/include/unistd.h没有对应调用号,添加即可。

image

实验结果

image

实验报告

Linux 0.11 现在的机制看,它的系统调用最多能传递几个参数?

image

include/unistd.h可以看出,总共有4个系统调用的宏定义:

  1. _syscall0:无参数。
  2. _syscall1:1个参数。
  3. _syscall2:2个参数。
  4. _syscall3:3个参数。

所以,如果不算系统调用的编号的话,最多能传递 3个参数,分别通过寄存器ebxecxedx传递。

你能想出办法来扩大这个限制吗?

我的想法是,3个参数可以分别用来存放 指向参数的指针、指向参数大小的指针和参数的数量。

这样,参数的大小可以用一个字节来表示,因此,可以通过递增第二个参数的值来获取每个参数的大小。同时,第一个参数(参数指针)会根据第二个参数(参数大小)所指示的值进行移动,以便获取每个参数的值。最终,在第三个参数(参数数量)的限制下,取得所有的参数。

这种设计使得系统调用能够接收任意数量和类型的参数。

用文字简要描述向 Linux 0.11 添加一个系统调用 foo() 的步骤。

  1. include/unistd.h 中为 foo() 增加系统调用号。例如,如果当前系统调用的数量为 72,那么 foo() 的系统调用号可以定义为 73
  2. 修改 kernel/system_call.s 中的系统调用总数。例如,如果当前系统调用的数量为 72,那么添加 foo() 后,系统调用的总数应该修改为 73
  3. include/linux/sys.h 中的 sys_call_table 函数表中增加 foo() 的函数引用,使用 extern 声明系统调用函数,比如extern int sys_foo();
  4. kernel/ 目录下创建 foo.c 文件,实现 foo() 函数。这个函数将会在系统调用 foo() 时被执行。
  5. 修改 kernel/ 目录下的 Makefile 文件,使得在编译内核时能够编译 foo.c 文件。
  6. 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);
}