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

    实验

    给MenuOS增加time和time-asm命令的方法:

    1. 更新menu代码到最新版
    2. 再main()函数中增加MenuConfig
    3. 增加对应的Time函数和TimeAsm函数(这里的函数要换成我们自己编写的使用系统调用的函数,比如mkdir和mkdirAsm)
    4. make rootfs (帮我们自动编译自动生成根文件系统,自动帮我们启动起来menuos)

    接下来我要使用gdb跟踪分析一个系统调用内核函数(mkdir)

    这次我实验所用的系统调用仍然是是mkdir

    首先,我们需要把上周做的两个实验加入到我们的MenuOS中,变成MenuOS中的两个命令。如图:

    方法是要将函数加入到test.c中(因为实验楼中的clone无法使用),加入命令为:

    int Mkdir()
    {
            int flag;
            flag = mkdir("/home/shiyanlou/testdir");
            if (flag == -1)
                    printf("mkdir failed!
    ");
            else
                    printf("make dirctory success!
    ");
            return 0;
    }
    
    int MkdirAsm()
    {
       int flag;
       char *dir = "/home/shiyanlou/testdir2";
       asm volatile(
           "movl $0x27,%%eax
    	"
           "movl %1,%%ebx
    	"
           "int $0x80
    	"
           "movl %%eax,%0
    	"
           :"=m"(flag)
           :"c"(dir)
           );
       if(flag==0)
          printf("mkdir success!
    ");
       else
          printf("mkdir failed!
    ");
       return 0;
    }
    

    在main函数中加入:

        MenuConfig("mkdir","Make A Directory",Mkdir);
        MenuConfig("mkdir-asm","Make A Directory(asm)",MkdirAsm);
    
    

    make rootfs就可以自动生成,输入help可以看到mkdir,如下结果:

    下面开始用gdb调试:

    cd LinuxKernel
    qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
    水平分割
    gdb
    file linux-3.18.6/vmlinux   //加载内核
    target remote:1234          //链接到menu os里
    b start_kernel              //在start_kernel处设置断点
    c                           //继续执行,到start_kernel 停下来
    

    list                        //查看startkernel这段代码
    b sys_mkdir                 //在我们要分析的这个系统调用处设置断点
    c                           //继续执行
    c
    c
    

    启动menuos,输入mkdir,看gdb调试结果

    如果我们换用视频里的sys_time设置断点进行调试,之前的方法与mkdir类似,然后可以继续跟踪调试如下:

    b sys_time
    c
    c
    c
    list
    s                           //单步执行
    s                           //单步执行
    finish                      //函数执行完
    s
    s
    n
    n
    

    这边代码就不大好调试了,如果我们再设置一个断点,当我们用int 0x80时,cpu自动跳转到system_call这个函数,下面我们直接设置断点system_call,是否能停下来呢?

    b system_call
    c
    

    发现time返回了。在menuos中输入time—asm,停在system_time的位置,system_call并不能停下。老师说这里的system_call他不是一个正常的函数,它是一段特殊的汇编代码,可能gdb对他不支持,我们只能调试系统调用函数和对应的内核函数,调试内核函数的处理过程,但不能跟踪entry_32.s这个汇编代码,在system_call处并没有停下来。system_call在entry_32.s中,可以找到ENTRY(system_call),gdb可以发现一个函数原型,实际上不是函数,是汇编代码的起点,gdb现在还不能跟踪它。

    关于从system_call到iret之间的过程

    画了一个大致的流程图,如下:

    首先保护现场(SAVE_ALL:保存需要用到的寄存器数据);退出恢复现场(RESTORE_ALL:退出中断程序,恢复保存寄存器的数据)。
    下面为SAVE_ALL的实现:

    .macro SAVE_ALL
        cld
        PUSH_GS
        pushl_cfi %fs
        /*CFI_REL_OFFSET fs, 0;*/
        pushl_cfi %es
        /*CFI_REL_OFFSET es, 0;*/
        pushl_cfi %ds
        /*CFI_REL_OFFSET ds, 0;*/
        pushl_cfi %eax
        CFI_REL_OFFSET eax, 0
        pushl_cfi %ebp
        CFI_REL_OFFSET ebp, 0
        pushl_cfi %edi
        CFI_REL_OFFSET edi, 0
        pushl_cfi %esi
        CFI_REL_OFFSET esi, 0
        pushl_cfi %edx
        CFI_REL_OFFSET edx, 0
        pushl_cfi %ecx
        CFI_REL_OFFSET ecx, 0
        pushl_cfi %ebx
        CFI_REL_OFFSET ebx, 0
        movl $(__USER_DS), %edx
        movl %edx, %ds
        movl %edx, %es
        movl $(__KERNEL_PERCPU), %edx
        movl %edx, %fs
        SET_KERNEL_GS %edx
    .endm
    
    

    在这段代码中,保存了相关寄存器的值。 他们依次是:ES,DS,EAX,EBP,EDI,ESI,EDX,ECX,EBX等等。从这里寄存器的顺序可以知道压栈的最后压入的是ebx,这里压入的栈是内核栈。

    遇到的问题

    1. 在使用实验楼clone的时候出现问题,后将test.c文件更改进行解决
    2. 实验楼一直很卡,试验了好多次最后在MenuOs上输入的mkdir命令上还是卡住了

    书上的内容整理

    1. 内核同步介绍:留意保护共享资源,防止共享资源并发访问,发生各个线程之间相互覆盖共享数据的情况,造成访问数据不一致;临界区和竞争条件,临界区:访问和操作共享数据的代码段。 竞争条件:两个执行线程处于同一个临界区中;内核各个部分都会调用两个函数,一个函数将新请求添加到队列尾部,另一个函数从队列头删除请求,然后处理它。
    2. 锁的使用是自愿的、非强制的,它完全属于一种编程者自选的编程手段;内核中造成并发的原因:(1)中断:任何时刻异步发生,打断当前执行的代码(2)软中断和tasklet:任何时刻唤醒或调度软中断、tasklet(3)内核抢占(preempt)(4)睡眠及与用户空间的同步:唤醒调度程序,调度新进程执行(5)对称多处理器(SMP);编程需注意的问题: (1)数据是否全局?除了当前线程,其他线程是否可以访问? (2)数据是否在进程/中断上下文中共享?是否在两个不同中断中共享?(3)进程在访问数据时可否被抢占?被调度的新进程是否会访问同一数据? (4)当前进程是否会睡眠(阻塞)在某些资源上?共享数据处于何种状态? (5)怎样防止数据失控?;加锁:按顺序加锁。使用嵌套锁必须以相同顺序获取锁;防止发生饥饿; 不要重复请求同一个锁; 设计力求简单;建议以获取锁相反的顺序来释放锁。
    3. 原子操作:原子操作执行过程不被打断,原子操作接口分为整数操作接口和单独位操作接口。
    4. 自旋锁:自旋锁最多只能被一个可执行线程持有。若一个线程试图获得一个被征用的自旋锁,线程会一直忙循环、选择、等待锁可用。缺点:由于自旋锁在等待时自旋(浪费处理器时间),因此自旋锁不应长时间持有。优点:线程不用睡眠,不用进行上下文切换。自旋锁可以使用在中断处理程序中。对于软中断,无论是否同种类型,如果数据被软中断共享,那么它必须得到锁的保护。读写自旋锁:读写不同锁,多人和可并发持有读者锁,写锁只能被一个任务持有。
    5. 信号量特点: Linux中的信号量是一种睡眠锁; 信号量适用于锁会被长期占有的情况;
      由于信号量会睡眠,所以只能用于进程上下文中,中断上下文不支持调度;可以在持有信号量时睡眠; 不可以在持有信号量时使用自旋锁; 信号量允许任意数目的锁持有者,自旋锁一个时刻只允许一个任务持有;在声明时课指定信号量拥有的持有者数量。
    6. 禁止抢占:内核代码使用自旋锁作为非抢占区域的标记。preempt_disable() 增加抢占计数值,从而禁止内核抢占;preempt_enable() 减少抢占计数值,当减为0时检查和执行被挂起的任务; preempt_count() 返回抢占计数。
  • 相关阅读:
    sfs2x 连接 mongodb
    java websocket
    webstorm 4.0 注册码
    解决 sfs2 admin tool 找不到扩展
    window 注册表五大类
    opengl 学习第二日
    java google Protobuf
    扩展 java sencha touch PhonegapPlugin
    sencha touch2 kryonet socket phonegap 通信 作者:围城
    sencha touch2 layout 笔记
  • 原文地址:https://www.cnblogs.com/Jarvan210/p/6036725.html
Copyright © 2011-2022 走看看