0%

系统调用

系统调用

知识储备

应用程序如何调用系统调用

在通常情况下,调用系统调用和调用一个普通的自定义函数在代码上并没有什么区别,但调用后发生的事情有很大不同。

调用自定义函数是通过 call 指令直接跳转到该函数的地址,继续运行。

而调用系统调用,是调用系统库中为该系统调用编写的一个接口函数,叫 API(Application Programming Interface)。API 并不能完成系统调用的真正功能,它要做的是去调用真正的系统调用,过程是:

把系统调用的编号存入 EAX;
把函数参数存入其它通用寄存器;
触发 0x80 号中断(int 0x80)。
linux-0.11 的 lib 目录下有一些已经实现的 API。Linus 编写它们的原因是在内核加载完毕后,会切换到用户模式下,做一些初始化工作,然后启动 shell。而用户模式下的很多工作需要依赖一些系统调用才能完成,因此在内核中实现了这些系统调用的 API。
为什么要有内核态和用户态两种状态?

因为有些操作很危险,比如清空内存,I/O等,不能随便一个程序就能进行这样的操作。所以区分出内核态与用户态,用户态可以执行一些不危险的操作,当需要执行危险操作时,需要通过系统调用等方法进入内核态执行。

实验过程

1.修改linux-0.11/include/linux/sys.h

需要把 iam()whoami() 两个函数声明为全局变量,并添加到中断函数表中,当中断被调用的时候,先查找中断向量表,找到相应的函数名,调用其函数。

image-20220523192718134

2.修改系统调用数

system_call.slinux-0.11/kernel
需要把nr_system_calls 由72改为 74 表示了中断函数的个数。

image-20220523192844373

3.新增系统调用号

需要在unistd.h 中修改,但是实验后发现行不通,查阅后发现需要在linux系统中修改。

运行 sudo ./mount-hdc 可以把虚拟机硬盘挂载在 oslab/hdc 目录下。
hdc/usr/include 目录下修改 unistd.h

image-20220523193158462

4.新增 who.c 文件,实现系统调用的函数

将完成的who.c文件放入linux-0.01/kernel 目录下

image-20220523210811801

image-20220523210825948

5.修改makefile

共有两处

image-20220523193418730

image-20220523193435486

6.新增 iam.c 和 whoami.c 文件以测试系统调用是否添加成功

iam.c

image-20220523193643654

whoami.c

image-20220523193550834

同理需要在linux0.11下编译

1
2
3
sudo ./mount-hdc 
cp ./iam.c hdc/usr/root
cp ./whoami.c hdc/usr/root

然后./run

7.编译 iam.c 跟 whoami.c

1
2
gcc -o iam iam.c 
gcc -o whoami whoami.c

image-20220523203159191

实验结果

image-20220523192418659

以及两个测试结果

image-20220523193847193

image-20220523193923766

问题回答

一、

  • Linux 0.11 现在的机制看,它的系统调用最多能传递几个参数?
1
Linux-0.11的系统调用通过寄存器ebx、ecx、edx传递参数,最多能传递3个参数。

二、

  • 你能想出办法来扩大这个限制吗?
1
2
3
4
1.增加传参所用的寄存器
2.通过定义结构体,在结构体中存入很多参数,然而只把结构体入口地址作为参数进行传递;
3.或者就利用这三个寄存器,重复传值
4.或者将寄存器进行拆分,根据需要不同位传值

三、

  • 用文字简要描述向 Linux 0.11 添加一个系统调用 foo() 的步骤。
1
2
3
4
5
1.在include/unistd.h中定义宏__NR_foo,并添加供用户调用的函数声明void foo();
2.修改kernel/system_call.s中的nr_system_calls,使其增加1;
3.在include/linux/sys.h中添加函数声明extern void sys_foo(),在系统调用入口表fn_ptr末端添加元素sys_foo;
4.添加kernel/foo.c文件,实现sys_foo()函数;
5.修改kernel/Makefile,在OBJS中加入foo.o,并添加生成foo.s、foo.o的依赖规则。

问题

记录一个只有自己遇到的问题,当我对于Linux0.11文件进行make时,发现会报错,具体错误如下,

image-20220523205611785

当我调试后发现,问题出自linux/kernel/chr_drv处

当我用一个新的该文件,只在chr_drv下make时,会出现

image-20220523205822630

于是我make clean,再进行make,会出现下面的错误make

image-20220523205901514

这两个问题分别对应于上面提到的那两个问题。

目前我没有找出这个问题的原因,我所采用的解决办法是,在其他机子上先对chr_drv文件进行编译,然后进行替换,则可以解决问题。困惑…