分析system_call中断处理过程

分析system_call中断处理过程

“20135224陈实 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 “

第一部分:

利用GDB打开系统调用函数并实现跟踪调试

具体步骤:

1 选取上周函数并利用原来的getpid的简单函数来实现本次实验

2 使用gdb跟踪分析使用在sys_time处设置断点并list找到的代码​

3 (注意)进入system_call的时候gdb无法继续跟踪,要提前结束直接quit退出即可

主函数内容:

getpid代码:
 
运行内核:
call前结束跟踪内容:
 

第二部分:

大致过程:SYSterm_call---运行到SAVE—ALL(保护现场)继续运行----table表找对应程序----iret结束返回

分析call对应函数功能(简化)

(注意)通过SAVE_ALL宏完成把所有相关寄存器的内容都保存在堆栈中
以下是各项简化函数的表示意思,依据视频依次是:

GET_THREAD_INFO(%ebp):将当前信息保存在ebp

testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%esp)  jnz syscall_trace_entry:判断是否 trace调用

cmpl $(NR_syscalls), %eax jae syscall_badsys:判断系统调用号是否超出最大值

call *sys_call_table(,%eax,4):系统调用的数字实际上是一个序列号,表示其在系统的一个数组sys_call_table[]中的位置。

movl %eax,PT_EAX(%esp):保存系统调用的返回值

DISABLE_INTERRUPTS(CLBR_ANY):屏蔽其他系统调用

movl TI_flags(%esp), %eax:寄存器ecx是通用寄存器,在保护模式中,可以作为内存偏移指针(此时,DS作为 寄存器或段选择器),此时为返回到系统调用之前做准备

testl $_TIF_ALLWORK_MASK, %eax     jne syscall_exit_work :退出系统调用之前,检查是否需要处理信号

RESTORE_REGS 4​ :x86架构恢复寄存器代码

INTERRUPT_RETURN即iret: 系统调用是通过软中断指令

INT 0x80 实现的,而这条INT 0x80指令就被封装在C库的函数中。(软中断和我们常说的硬中断不同之处在于,软中断是由指令触发的,而不是由硬件外设引起的。)

INT 0x80 这条指令的执行会让系统跳转到一个预设的内核空间地址,它指向系统调用处理程序,即system_call函数。

总结

system_call函数是怎么找到具体的系统调用服务例程路径:

通过系统调用号查找系统调用表sys_call_table,软中断指令INT 0x80执行时,系统调用号会被放入 eax 寄存器中,system_call函数可以读取eax寄存器获取,然后将其乘以4,生成偏移地址,然后以sys_call_table为基址,基址加上偏移地址,就可以得到具体的系统调用服务例程的地址了!然后就到了系统调用服务例程了。需要说明的是,系统调用服务例程只会从堆栈里获取参数,所以在system_call执行前,会先将参数存放在寄存器中,system_call执行时会首先将这些寄存器压入堆栈。system_call退出后,用户可以从寄存器中获得(被修改过的)参数。

注意事项:系统调用通过软中断INT 0x80陷入内核,跳转到系统调用处理程序system_call函数,然后执行相应的服务例程。但是由于是代表用户进程,所以这个执行过程并不属于中断上下文,而是进程上下文。因此,系统调用执行过程中,可以访问用户进程的许多信息,可以被其他进程抢占,可以休眠。当系统调用完成后,把控制权交回到发起调用的用户进程前,内核会有一次调度。如果发现有优先级更高的进程或当前进程的时间片用完,那么会选择优先级更高的进程或重新选择进程执行。

原文地址:https://www.cnblogs.com/chuishi/p/5322754.html