Lab1

MIT 6.828 Lab1笔记


PART 1: PC Bootstrapr

这一部分主要是实验环境的配置,跟随教程操作即可

实模式下的地址转换

物理地址 = 段基址*16 + 偏移量


PART 2: Boot Loader

在6.828课程的系统中,boot loader包含两部分:一份汇编代码 boot/boot.s 和一份c代码 boot/main.c 。它们构成的boot loader主要有两个作用

1. 将处理器从实模式切换道32位保护模式。在实模式中,处理器只能访问1MB物理空间,而在32位保护模式下,处理器可以访问1MB以上的物理空间。切换模式后,逻辑地址向物理地址的映射方式也发生了变化,(段基址:偏移量)转化需要的offset从16变为32。

2. 借由x86的特殊I/O指令,直接从IDE硬盘中读取内核程序

Exercise 3 的四个问题

  • Q: 处理器是何时开始执行32位代码的?是什么机制使得处理器从16位转为32位?

  • A: 如下图所示, 汇编操作将cr0寄存器的最后一位置为1,通过Intel手册我们可以知道,当cr0寄存器的最后一位为1时,开启保护模式。

Lab1-1.png

  • Q: boot loader 执行的最后一条指令是什么?它加载的kernel执行的第一条指令是什么?

  • A: 如下图所示,这是boot loader执行的最后一条指令。这条指令转到了kernel程序的入口。

Lab1-2.png
  • kernel执行的第一条指令如下图所示。
    Lab1-3.png


  • Q: kernel的第一条指令在哪里?

  • A: 根据上一张图,我们可以看到kernel第一条指令的地址在于 0x10000c


  • Q: boot loader在从硬盘读取内核时,它是怎样决定读取几个扇区的?它是怎样得知这个信息

  • A: bootmain函数如下图所示,程序首先读取足够大的数据(程序中是SECTSIZE*8),判断要读取的数据是不是一个ELF数据,如果是,则读取程序头,从表征程序头的结构体里面的e_phnum成员得知要读取的数据数量。

Lab1-4.png

Exercise 5

linker的地址改变,从结果上来看,kernel无法被加载进内存,现象如下图所示

Lab1-5.png

我在这里将链接地址从0x7c00改成了0x7cd0,用gdb跟踪程序,会发现boot loader的起始地址变为了我们改成的0x7cd0,如下图所示

Lab1-6.png

将链接地址修改成不同的值会出现不同的问题,但最终都会导致程序循环,无法正确加载kernel程序

Exercise 6

将断点打在boot loader的起始位置,观察地址0x100000,可以看出这一地址的数据全部为0。当程序进入kernel后,发现指定的地址位置出现了数据。原因可能是boot loader 将kernel加载进了内存,所以相应位置的数据出现了变化;

Exercise 7

在执行指令 movl %eax, %cr0 之前, 两个地址对应的数值如下图所示地址空间

Lab1-8.png

在执行指令过后, 两个地址对应的数值如下图所示地址空间

Lab1-9.png

执行指令前两个地址空间对应的数据不同,而执行指令后两个地址空间对应的数据相同,说明开启分页机制后这两个虚拟地址被映射成了同一个物理地址。


注释掉这条指令重新编译,从结果上来看,硬件启动失败,直接退出

gdb跟踪发现是一条jmp指令出错了,因为跳转过后的地址是一个无效地址。


PART 3: The Kernel

kern/printf.c, lib/printfmt.c 和 kern/console.c三个文件的关系

kern/console.c 最底层,用了大量汇编语言编写,主要是适配于硬件的屏幕输出;

kern/printf.c 使用了console.c中的底层函数;

lib/printfmt.c 的函数最上层,封装了内核中的函数,可以供上层使用。

Exercise 8

需要修改的代码在lib/printfmt.c中,改变后的代码为

case 'o':
// Replace this with your code.
     /*
     putch('X', putdat);
     putch('X', putdat);
     putch('X', putdat);
     break;
     */
     num = getuint(&ap, lflag);
     base = 8;
     goto number;

