美文网首页
MIT6.828 HW1 Boot xv6

MIT6.828 HW1 Boot xv6

作者: 扶桑与克里斯 | 来源:发表于2020-11-20 17:43 被阅读0次

    环境

    ubuntu 20.04 64位系统

    本次作业的地址:homework
    MIT6.828地址:MIT6.828-2018-fall

    正文

    如果做过前面lab1的老铁一定感觉lab1的内容之多,后面做起来也不容易,相对而言,这一份作业就没那么困难了,这次作业主要做的是调试,不需要写代码。

    准备工作
    这次使用的代码是xv6,而不是之前lab1的代码,所以需要重新从github拉下来:

    git clone git://github.com/mit-pdos/xv6-public.git
    

    然后make一下,这里为就用下mit的例子:

    $ cd xv6-public
    $ make
    ...
    gcc -O -nostdinc -I. -c bootmain.c
    gcc -nostdinc -I. -c bootasm.S
    ld -m    elf_i386 -N -e start -Ttext 0x7C00 -o bootblock.o bootasm.o bootmain.o
    objdump -S bootblock.o > bootblock.asm
    objcopy -S -O binary -j .text bootblock.o bootblock
    ..
    

    好了,万事俱备只欠东风。
    打开两个terminal,一个先收入make qemu-gdb,一个输入make gdb就行,不过这里官方给的代码有一点小错误,直接输入make gdb是出错的,所以我们在xv6的Makefile里面任选一行,加入以下内容:

    修复Makefile的问题
    这样一来应该可以运行make gdb了。
    接下来继续回到作业的内容,首先使用命令:
    nm kernel | grep _start
    

    接着我们得到以下的内容:


    输出的结果
    我们看到内核的起始地址在0x10000c,所以我们在这里打一个断点,然后看看此时在栈内的内容,注意作业并没有要求我们解释栈当中所有的内容,并且尝试解释这些内容是什么意思,下面在我的机子上实验的内容: 栈内的内容

    先回想以下,0x10000c这个地址内核执行的第一句代码的地址,所以说我们在前面栈的内容都是由引导程序在执行的时候压入的。在想想,结合一下以前面的lab1,我们通过call指令跳转到了内核当中执行,在bootmain.c当中的代码,下面的代码对应的汇编是call 0x10018:

      entry = (void(*)(void))(elf->entry);
      entry();
    

    这两句代码帮我们跳转到了内核的当中,因为call的执行都会将下依据需要执行的指令压入到栈,所以0x000_7d97就是call下一条语句的代码的,在bootmain.asm当中发现,内容确实如此:

    0x00009d97

    确实对了,好像接下来一堆0x0不知道怎么来的,暂且不理会,在bootmain.S当中,有以下两条语句:

      movl    $start, %esp
      call    bootmain
    
    

    start标号的地址在0x7c00,所以我们看下0x7c00开始的地址内容,如下:

    0x7c00
    和上面对照一下,0x8ec0_31fa在哪,可以看到0x8ec0_31fa后面紧跟着的就是0x7c4d,在bootmian.asm看一下,结果如下:
    0x7c4d
    原来又是下一条代码的地址,和之前那个比起来没什么花样。因为我们在bootmain.S当中对edi等寄存器都设置为0,所以在call bootmain的时候压入了这些寄存器的值,所以压入了一大堆的0。好了我们已经把栈当中的内容都解释清楚了。
    来到本次作业的Exercise,我没有完全按照作业的问题顺序来作实验,因为上面的问题搞清楚了,exercise的几个小问题都很简单:
    1. 将断点设置在0x7c00,逐步调试,在那里初始化了栈?
    2. 逐步执行call bootmain,现在栈里面有什么?
    3. bootmain.asm当中第一条对栈做了什么操作?仔细查看bootmain.asm
    4. call 0x10000c做了对栈做了什么呢?

    这几个问题确实很简单,直接放在一起回答,我们call bootmain上一句代码初始化了栈,在calll bootmain后,我们在栈内压入了0x7c4d,经过之前的C calling convention学习,我们知道了调用函数的时候先要执行push %ebp,所以bootmain.asm当中第一局指令压入了ebp。在call 0x10000c的时候,我们又压入了0x7d97

    PS:不知道各位是否还记得lab1 part3 最后一个循环的条件,while(*ebp != 0x0),通过上面的实验,我们看到了我们在栈内压入了ebp,此时ebp = 0x0,循环条件就是从这里的得到的,不得不说,MIT的代码还是写的很好的,我们也逐渐感受到了它的巧妙。

    本次的作业就做完了,还是比较简单的,稍微调试一下就知道所有问题的答案了,奥利给!

    相关文章

      网友评论

          本文标题:MIT6.828 HW1 Boot xv6

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