“Linux内核分析”实验五

系统调用(上)

作者:何振豪

原创作品转载请注明出处 http://www.cnblogs.com/scoyer/p/6624232.html 

《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000

 

实验步骤(由于实验楼git被墙住了,所以在自己的PC下进行试验)

1. 删除menu目录

  从git上下载最新版(带有time系统调用的版本),由于我之前加载的就是git上新版的menu,所以就省去了这一步。

2. 修改menu里面的test.c文件

  在test.c中加上上一个实验写的两个函数,然后按照MenuConfig的参数格式加上菜单选项,代码如下:

 3. 然后键入下面命令

gcc -o init linktable.c menu.c test.c -m32 -static –lpthread
cd ../rootfs
cp ../menu/init ./
find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img

  编译成init文件然后打包成一个文件系统。编译成功后,启动Menu系统

cd ~/LinuxKernel/
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img

  输入help得到如下界面就说明成功了。

  可以看到里面有我们新添加的uid选项。

4. 启动gdb进行调试:

  具体启动方法可以参照实验三。

  设置断点sys_getuid并且利用continue指令执行:

  可以看到整个系统已经开机完毕,没有触发断点,因为sys_getuid还没有被调用,所以我们需要执行uid的指令进行系统调用执行到断点处:

  利用continue继续执行:

  这样就会跳出断点,列出附近代码:

 

 

实验总结

了解系统调用实际上只要分析好具体的调用过程就好了。姑且先把我们的函数叫做f,f里面调用了getuid这个系统提供的接口,f利用getuid这个函数来获取当前进程的用户id。因此上述调用的具体过程可以描述为

(1)f调用了getuid,需要它返回该进程的用户id;

(2)getuid先是做好了保存现场SAVE_ALL的工作,然后设置好相应的寄存器参数,使用软中断int80x进行系统调用system_call;

(3)system_call从eax取出系统调用号,检查系统调用号合法并且该系统调用没有被跟踪后,从系统调用表sys_call_table里面找到内核函数入口地址之后,跳到相应地址去调用对应的服务例程

sys_getuid,注意这时候系统处于内核态;

(4)sys_getuid经过一些处理得到进程的用户id之后,保存到eax,返回到system_call;

(5)system_call继续执行就到ret_system_call来结束系统调用,返回到用户态,利用iret指令回到之前从getuid中断的下一句的位置,恢复调用前的现场RESTORE_ALL,接着将得到的uid返回到f;

(6)f得到这个uid才是真正的结束。

 

当然实际上的系统调用没有这么简单,这只是一个大概的轮廓,因为还要考虑到同时存在的几个进程的因素,处理一些信号产生的问题等。

posted @ 2017-03-26 21:49  scoyer  阅读(271)  评论(0编辑  收藏  举报