zoukankan      html  css  js  c++  java
  • Linux内核设计第五周学习总结 分析system_call中断处理过程

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

    使用gdb跟踪分析一个系统调用中断处理过程,分析系统调用从system_call开始到iret结束之间的整个过程。

    实验过程:

    登陆实验楼虚拟机http://www.shiyanlou.com/courses/195

    打开shell终端,执行以下命令:

    cd LinuxKernel

    rm -rf menu

    git clone https://github.com/mengning/menu.git

    获取到MenuOS源码后修改test.c文件,加入getuid系统调用函数源码,Getuid为调用C API版本,GetuidAsm为内嵌汇编语言版本


    增加命令菜单


    在menu目录下执行

    make rootfs

    改造后的MenuOS系统会自动编译并启动运行


    执行getuid和getuid-asm命令可以看到执行结果


    结束qmeu,以调试方式启动,在LinuxKernel目录下执行

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


    打开另一个shell终端,进入gdb调试工具

    gdb

    读入符号表

    file linux-3.18.6/vmlinux

    连接内核调试

    target remote:1234


    设置断点

    b sys_getuid16

    继续执行

    c


    列出代码

    list


    继续单步执行后续操作

    s


    实验分析:

    通过上述实验过程可以分析出在Linux系统下发生一次系统调用后system_call中断处理的整个过程。

    当在应用程序中调用获取当前用户uid函数getuid(),将对应的系统调用号0x18送入eax寄存器,由于没有其他参数,ebx寄存器赋值为0,执行init 0x80汇编语言指令,从用户态切换到内核态,触发系统调用中断,在system_call的最后是iret汇编语言指令,从系统调用退出,从内核态切换回用户态。

    system_call()函数

    首先把系统调用号和这个异常处理程序可以用到的所有CPU寄存器保存到相应的栈中,不包括由控制单元已自动保存的eflags、cs、eip、ss和esp寄存器。

    pushl %eax

    SAVE_ALL

    movl $0xffffe000, %ebx /* or 0xfffff000 for 4-KB stacks */

    andl %esp, %ebx

    接下来检查thread_info结构flag字段的TIF_SYSCALL_TRACE和TIF_SYSCALL_AUDIT标志之一是否被置为1,即检查是否有某一调试程序正在跟踪执行程序对系统调用的调用。

    如果系统调用号无效则把-ENOSYS值存放在栈中曾保存eax寄存器的单元中,当进程恢复在用户态的执行时会在eax中得到一个负的返回码。

    cmpl $NR_syscalls, %eax

    jb nobadsys

    movl $(-ENOSYS), 24(%esp)

    jmp resume_userspaces

    最后调用与eax中所包含的系统调用号对应的特定服务例程。

    call *sys_call_table(0, %eax, 4)

    从系统调用退出

    当系统调用服务例程结束时,system_call()函数从eax获得返回值,并保存在曾经保存用户态eax寄存器值的栈单元位置上,用户态进程将在eax中找到系统调用的返回码。

    movl %eax, 24(%esp)

    system_call()函数关闭本地中断并检查当前进程的thread_info结构中的标志,如果所有的标志都没有被设置函数就会跳转到restore_all标记处,恢复保存在内核栈中的寄存器的值,并执行iret汇编语言指令以重新开始执行用户态进程。

    cli

    movl 8(%ebp), %ecx

    testw $0xffff, %cx

    je restore_all

    实验总结:

    Linux内核在启动初始化期间会调用trap_init()函数设置向量128(十六进制0x80)对应的内核入口点。当初始化完毕后,程序需要执行系统调用时,只需执行init 0x80语句,发生一个向量128的中断即可。

    系统调用本质上是发生了一次软件中断。

  • 相关阅读:
    Notepad++64插件安装方法
    lucene、solr、nutch三者的关系
    更改MySQL数据库的编码为utf8mb4
    对request.getSession(false)的理解(附程序员常疏忽的一个漏洞)
    登录页面的表单验证(登录+密码 )
    MSYS2 环境搭建,并整合Qt
    QAbstractItemView为截断的项显示ToolTip(使用事件过滤)
    TraceTool 跟踪工具的瑞士军刀(C++版使用)
    Indy9的TIdFTPServer封装类
    Delphi 7学习开发控件(继承TGraphicControl只画一条线)
  • 原文地址:https://www.cnblogs.com/20135310cqr/p/5307178.html
Copyright © 2011-2022 走看看