zoukankan      html  css  js  c++  java
  • 系统调用小识

    :xujianguo

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

    ——————————————————————————————————————————————————————-————

    实验目的:

           通过gdb调试和汇编嵌入menuOS的文件来进一步熟悉linux系统调用。

    实验环境:

      

            实验楼:www.shiyanlou.com。

    实验步骤:

    1.配置环境,登录实验楼网站。

      按照上次实验的基本步骤,结合老师视频所讲,完成相关实验。

    cd LinuxKernel

    删除menu

    然后从github上克隆相应的mengning/menu.git

    2.编译menu,生成rootfs。

    3.调整main.c,添加上次实验所用的系统调用段。

    系统调用:

    MenuConfig(“open”,"open or create file", Open);

    汇编嵌入也类似。

    4.编译和配置调试条件。

    按照学过的方式配置环境:

    5.启动gdb调试器,分别在sys_open、start_kernel、system_call处设置断点调试。

    实验分析:

      实验参考资料:

         http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/syscalls/syscall_32.tbl

       http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/kernel/entry_32.S

    重要源码分析:

    # system call handler stub

    490ENTRY(system_call) //系统调用入口

    491 RING0_INT_FRAME # can't unwind into user space anyway

    492 ASM_CLAC

    493 pushl_cfi %eax # save orig_eax

    494 SAVE_ALL //保存现场

    495 GET_THREAD_INFO(%ebp)

    496 # system call tracing in operation / emulation

    497 testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)

    498 jnz syscall_trace_entry

    499 cmpl $(NR_syscalls), %eax

    500 jae syscall_badsys

    501syscall_call: //调用系统调用号

    502 call *sys_call_table(,%eax,4)

    503syscall_after_call: //调用结束的处理。

    504 movl %eax,PT_EAX(%esp) # store the return value

    505syscall_exit: //退出调用

    506 LOCKDEP_SYS_EXIT

    507 DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt

    508 # setting need_resched or sigpending

    509 # between sampling and the iret

    510 TRACE_IRQS_OFF

    511 movl TI_flags(%ebp), %ecx

    512 testl $_TIF_ALLWORK_MASK, %ecx # current->work

    513 jne syscall_exit_work

    514 515restore_all:

    516 TRACE_IRQS_IRET

    517restore_all_notrace:

    ..........

    530restore_nocheck:

    531 RESTORE_REGS 4 # skip orig_eax/error_code

    532irq_return://系统调用返回

    533 INTERRUPT_RETURN

    534.section .fixup,"ax"

    535ENTRY(iret_exc)

    536 pushl $0 # no error code

    537 pushl $do_iret_error

    538 jmp error_code

    ...............

    588ENDPROC(system_call)

    589

    590 # perform work that needs to be done immediately before resumption

    591 ALIGN

    592 RING0_PTREGS_FRAME # can't unwind into user space anyway

    593work_pending:

    594 testb $_TIF_NEED_RESCHED, %cl

    595 jz work_notifysig

    596work_resched:

     655 ALIGN

    656syscall_exit_work://系统调用结束处理环节

    657 testl $_TIF_WORK_SYSCALL_EXIT, %ecx

    658 jz work_pending

    659 TRACE_IRQS_ON

    660 ENABLE_INTERRUPTS(CLBR_ANY) # could let syscall_trace_leave() call

    661 # schedule() instead

    662 movl %esp, %eax

    663 call syscall_trace_leave

    664 jmp resume_userspace

    665END(syscall_exit_work)

    666 CFI_ENDPROC

     668 RING0_INT_FRAME # can't unwind into user space anyway

    669syscall_fault://默认处理

    670 ASM_CLAC

    671 GET_THREAD_INFO(%ebp)

    672 movl $-EFAULT,PT_EAX(%esp)

    673 jmp resume_userspace

    674END(syscall_fault)

    675

    676syscall_badsys://坏调用处理

    677 movl $-ENOSYS,%eax

    678 jmp syscall_after_call

    679END(syscall_badsys)

    680

    ....................

      

          本次实验是基于上次实验的基础进一步分析和发现,通过编译系统调试的方式来分析system_call。实验过程中,发现所使用open函数如果在启动过程中设置断点的话,调试的步骤比较多,只好跳过;在用高蛋白调试的过程中,n(Next)和s(Step)两种命令的区别和联系,值得注意;其中主要是在sys_open 、sys_time和system_call等处设置测试点。由于个人知识储备不足,对系统调用的部分细节没有好的意见,敬请谅解。

          下面继续对system_call对应的汇编代码的工作过程进行分析:

          系统在用户态和核心态之间的系统调用主要是通过int指令来完成的。start_kernel中trap_init()完成系统调用的初始化。

    根据entry_32.S(简略细节如下图)文件的system_call环节可知,

    1)ENTRY(system_call) //入口,标志着系统已经由用户态转向Kernel;

    2)SAVE_ALL//保存相关寄存器的值,起着保护现场的作用,方便中断返回;

    3)GET_THREAD_INFO(%ebp) // 通常ebp寄存器被高级语言编译器用以建造‘堆栈帧’来保存函数或过程的局部变量,此时可以知道将来返回到那个函数的那个部位
    4)syscall_call: //真正的系统调用!sys_call_table就是
    call *sys_call_table(,%eax,4)
    movl %eax,PT_EAX(%esp) //保存系统调用的返回值
    5)syscall_exit:
    LOCKDEP_SYS_EXIT
    DISABLE_INTERRUPTS(CLBR_ANY) //屏蔽其他系统调用
    ..............
    6)restore_all_notrace:
    ........
    je ldt_ss //返回到用户空间,系统调用返回

    7)RESTORE_ALL//恢复现场;

    8)irq_return//返回调用

    总结:

          系统调用主要是用户态向核心态进行调用请求,主要以中断的形式完成调度。在核心态下,系统调用通过系统调用号来完成调用匹配,system_call进行调度,sys_xxx来完成相应的系统调用,ret_from_sys_call获取返回结果,进行相关处理和调用后,通过iret返回相关结果。

         系统调用实际上是利用了中断的处理过程。而中断的一般处理过程是:当CPU收到中断或者异常的信号时,它会暂停执行当前的程序或任务,通过一定的机制跳转到负责处理这个信号的相关处理程序中,在完成对这个信号的处理后再跳回到刚才被打断的程序或任务中。

         在LINUX中,发生中断时,内核就在被中断进程的上下文中,在内核态下执行中断服务例程。但同时会保留所有需要用到的资源,以便中继服务结束时能恢复被中断进程的执行。

    参考资料:

     1. 老师的讲解视频;

     2.http://www.tuicool.com/articles/NNFzuu

     3.http://blog.csdn.net/wangzhen199009/article/details/38677075

  • 相关阅读:
    手摸手带你用Hexo撸博客(三)之添加评论系统
    手摸手带你用Hexo撸博客(二)之配置主题
    手摸手带你用Hexo撸博客(一)
    vue3和vue2生命周期的对比
    如何根据key合并数组中的对象
    webpack之require.context实现前端工程自动化
    js常用方法封装
    首页
    CentOS7安装MySQL8
    印象笔记代码高亮最完美解决方式
  • 原文地址:https://www.cnblogs.com/emochuanshuo/p/4394972.html
Copyright © 2011-2022 走看看