Linux内核分析学习笔记:system_call中断处理过程
2016-03-27 17:33
423 查看
原创内容(陈晓爽 cxsmarkchan)
转载请注明出处
《Linux内核分析》MOOC课程 学习笔记
前两篇博文从汇编的角度分析了linux系统的系统调用方法,本博客在实验楼平台下写了一个简单的系统调用程序,并分析系统调用的实际过程。
在实验平台下,切换到
运行
该系统中仅有3个命令,分别是
打开
可见main函数中给出了命令和对应函数。此处不再关心
其中,cmd为命令名称,desc为命令说明(在help中显示),handler是命令处理程序。
将main函数改写如下:
这样就添加了两条命令。接下来,给出
这段代码也不再解释,可以参照前一篇博文用asm内联汇编实现系统调用。
添加了如下代码后,运行系统,点击help命令,就会出现更多的选择。同时,write命令和write-asm命令都可以执行,其功能是将参数表中的所有内容按顺序输出,并自动添加换行。
运行效果如下图:
遗憾的是,entry_32.S是一段汇编代码,system_call也不是一个函数,只是一个程序入口标志。因此,无法用gdb来对代码进行单步调试。因此,我们仅通过汇编代码的分析来了解系统调用的过程。
系统调用的汇编代码可以简化如下,其中省略了部分代码:
在该段代码执行时,系统已经进入内核态。该段代码首先通过
值得注意的是,在返回之前,系统还会根据情况,决定是否要调用
根据中断号和中断向量表,跳转到相应的中断处理程序;
在中断开始的时候保存中断现场,在中断结束的时候恢复中断现场;
中断结束时通过iret返回到中断发生前的程序执行位置;
同时,在系统调用的过程中,还会根据
转载请注明出处
《Linux内核分析》MOOC课程 学习笔记
前两篇博文从汇编的角度分析了linux系统的系统调用方法,本博客在实验楼平台下写了一个简单的系统调用程序,并分析系统调用的实际过程。
1 实验内容
本文实验平台为实验楼Linux内核分析的第5个实验:分析system_call中断处理过程。在实验平台下,切换到
~/LinuxKernel/menu文件夹下。该文件夹下的内容会被写入磁盘镜像
rootfs.img中。Linux加载磁盘后,启动的第一个用户态进程(可参考linux内核分析学习笔记:用gdb跟踪linux内核启动过程)即在该文件夹的test.c中。
运行
make rootfs,可以编译并启动系统,结果如下:
该系统中仅有3个命令,分别是
help,
version,
quit。下面在该系统中添加两个命令:
write和
write-asm。顾名思义,这两个函数是系统调用
sys_write的C语言版本和汇编版本。
打开
test.c,可以看到main函数如下:
int main() { PrintMenuOS(); SetPrompt("MenuOS>>"); MenuConfig("version","XXX V1.0(Menu program v1.0 inside)",NULL); MenuConfig("quit","Quit from XXX",Quit); ExecuteMenu(); }
可见main函数中给出了命令和对应函数。此处不再关心
SetPrompt和
ExecuteMenu函数的细节(与Linux操作系统无关),只需了解
MenuConfig函数的定义如下:
int MenuConfig(char *cmd, char *desc, int (*handler)());
其中,cmd为命令名称,desc为命令说明(在help中显示),handler是命令处理程序。
将main函数改写如下:
int main() { PrintMenuOS(); SetPrompt("MenuOS>>"); MenuConfig("version","XXX V1.0(Menu program v1.0 inside)",NULL); MenuConfig("quit","Quit from XXX",Quit); MenuConfig("write", "Print to screen", Write); MenuConfig("write-asm", "Print to screen(asm)", Write_asm); ExecuteMenu(); }
这样就添加了两条命令。接下来,给出
Write和
Write_asm函数:
int Write(int argc, char *argv[]){ int i; for(i = 1; i < argc; i++){ write(0, argv[i], strlen(argv[i])); write(0, "\n", 1); } return 0; } void Write_asm(int argc, char *argv[]){ int i; int len; char *str; for(i = 1; i < argc; i++){ len = strlen(argv[i]); str = argv[i]; asm volatile( "int $0x80\n\t" "mov $4, %%eax\n\t" "mov $0, %%ebx\n\t" "mov %4, %%ecx\n\t" "mov $1, %%edx\n\t" "int $0x80\n\t" : :"a"(4), "b"(0), "c"(str), "d"(len), "D"("\n") ); } return 0; }
这段代码也不再解释,可以参照前一篇博文用asm内联汇编实现系统调用。
添加了如下代码后,运行系统,点击help命令,就会出现更多的选择。同时,write命令和write-asm命令都可以执行,其功能是将参数表中的所有内容按顺序输出,并自动添加换行。
运行效果如下图:
2 系统调用的过程
下面分析系统调用的过程。在汇编代码中,我们通过int $0x80产生中断,系统会在中断向量表中查找相应的中断处理函数。
0x80对应的函数即为系统调用函数
system_call,位于
arch/x86/kernel/entry_32.S。
遗憾的是,entry_32.S是一段汇编代码,system_call也不是一个函数,只是一个程序入口标志。因此,无法用gdb来对代码进行单步调试。因此,我们仅通过汇编代码的分析来了解系统调用的过程。
系统调用的汇编代码可以简化如下,其中省略了部分代码:
ENTRY(system_call) #…… SAVE_ALL #…… syscall_call: call *sys_call_table(,%eax,4) syscall_after_call: movl %eax,PT_EAX(%esp) # store the return value syscall_exit: #…… movl TI_flags(%ebp), %ecx testl $_TIF_ALLWORK_MASK, %ecx # current->work jne syscall_exit_work restore_all: TRACE_IRQS_IRET #…… irq_return: INTERRUPT_RETURN ENDPROC(system_call)
在该段代码执行时,系统已经进入内核态。该段代码首先通过
SAVE_ALL宏保存现场,接下来根据
eax寄存器的内容,查找
sys_call_table表,跳转到合适的系统调用,并把返回值存入
eax寄存器中。完成这一步之后,系统调用就基本结束了,会执行restore_all部分的代码恢复现场,最后执行
iret(此处即为
INTERRUPT_RETURN)返回到中断调用的位置,继续执行。
值得注意的是,在返回之前,系统还会根据情况,决定是否要调用
syscall_exit_work函数。该函数的意义在于退出系统调用前,执行一些清理工作。其中最重要的工作是进程调度,这是因为有些系统调用函数可能会改变进程执行情况,例如挂起当前进程。此时,在该函数中就会调用进程调度函数,实现进程切换。
3 小结
系统调用处理过程本质是一种中断过程,因此遵循中断处理的一些共性,包括:根据中断号和中断向量表,跳转到相应的中断处理程序;
在中断开始的时候保存中断现场,在中断结束的时候恢复中断现场;
中断结束时通过iret返回到中断发生前的程序执行位置;
同时,在系统调用的过程中,还会根据
eax寄存器中存储的系统调用号,进一步查找系统调用表,执行系统调用操作。系统调用结束后,程序会根据系统调用的结果,进行一些收尾工作,例如进程调度等,最后退出内核态,返回用户态。
相关文章推荐
- Linux就这个范儿 第14章 身在江湖
- CentOS系列开机启动流程
- Linux 进程查看命令 ps top htop dstat
- Linux下MySQL备份以及crontab定时备份
- linux内核分析作业5:分析system_call中断处理过程
- 《Linux内核设计与实现》读书笔记 18
- 《Linux内核设计与实现》读书笔记 5
- 《Linux内核设计与实现》读书笔记 1&2
- linux下的进程管理
- linux进程管理
- linux下swap分区的作用
- Linux内核分析第五周——扒开系统调用的“三层皮”(下)
- linux下搭建生成HLS所需的.ts和.m3u8文件
- Linux常用命令
- Ubuntu Linux下搭建LAMP服务器环境
- 《Linux内核设计与实现》第五周读书笔记——第十一章
- [linux basic 基础]----同步互斥量
- linux及安全第五周总结
- Linux 修改系统时间 需要Root权限
- linux内核设计与实现一书阅读整理 之第十八章