LAB1_Part3 The Kernel
前言
记录一下自己的学习过程
实验内容翻译:
https://gitee.com/cherrydance/mit6.828
该翻译仅供参考
练习7
使用QEMU和GDB跟踪进入JOS内核,并停在movl %eax, %cr0指令处。检查内存地址0x00100000和0xf0100000的内容。现在,使用GDB的stepi命令单步执行该指令。再次检查内存地址0x00100000和0xf0100000的内容。确保你理解刚刚发生的事情。
如果没有建立映射,新映射建立后的第一条指令将无法正常工作是什么?在kern/entry.S中将movl %eax, %cr0注释掉,跟踪进入它,看看你是否正确。
运行结果如图所示:
可以看到,mov %eax,%cr0
执行后两块地址的内容相同,这是因为地址映射。在将该指令注释之后重新运行发现在执行jmp *%eax
之后出错, 出错结果如下图:
不要忘记在之后将代码修改回来。
练习8
我们省略了一小段代码——用于以"%o"格式打印八进制数的代码。请找到并填写这段代码片段。
我们还是先看问题
1.解释一下printf.c和console.c之间的接口。具体来说,console.c导出了哪个函数?这个函数是如何被printf.c使用的?
首先看printf.c,因为它只有三个函数,脉络清晰。即cprintf调用vcprintf,而putch看上去与这两个函数无关,我们直接进入vcprintf,往深处探索。结果如图:
printf.c使用console.c的cputchar()函数。
2.解释一下console.c中的以下内容。
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 | ’ ';
crt_pos -= CRT_COLS;
}
CRT_SIZE=25*80,这是一页所能显示的字符数量,如果crt_pos>=CRT_SIZE,说明当前已经显示满了,需要将最下面一行腾出来,因此会复制前1-24行到0-23的位置,将最后一行清空以便显示新的字符。
3.对于以下问题,你可能希望参考第二讲的笔记。这些笔记涵盖了x86上GCC的调用约定。
逐步跟踪以下代码的执行:
int x = 1, y = 3, z = 4;
cprintf(“x %d, y %x, z %d\n”, x, y, z);
在对cprintf()的调用中,fmt指向什么?ap指向什么?
按执行顺序列出每次调用cons_putc、va_arg和vcprintf。对于cons_putc,同时列出它的参数。对于va_arg,在调用之前和之后列出ap指向的内容。对于vcprintf,列出它的两个参数的值。
先将代码写在mon_backtrace中。然后运行
在回答问题前要先理解cprintf()函数,也需要对c可变参数稍微了解一下。菜鸟教程我们使用gdb进入cprint函数后,直接打印fmt和ap即可得到第一问的结果。如图所示,
上图可以得到vcprintf在调用时的值,至于每次调用cons_putc时参数c的值和va_arg调用前后的值,需要自己耐心走一遍流程
这是第一次调用cons_putc时c的值,后续不再列出,对于ap的变化,不需要查看也能得知。va_arg会获取可变参数列表的下一个参数。所以开始时1 3 4调用一次就变化为3 4,一次类推。
4.运行以下代码:
unsigned int i = 0x00646c72;
cprintf(“H%x Wo%s”, 57616, &i);
输出是什么?解释一下如何按照前面练习的逐步方式得出这个输出。这是一个将字节映射到字符的ASCII表。
输出取决于x86是小端序的事实。如果x86是大端序的,为了得到相同的输出,你会将i设置为什么值?你需要将57616更改为不同的值吗?
运行结果如下图所示:
因为57616=0xe110,而0x00646c72在内存中为72 6c 64,将他们转化为char之后得到的值为114’r’ 108’l’ 100’d’
如果是大端,那就需要将i设置为0x726c6400且不需要改变57616的值
- 在下面的代码中,在’y='之后会打印什么?(注意:答案不是具体的值。)为什么会这样打印?
cprintf(“x=%d y=%d”, 3);
结果如下
因为y没有指定对应的值,直接打印的随机值
如果GCC更改其调用约定,使得参数按声明顺序从后往前推送到栈上,那么你需要如何更改cprintf或其接口,以使其仍然能够接受可变数量的参数?
直接倒过来cprintf( …,const char *fmt)
到现在我们只是回答了问题,还没有补全练习8的代码。补全这个代码很简单,照着相似的上下文抄就行了,代码如下:
case 'o':
// Replace this with your code.
num = getuint(&ap, lflag);
base = 8;
goto number;
输出结果如下:
总结
完成了Part3前半部分,剩下的半部分将在下一篇博客继续。
有问题欢迎各位指出。