系统调用
知识储备
应用程序如何调用系统调用
在通常情况下,调用系统调用和调用一个普通的自定义函数在代码上并没有什么区别,但调用后发生的事情有很大不同。
调用自定义函数是通过 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()
两个函数声明为全局变量,并添加到中断函数表中,当中断被调用的时候,先查找中断向量表,找到相应的函数名,调用其函数。
2.修改系统调用数
system_call.s
在 linux-0.11/kernel
中
需要把nr_system_calls
由72改为 74 表示了中断函数的个数。
3.新增系统调用号
需要在unistd.h
中修改,但是实验后发现行不通,查阅后发现需要在linux系统中修改。
运行 sudo ./mount-hdc
可以把虚拟机硬盘挂载在 oslab/hdc
目录下。
在 hdc/usr/include
目录下修改 unistd.h
4.新增 who.c 文件,实现系统调用的函数
将完成的who.c文件放入linux-0.01/kernel 目录下
5.修改makefile
共有两处
6.新增 iam.c 和 whoami.c 文件以测试系统调用是否添加成功
iam.c
whoami.c
同理需要在linux0.11下编译
1 | sudo ./mount-hdc |
然后./run
7.编译 iam.c 跟 whoami.c
1 | gcc -o iam iam.c |
实验结果
以及两个测试结果
问题回答
一、
- 从
Linux 0.11
现在的机制看,它的系统调用最多能传递几个参数?
1 | Linux-0.11的系统调用通过寄存器ebx、ecx、edx传递参数,最多能传递3个参数。 |
二、
- 你能想出办法来扩大这个限制吗?
1 | 1.增加传参所用的寄存器 |
三、
- 用文字简要描述向
Linux 0.11
添加一个系统调用foo()
的步骤。
1 | 1.在include/unistd.h中定义宏__NR_foo,并添加供用户调用的函数声明void foo(); |
问题
记录一个只有自己遇到的问题,当我对于Linux0.11文件进行make时,发现会报错,具体错误如下,
当我调试后发现,问题出自linux/kernel/chr_drv处
当我用一个新的该文件,只在chr_drv下make时,会出现
于是我make clean,再进行make,会出现下面的错误make
这两个问题分别对应于上面提到的那两个问题。
目前我没有找出这个问题的原因,我所采用的解决办法是,在其他机子上先对chr_drv文件进行编译,然后进行替换,则可以解决问题。困惑…