《Linux内核分析》MOOC课程
http://mooc.study.163.com/course/USTC-1000029000
一、 使用C和内嵌汇编方式完成系统调用
我使用了39号系统调用sys_mkdir来进行实验。
<number> <abi> <name> <entry point>
39 i386 mkdir sys_mkdir
mkdir函数使用的是39号系统调用,作用是新建一个目录。
mkdir使用头文件库:
#include <sys/stat.h>
函数原型:
int mkdir(const char *pathname, mode_t mode);
函数说明:
mkdir()函数以mode方式创建一个以参数pathname命名的目录,mode定义新创建目录的权限。
我们使用mode_t值为S_IRWXU来创建目录,
也就是00700权限,代表该文件所有者拥有读,写和执行操作的权限。
1、 使用C语言创建文件如下:
#include <sys/stat.h>
int main()
{
mkdir("new dir", S_IRWXU);
return 0;
}
当我们编译运行时,发现生成了一个新目录new dir,权限是rwx---------也就是700权限。
2、 使用内联汇编方式进行系统调用
#include <stdio.h>
#include <sys/stat.h>
int main()
{
char *dirName = "new dirAsm";
mode_t mode = S_IRWXU;
int returnValue = 0;
asm
(
"movl $39, %%eax\r\n" /*将39号系统调用号放到eax寄存器中*/
"movl %1, %%ebx\r\n"/*将第一个参数文件名的地址,存入ebx寄存器*/
"movl %2, %%ecx\r\n"/*将第二个参数文件夹的访问权限存入ecx寄存器*/
"int $0x80\r\n"
"movl %%eax, %0"/*最后将返回值放入returnValue变量中*/
:"=m"(returnValue)
:"d"(dirName),"D"(mode)/*使用edx寄存器保存dirName的地址,edi保存mode*/
);
printf("%d\n",returnValue);
return 0;
}
我们编译执行这段代码后,发现新建了一个new dirAsm的目录,访问权限仍然是rwx---------,也就是700权限,所以使用内联汇编进行int $0x80软中断得到了和调用API一样的效果。
二、 系统调用的工作机制
1.内核态与用户态
Linux系统分为内核态和用户态。普通的程序运行在用户态,当用户需要进行一些控制硬件的操作,读取内核状态,或者进程管理等操作的时候
,则需要用到系统调用来使用内核态的一些功能。
系统调用不仅可以方便编程,增加可移植性,又可以提高系统的安全性。
Linux实现系统调用则是利用了i386体系结构的软件中断,使用int $0x80产生128号向量的编程异常,CPU便切换到内核态。
2.API与系统调用
API只是一个函数定义,系统调用是通过软中断向内核发出一个明确的请求。
但是有的API是封装了软中断的一个函数,便于编程使用。
例如上面的mkdir函数,便是封装了39号系统调用,当调用mkdir函数时,会产生一个39号的系统调用。
3.系统调用的过程
上面的mkdir系统调用,可以使用下面的图来表示:
(1) 首先用户调用mkdir API
(2) 在API的具体实现里面会调用39号系统调用,使用int $80软中断进入内核态
(3) 此时会压入用户的栈顶地址,当前状态字,和CS:EIP。
(4) 然后使用SAVE ALL保存现场,内核进程根据用户的系统调用号,查找系统调用表(sys_call_table),找到中断处理子程序的地址,并且进入内核函数
(5) 完成调用中断处理子程序后,使用RESTORE ALL还原现场,返回调用的用户态空间
三、 总结
通过进行实验,并且对系统调用过程的分析,了解了系统调用是用户操作系统硬件等内核态操作的桥梁以及了解了系统调用的工作过程。