深入分析 Linux 内核系统调用

作者: AMG架构师 | 来源:发表于2016-03-26 17:36 被阅读389次

    《Linux 内核分析》 MOOC 课程实验 分析 Linux 中断处理过程

    在上一周的实验课程中,我们分析了 Linux 内核系统调用过程,理解了中断的概念和中断上下文,掌握了系统调用的原理,今天,我们继续以 Linux 内核 2 号系统调用 fork 函数为例,更加深入的分析系统调用过程。

    1.增加 Menu 内核命令行

    在这里,我们把上一次实验的 fork 函数以命令行的形式写入内核,在这里我就不赘述操作步骤了,之前的实验有详细的操作流程。


    这就是我们将 fork 函数写入 Menu 系统内核后的效果,通过命令行,实现了操作系统调用过程。

    2.GDB 追踪内核调用 sys_fork

    通过查询操作系统内核调用函数 API,我们知道 fork 函数的系统调用是 sys_fork,下面我们就通过 GDB 来追踪 sys_fork 的调用过程。同样,这里我也不再赘述操作过程了,之前的实验都有涉及。


    由上图可知,sys_fork 在底层调用的是 do_fork 函数。这里需要注意一下,GDB 支持在 system_call 处设置断点,但却无法让程序停留在这个地方,因此,我们只能暂停在这里了,转向分析源码。

    3.分析内核调用汇编源码

    ENTRY(system_call)
        RING0_INT_FRAME     # can't unwind into user space anyway
        ASM_CLAC
        pushl_cfi %eax          # save orig_eax
        SAVE_ALL      #保存现场
        GET_THREAD_INFO(%ebp)   # system call tracing in operation / emulation
        testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
        jnz syscall_trace_entry
        cmpl $(NR_syscalls), %eax
        jae syscall_badsys
    
    syscall_call:
        call *sys_call_table(,%eax,4)    #系统调用
    
    syscall_after_call:
        movl %eax,PT_EAX(%esp)      # store the return value
    
    syscall_exit:
        LOCKDEP_SYS_EXIT
        DISABLE_INTERRUPTS(CLBR_ANY)    # make sure we don't miss an interrupt
                                        # setting need_resched or sigpending
                                        # between sampling and the iret
        TRACE_IRQS_OFF
        movl TI_flags(%ebp), %ecx
        testl $_TIF_ALLWORK_MASK, %ecx  # current->work
        jne syscall_exit_work
    
    restore_all:
        TRACE_IRQS_IRET    #恢复现场
    
    irq_return:
        INTERRUPT_RETURN    #中断返回
    

    为了方便阅读,我把上述系统调用源码整理了一下,关键的地方被我打上了注释。总的来说,系统调用过程并不复杂。值得注意的是,在退出系统调用之前,会检查当前进程是否需要执行 syscall_exit_work,如果需要处理,就会查看是否有进程信号或进程调度,若有进程信号或进程调度就再进行相应操作,这不是本次实验的重点,不再展开。据此,我们可以画出从系统调用到中断返回的函数流程图:

    4.总结

    本实验通过分析 Linux 内核系统调用源码,深入剖析了系统调用的全过程。通过 int 0x80 中断跳转到系统调用处理程序 system_call 函数处,执行相应的例程。

    但是,由于是代表的是用户进程,所以这个执行过程并不属于中断上下文,而是进程上下文。因此,系统调用执行过程中,可以访问用户进程的许多信息,也可以被更高优先级的进程抢占。

    当系统调用完成后,把控制权交回到发起调用的用户进程前,内核又会有一次调度。如果发现有优先级更高的进程或当前进程的时间片用完,那么会选择优先级更高的进程或重新选择进程执行。

    相关文章

      网友评论

        本文标题:深入分析 Linux 内核系统调用

        本文链接:https://www.haomeiwen.com/subject/bdldlttx.html