系统调用的工作流程探究
在线学习了孟宁老师的《Linux内核分析》课程,本章主要内容是系统调用及其工作原理。
针对本次课程的实验现记录于下:
分别利用库函数API方式和C语言嵌入汇编方式调用同一个系统调用:mkdir()
首先来熟悉一下mkdir()这个API函数的定义
原型:int mkdir (const char *filename, mode_t mode)
使用该函数需要包含头文件sys/stat.h(代码中并未加上次头文件,也能编译通过,不知道什么原因),mode 表示新目录的权限。
该API对应的是Linux内核中的39号系统调用,即库函数mkdir是对系统调用sys_mkdir的封装,sys_mkdir在系统调用表中的系统调用号是39。
1. 利用库函数API方式来调用sys_mkdir系统调用
首先我们在环境中编写代码:
#include <stdio.h> int main(int argc, char **argv) { if(argc != 2) printf("illegal parameter!!\n"); if(mkdir(argv[1]) == -1) { printf("mkdir error"); return -1; } return 0; }

在终端编译代码:
gcc c_system_call.c -o c_system_call -m32
在目录下生成32位环境的可执行文件,如图:

输入运行命令:
./c_system_call mydir1
可以看见此时在目录下生成了一个名为mydir1的目录,如图:

这样就利用API函数的方式实现了系统调用。
2. C代码中嵌入汇编代码实现系统调用
为了探究系统调用的具体过程,我们有必要利用汇编代码通过软中断来实现系统调用。
其实系统调用就是一种软中断。
在系统中断向量表中用0x80号表示系统调用中断,因此我们可以通过中断指令:
int $0x80
来向内核发送中断信号,使CPU陷入内核态。
通过eax寄存器来向内核传递系统调用号,在system_call()中转向系统调用服务程序。
我们首先编写代码如下:
#include <stdio.h> int main(int argc, char **argv) { if(argc != 2) printf("Illagel parameters!!\n"); int ret = 0; asm volatile( "mov $0, %%eax\n\t" "mov $0x27, %%eax\n\t" "int $0x80\n\t" "mov %%eax, %0\n\t" :"=m"(ret) :"b"(argv[1]) ); if(ret == -1) { printf("Mkdir Error!!\n"); return -1; } return 0; }
在实验楼环境中:

编译执行:
./asm_system_call mydir2
在当前目录下生成了mydir2目录。如图:

到此,实验结束,下面谈谈通过本次实验我对系统调用流程的理解。
3. 系统调用之我见
在Linux系统中,系统调用是用户空间访问内核的唯一手段,是内核唯一的合法入口。
为了保证系统的安全,Linux操作系统有两种指令执行级别,分别是0(内核态)和3(用户态),用户态下的指令只能访问0xC0000000以上的内存地址空间和一些非特权指令;而处于内核态下,CPU可以执行特权指令以及访问包括0x00000000 - 0xBFFFFFFF在内的所有地址空间(逻辑地址)。为了通过内核操作硬件、使用操作系统提供的服务,我们必须在内核态下执行一些指令,所以必须要从用户态转移到内核态来执行相关的指令,这就需要通过中断来实现。系统调用就是一种中断。x86体系结构上软中断是通过int $0x80指令发出的。中断发生后的第一件事就是保存现场,中断处理程序把用户态栈顶地址、当前状态字以及cs:eip的值保存在内核堆栈中。接着cs:eip的值指向系统调用处理程序system_call(),在system_call()中根据从eax寄存器接收的系统调用号,CPU跳转到系统调用服务程序中实现具体的处理。因而在内核中有一张系统调用表,表中每个系统调用都有唯一的系统调用号,存储在sys_call_table中。它与体系结构有关,一般在entry.s中定义。
除了要通过eax寄存器传递系统调用号以外,还需要一些外部的参数输入。最简单的办法就是像传递系统调用号一样把这些参数也存放在寄存器里。在x86系统上ebx,ecx,edx,esi和edi按照顺序存放前5个参数。多于六个参数时用一个单独的寄存器存放指向所有这些参数在用户空间地址的指针。给用户空间的返回值通过eax寄存器传递。
具体的系统调用流程见下图:

本次实验中很多细节问题没有弄清楚,还要靠以后继续学习。
2015-03-29 21:13:08
Allen 原创作品转载请注明出处 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
浙公网安备 33010602011771号