zoukankan      html  css  js  c++  java
  • 20169203《Linux内核原理与分析》第七周作业

    对于本周的实验是使用gdb跟踪分析一个系统调用中断处理过程,分析系统调用从system_call开始到iret结束之间的整个过程。
    首先进入实验楼虚拟机打开终端进入LinuxKernel中将原有的menu删除代码如下

    rm -rf menu
    

    再拷贝新的menu

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

    进入到test.c中添加上周写的系统调用


    添加后编译运行menu

    make rootfs
    

    我们以调试的方式启动menuos

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

    再打开另一个中断,输入符号表,连接menuos

    file linux-3.18.6/vmlinux
    target remote:1234
    

    在系统调用出设置断点

    b sys_getuid18
    

    即可在断点处列出其代码

    通过本次的实验我了解的系统调用的过程那程序运行到getuid()时程序需要进行系统调用那么会通过init 0x80陷入到内核态并将其对应的系统调用号传送给eax寄存器中,并且在系统调用的过程中还会有可能放生进程调度进入到另一个函数中,在system_call的最后是iret汇编语言指令,从系统调用退出,从内核态切换回用户态。

    # system call handler stub
    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)   // 获取thread_info结构的信息
                        # system call tracing in operation / emulation
        testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) // 测试是否有系统跟踪
        jnz syscall_trace_entry   // 如果有系统跟踪,先执行,然后再回来
        cmpl $(NR_syscalls), %eax // 比较eax中的系统调用号和最大syscall,超过则无效
        jae syscall_badsys  // 无效的系统调用 直接返回
    syscall_call:
        call *sys_call_table(,%eax,4) // 调用实际的系统调用程序
    syscall_after_call:
        movl %eax,PT_EAX(%esp)      // 将系统调用的返回值eax存储在栈中
    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  //检测是否所有工作已完成
        jne syscall_exit_work           //工作已经完成,则去进行系统调用推出工作
    
    restore_all:
        TRACE_IRQS_IRET         // iret 从系统调用返回
    syscall_exit_work:
        testl $_TIF_WORK_SYSCALL_EXIT, %ecx //测试syscall的工作完成
        jz work_pending
        TRACE_IRQS_ON  //切换中断请求响应追踪可用
        ENABLE_INTERRUPTS(CLBR_ANY) # could let syscall_trace_leave() call
                        //schedule() instead
        movl %esp, %eax
        call syscall_trace_leave //停止追踪系统调用
        jmp resume_userspace //返回用户空间,只需要检查need_resched
    END(syscall_exit_work)
    work_pending:
        testb $_TIF_NEED_RESCHED, %cl  // 判断是否需要调度
        jz work_notifysig   // 不需要则跳转到work_notifysig
    work_resched:
        call schedule   // 调度进程
        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
        andl $_TIF_WORK_MASK, %ecx  // 是否所有工作都已经做完
        jz restore_all              // 是则退出
        testb $_TIF_NEED_RESCHED, %cl // 测试是否需要调度
        jnz work_resched            // 重新执行调度代码
    
    work_notifysig:             // 处理未决信号集
    #ifdef CONFIG_VM86
        testl $X86_EFLAGS_VM, PT_EFLAGS(%esp) // 判断是否在虚拟8086模式下
        movl %esp, %eax
        jne work_notifysig_v86      // 返回到内核空间
    1:
    #else
        movl %esp, %eax
    #endif
        TRACE_IRQS_ON  // 启动跟踪中断请求响应
        ENABLE_INTERRUPTS(CLBR_NONE)
        movb PT_CS(%esp), %bl
        andb $SEGMENT_RPL_MASK, %bl
        cmpb $USER_RPL, %bl
        jb resume_kernel        // 恢复内核空间
        xorl %edx, %edx
        call do_notify_resume  // 将信号投递到进程
        jmp resume_userspace  // 恢复用户空间
    
    #ifdef CONFIG_VM86
        ALIGN
    work_notifysig_v86:
        pushl_cfi %ecx          # save ti_flags for do_notify_resume
        call save_v86_state     // 保存VM86模式下的CPU信息
        popl_cfi %ecx
        movl %eax, %esp
        jmp 1b
    #endif
    END(work_pending)
    

    对于教材内容的学习本周主要学习的是Linux对于内核同步与并发的方法,多线程相当于一个并发系统。并发系统一般同时执行多个任务。如果多个任务可以共享资源,特别是同时写入某个变量的时候,就需要解决同步的问题。比如说,我们有一个多线程火车售票系统,用全局变量i存储剩余的票数。多个线程不断地卖票(i = i - 1),直到剩余票数为0。如果只有一个线程执行上面的程序的时候(相当于一个窗口售票),则没有问题。但如果多个线程都执行上面的程序(相当于多个窗口售票), 我们就会出现问题。其根本原因在于同时发生的各个线程都可以对i读取和写入。这就需要引入同步对于多线程程序来说,同步是指在一定的时间内只允许某一个线程访问某个资源 。而在此时间内,不允许其它的线程访问该资源。我们可以运用自旋锁,信号量,互斥体等来对内核进行同步.

  • 相关阅读:
    CSLA.Net 3.0.5 项目管理示例 业务基类 Project.cs
    为什么我要写博客
    LINQ 标准的查询操作符 过滤 where、index1、OfType
    LINQ 概述和演变
    sl中几个简单变量的获取
    Rails存储库从SVN转向Git
    showcase测试界面
    Silverlight读取xml
    向silverlight传递自定义参数
    RadRails1.0降临——增加Profiler、CallGraph Analyzer和Rails Shell等新特性
  • 原文地址:https://www.cnblogs.com/lxy666666/p/6035296.html
Copyright © 2011-2022 走看看