网易云课堂《Linux内核分析》MOOC课程:http://mooc.study.163.com/course/USTC-1000029000,欢迎前往共同学习。
一、课堂内容概述
在本讲中,继续上节内容,先是讲述了如何将自己编写的系统调用程序加载到MenuOS系统中。主要分为以下几步:
1、删除原有MenuOS系统,用github clone新版MenuOS。主要指令如下:
rm menu -rf
git clone https://github.com/mengning/menu.git
2、将上节课完成的系统调用函数添加到 menu 目录下的 test.c 中:添加 MenuConfig 及相应的系统调用函数。
3、在 menu 目录下,重新编译 MenuOS 系统。
make rootfs
编译完成后,MenuOS 系统会自动启动。与旧版相比,新版主要是增加了 time 与 timeasm 这两个课堂实例 。
接下来,就是使用 gdb 跟踪 新增函数的系统调用过程了。这一部分,我结合自己的实例来加以说明与分析。
二、添加自定义系统调用函数,重新编译 MenuOS
在上节课中,我实验的系统调用是执行删除目录功能的 rmdir 函数。现将其加入到 MenuOS 系统的 test.c中,代码如下:
代码修改完毕,重新编译 MenuOS系统,以使新增函数生效。
由 help 命令可知,新的函数已经添加到系统命令中了,本想验证下自己的函数的功能的,可现有系统下没有目录可删,尝试着又加入了一个 mkdir 指令,可没有权限在 MenuOS 中添加目录。好吧,自己选的材,做出的菜再难看,也得尝尝不是?那就将错就错,继续跟踪分析吧。
三、跟踪分析
先关闭MenuOS,再以前面学习过的 linux 内核启动跟踪方法启动 MenuOS。
qemu - kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
(gdb) file linux-3.18.6/vmlinux
(gdb) target remote:1234
接下来是设置断点。因为是要跟踪用户的系统调用函数,所以直接在rmdir 函数所使用的系统调用接口 sys_rmdir 处设置断点。至于伪函数 system_call(只是一段汇编代码的入口标记),因为 gdb 无法在此处停下,这里的断点设置也就可有可无。为了多充点字数,还是加上好了。
(gdb) b sys_rmdir
(gdb) b system_call
接下来,按下 “c”,让 MenuOS 完全启动。再无参执行 rmdir 命令,还好,gdb还是抓到了一个sys_rmdir:
rmdir
不知道这个出错信息是什么意思,又按了几次n,一直显示这个,那就按“c“让 rmdir 运行完好了。又多试了几回 rmdir,MenuOS 与 gdb 居然都成了“僵尸”,只好"kill 无赦"了。
换老师的 time 指令跟踪,一到 sys_time 断点,MenuOS 与 gdb 又都卡死了。。。
看来实验是做不成了,咱就直接以老师在课堂上提供的伪代码来分析系统调用过程吧。由这段伪代码生成的流程图如下:
由流程图可知,发生系统调用时,要先执行 SAVE_ALL,保存所有的现场信息,再根据保存在 eax 寄存器中的系统调用号,执行相应的的系统功能,返回值同样保存在eax寄存器中,需要用户及时取出,以免被其他系统调用破坏。系统调用执行完毕,并不是直接返回调用函数,而是先判断当前进程有没有其他需要处理的调度情况、信号处理等,如有,先处理这些情况,没有则直接跳过。接着通过 restore_all 恢复调用前现场信息,最后返回调用函数,结束系统调用过程。
四、总结
执行系统调用时,先保存现场,准备调用参数,接着执行系统调用,保存调用结果。处理必需的调度、信号等,恢复现场,返回调用函数,这便是system_call中断处理的大概过程。