第五章 系统调用的三层机制(下)
1.往MenuOS中添加命令
(1)首先进入LinuxKernel文件夹,将menu目录删除。然后再git clone克隆下载更新了版本之后的menu目录(包含time和time-asm系统调用)。
cd LinuxKernel/ //进入LinuxKernel文件夹
rm -rf menu //将menu目录删除
git clone http://github.com/mengning/menu.git //克隆下载更新了版本之后的menu目录
(2)进入menu文件夹,使用make rootf进入MenuOS,并使用help命令查看现有的命令。
cd menu/ //进入menu文件夹
make rootfs //进入MenuOS
MenuOS>>help //并使用help命令查看现有的命令
(3)在test.c中加入getpid()。
sudo gedit test.c //编辑test.c
(4)再次使用make rootfs命令,make rootfs成功后,输入help命令查看新增的GPid,然后输入GPid命令成功返回pid的值。
make rootfs //将根目录系统重新编译
MenuOS>>help //查看新增的GPid
MenuOS>>GPid //调用GPid查看返回值
2.使用gdb跟踪系统调用内核函数sys_time
(1)返回LinuxKernel目录,然后用如下命令启动内核,内核被冻结起来。
cd LinuxKernel //返回LinuxKernel目录
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S //启动内核
(2)使用水平分割,打开一个shell窗口,使用gdb调试,打开vmlinux,连接1234端口,并在start_kernel处设置断点。
(gdb)file linux-3.18.6/vmlinux
(gdb)target remote:1234
(gdb)b start_kernel
(3)在sys_time处设置断点,并c继续调试,启动MenuOS后执行time命令,程序停在sys_time处。
(gdb)b sys_time
(gdb)c
(4)使用list命令列出sys_time对应的代码。并使用s命令单步调试。
(gdb)list
(gdb)s
分析system_call汇编代码过程
在system_call处设置断点,查看system_call
通过结果分析,它其实就是系统调用的处理过程,内部没有严格遵守函数调用堆栈基址,不支持gdb的调试,所以MenuOS中仍停留在sys_time。
从system_call到iret的流程图
总结
通过本实验,查阅相关资料,我了解到系统调用时,首先通过save_all来保存现场,然后进行系统调用,并将返回值放入寄存器eax中,然后确认有没有其他的中断进入,以便设置返回信号。如果没有就从系统调用返回,并通过函数restore_all恢复现场;如果有就进入函数syscall_exit_work,查看有没有挂起的任务,有就转入函数work_pending进行任务调度,没有就返回,并恢复现场。