20135201李辰希 《Linux内核分析》第五周 扒开系统调用的“三层皮”(下)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20135201李辰希 《Linux内核分析》第五周 扒开系统调用的“三层皮”(下)相关的知识,希望对你有一定的参考价值。

 李辰希  原创作品转载请注明出处 《Linux内核分析》

MOOC课程http://mooc.study.163.com/course/USTC-100002900

一.给MenusOS增加time和time-asm命令

1.操作步骤

进入实验楼

  1. 首先,强制删除当前的menu
  2. 克隆一个新的menu

  3. 进入menu之后,输入make rootfs,就可以自动编译

  4. 输入help,可以发现系统支持更多的命令:
    • help
    • version
    • quit
    • time
    • time-asm
  5. 那么,time和time-asm是如何实现的呢?
    • 进入test.c之后,查看main函数。与之相关的只有两条语句:
      • menuconfig("time","Show system Time",Time);
      • menuconfig("time-asm","Show system Time",Time(asm));
      • 技术分享技术分享技术分享

6.给MenuOS增加time和time_asm命令的步骤:

  • 更新menu代码到最新版
  • test.c中main函数里,增加MenuConfig()
  • 增加对应的Time函数和TimeAsm函数
  • make rootfs

 

 二.使用gdb跟踪系统调用内核函数sys_time

1.操作步骤

  1. 进入内核,冻结启动

    qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
    
  2. 启动gdb技术分享
  3. 加载debug版本内核并连接到target地址技术分享
  4. 为处理time函数的系统调用systime设置断点之后,在menuOS中执行time。发现系统停在systime处。继续按n单步执行,会进入schedule函数。
  5. sys_time返回之后进入汇编代码处理,gdb无法继续跟踪
  6. 如果在syscall设置断点(entry32.S),然后输入c之后,发现是不会在sys_call处停下来的(因为这里是一处系统调用函数而不是正常函数)

代码如下:

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

gdb (gdb)file linux-3.18.6/vmlinux //加载符号表

(gdb)target remote:1234 //连接

b sys_time:在系统调用time的位置设置断点

c:继续执行,停在断点处

n/s:单步运行,s进入函数,n不进入

 

理解system_call到iret之间的主要代码

系统调用返回前可能进行进程调用,里面会发生进程上下文的切换。

从系统调用入口开始:ENTRY(system_call)

SAVE_ALL //保存现场

system_call:
    call *system_call_table(,%eax,4) 
//调用了系统调用处理函数,有系统调用号eax中,是实际的系统调用处理程序。

当前任务syscall_exit_work里面有work_pending里面有
work_notifysig //处理pending信号,不用管
重要的是work_resched:call schedule //决定了进程调度的代码,调用完会跳转到restore_all

restore_all //恢复现场

INTERRUPT_RETURN //irp_return宏,中断处理过程在这结束


三、系统调用在内核代码中的处理过程

1.int 0x80指令与systemcall是通过中断向量联系起来的,而API和对应的sys[函数]是通过系统调用号联系起来的

2.系统调用机制的初始化

  1. trapgate函数中,涉及到了系统调用的中断向量和systemcall的汇编代码入口;一旦执行int 0x80,CPU直接跳转到system_call

3.简化后便于理解的system_call伪代码

  • int 0x80后的下一条指令从此处的ENTRY(system_call)开始
  • 系统调用返回之前可能会发生进程调度(call schedule)
  • 当前进程可能有信号需要处理(work_notifysig)
  • 进程调度中会发生中断上下文切换和进程上下文的切换,这是个连贯的过程
  • 内核可以抽象成多种不同中断处理过程的集合

 

4.简单浏览system_call到iret之间的主要代码

  1. SAVE_ALL:保存现场
  2. syscall_call:调用了系统调用处理函数
  3. restore all:恢复现场(因为系统调用处理函数也算是一种特殊的“中断”)
  4. syscallexitwork:如3.中所述
  5. INTERRUPT RETURN:也就是iret,系统调用到此结束

四、总结

阐明自己对“系统调用处理过程”的理解。

  系统调用是一种特殊的中断。它是写一个函数,它需要用到内核中的代码,但这部分代码我没有办法直接访问,所以,我通过系统调用,它说它帮我去让内核执行我想执行的代码,把最后的结果告诉我。这时,我作为用户就是什么都不知道了,等着系统调用来告诉我结果。系统调用,它先通过sys_ call这个函数和内核沟通,说我想用一下你的sys_ xxx功能,请你把这个功能执行的结果告诉我。内核很快就去自己的内部,执行sys_ xxx的功能,执行完了之后,内核告诉了系统调用,这个函数的执行结果。最后系统调用就通过iret指令将结果信息反馈给了用户。这样,用户就完美的在请求系统调用帮助后,轻松的解决了问题。

 

以上是关于20135201李辰希 《Linux内核分析》第五周 扒开系统调用的“三层皮”(下)的主要内容,如果未能解决你的问题,请参考以下文章

20135201李辰希《Linux内核分析》第三次 构造一个简单的Linux系统OS

20135201李辰希 《Linux内核分析》第四周 扒开系统调用的“三层皮”

20135201李辰希《Linux内核分析》第一周 计算机是如何工作的?

《Linux内核分析》第五周

《Linux内核与分析》第五周

Linux内核分析——第五周学习笔记