模仿上方的代码即可写出,下面是问题的回答

1. console.c 导出了 cputchar 函数供 printf.c 使用,cputchar封装在了 putch 函数中。

2. 下面代码处理的情况是:屏幕上已经充满了字符,若现在的操作需要向屏幕再次输入字符,则需要进行的动作是:1.所有的字符向上移动一行 2.最后一行清空。这段代码实现的就是这个功能。

if (crt_pos >= CRT_SIZE) {//*如果目前屏幕上的字符数超过了屏幕的容量
    int i;
    memmove(crt_buf, crt_buf + CRT_COLS, (CRT_SIZE - CRT_COLS) * sizeof(uint16_t));//* 将从第二行开始的内容移动到第一行去
    for (i = CRT_SIZE - CRT_COLS; i < CRT_SIZE; i++)
        crt_buf[i] = 0x0700 | ' ';//*最后一行的内容清零,由上文的内容可知,对0x700进行或操作与显示的色彩有关
    crt_pos -= CRT_COLS;
}

3. 我将文中提及到的代码段加在了 kern/init.c 中,因为前方有明显的屏幕打印值,所以可以很方便地找到要追踪地语句地位置。把断点打在 cpirntf 上。

  • 在 cprintf 函数内,fmt指向的是字符串 "x %d, y %x, z %d\n" 的地址。函数原型中没有ap,所以这里ap也打印不出来,如下图所示

Lab1-10.png
  • 在 vcprintf 函数内,fmt指向的是字符串 "x %d, y %x, z %d\n" 的地址。ap指向一个地址,这个地址分别放有 x, y, z 的值,如下图所示

Lab1-11.png
  • cons_putc 中,变量是一个char型

  • va_arg 是一个宏定义,gdb无法在之上直接打断点。进入vprintfmt逐步跟踪后,可以看到每次va_arg后,ap都是指向下一个变量的地址

Lab1-12.png

4. 输出变成了 He110 World 。57616化成16进制是e110, 72,6c,64分别是rld的ascii码,如果在大端序的cpu上运行,则 Wo后面不会显示字符。

5. 虽然输入y没有对应的值,但还是会打印栈上的内容,在信心安全领域这种叫做格式化字符串漏洞,用于泄露栈上信息。

6. 函数原型声明为 cprintf(const char *fmt, va_list ap);

Exercise 11 12

要通过寄存器追溯函数调用栈,首先要弄懂一些细节:

1.pop 和 push 指令的操作顺序

  • push: 先减小esp寄存器里的值,再将要压入的数据写入到esp寄存器指向的地址;

  • pop: 先读出esp寄存器指向地址的值,再增加esp寄存器的值

  • 读写与寄存器值改变, 这两个顺序不要弄错了

2.即将进行函数调用时,进行的压栈操作

  • 首先按照参数的声明顺序,将参数压入栈中(关于压栈的顺序,可能根据编译器有所不同;32位操作系统下函数传参需要通过压栈,64位cpu寄存器资源丰富,传参直接用寄存器)。

  • 然后压入返回地址eip,传参和压入eip都是在call函数之前实现的

  • 最后将esp地址传递给ebp,并将ebp的值压入栈中。注意,这一部是在被调函数中实现的。

3.栈的生长方向,从高地址向低地址生长


关于在调用时显示符号信息,这个实验中的要求比较简单,已经写好了 stab_binsearch 函数,只需要利用即可,相应的代码中也有提示。

有一点需要注意的是,stab结构体中有很多成员,哪一项显示的是eip地址的行号呢,通过验证,我们可以得知是 n_value 这个变量,如果使用了其他变量,make grade 也能通过,不过返回地址是不正确的。具体看程序吧

kern/kdebug.c中代码如下图所示

Lab1-13.png

kern/monitor.c中代码如下图所示

Lab1-14.png

make qemu 的结果如下图所示

Lab1-15.png

通过查看 obj/kernel.asm ,我们判断 test_backtrace 的返回地址应该是基地址+0x28, 即十进制的40, 与实验结果相符。

make grade, 实验通过!!

Lab1-16.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容