The help command is obvious, and we will shortly discuss the meaning of what the kerninfo command prints.
Although simple, it's important to note that this kernel monitor is running "directly" on the "raw (virtual) hardware" of the simulated PC.
This means that you should be able to copy the contents of obj/kern/kernel.img onto the first few sectors of a real hard disk, insert that hard disk into a real PC, turn it on, and see exactly the same thing on the PC's real screen as you did above in the QEMU window.
(We don't recommend you do this on a real machine with useful information on its hard disk, though, because copying kernel.img onto the beginning of its hard disk will trash the master boot record and the beginning of the first partition, effectively causing everything previously on the hard disk to be lost!)
Ex1 读手册 #TODO
Ex2 配环境、使用help和kerninfo命令
Ex3
The boot loader consists of one assembly language source file, boot/boot.S, and one C source file, boot/main.c
First, the boot loader switches the processor from real mode to 32-bit protected mode
Second, the boot loader reads the kernel from the hard disk by directly accessing the IDE disk device registers via the x86's special I/O instructions
- At what point does the processor start executing 32-bit code? What exactly causes the switch from 16- to 32-bit mode?
jmp protcseg - What is the last instruction of the boot loader executed, and what is the first instruction of the kernel it just loaded?
ELFHDR->e_entry
movw $0x1234, 0x472 (obj/kernel.asm) - How does the boot loader decide how many sectors it must read in order to fetch the entire kernel from disk? Where does it find this information?
in bootmain()
先读一页,把header table的首末地址读到,然后遍历table的每一条记录去load segment address
repnz: ecx不为零时就反复执行;一共128次
Ex4
看书熟悉指针 #TODO
p = &c: assigns the address of c to the variable p, and p is said to "point to" c
int x = 1, y = 2, z[10];
int *ip; // ip is a pointer to int
ip = &x; // ip now points to x
y = *ip; // y is now 1
*ip = 0; // x is now 0
ip = &.z[O]; // ip now points to z[O]
The unary operators * and & bind more tightly than arithmetic operators
Ex5
An ELF binary starts with a fixed-length ELF header, followed by a variable-length program header listing each of the program sections to be loaded. The C definitions for these ELF headers are in inc/elf.h. The program sections we're interested in are:
.text: The program's executable instructions.
.rodata: Read-only data, such as ASCII string constants produced by the C compiler. (We will not bother setting up the hardware to prohibit writing, however.)
.data: The data section holds the program's initialized data, such as global variables declared with initializers like int x = 5;.
There is one more field in the ELF header that is important to us, named e_entry. This field holds the link address of the entry point in the program: the memory address in the program's text section at which the program should begin executing.
x/Nx ADDR prints N words of memory at ADDR.
0x7c00 检查全是0
应该是kernel的text segment
Ex6
-Ttext 是0x7c00
kernel.ld里面load位置是100000
把-Ttext随便改成什么别的就行
Ex7
boot loader 的链接地址和加载地址是一样的,但是 kernel 的链接地址和加载地址有些差异。 kern/kernel.ld 可以发现内核地址链接在 0xF0100000;加载在)0x10000c(objdump)
Up until kern/entry.S sets the CR0_PG flag, memory references are treated as physical addresses
entry.S 里面置Cr0的代码是movl %eax, %cr0
执行完这句话,两个被映射到相同代码(原本存放在0xf0100000处的内容,已经被映射到0x00100000处了)
如果把这句话注释掉:movl $0x0,%ebp会挂
全局标识符表:https://wiki.osdev.org/Global_descriptor_table #TODO
Ex8
Ex9
在case d和case +里面改
- Explain the interface between printf.c and console.c. Specifically, what function does console.c export? How is this function used by printf.c?
cputchar
kern/printf.c 和 lib/printfmt.c 依赖 kern/console.c
printf是formatting console更底层 - Explain the following from console.c
如果要显示的内容过多,超过一屏大小,那么就把行从下往上移一行,然后最下面一行为空 - For the following questions you might wish to consult the notes for Lecture 2. These notes cover GCC's calling convention on the x86.
Trace the execution of the following code step-by-step:
3.1. In the call to cprintf(), to what does fmt point? To what does ap point?
fmt: the formatting string
ap: the pointer of the first element in the list, namely x.
3.2. List (in order of execution) each call to cons_putc, va_arg, and vcprintf. For cons_putc, list its argument as well. For va_arg, list what ap points to before and after the call. For vcprintf list the values of its two arguments.
TODO
int cprintf("x %d, y %x, z %d\n", x, y, z);
vc_printf:fmt points to "x %d, y %x, z %d\n" and ap points to the pointer of x
vcprintf calls void vprintfmt(void (putch)(int, void), void *putdat, const char *fmt, va_list ap); putch points to the function putch; putdat equals 0; fmt and ap is the same as above.
va_arg在putch里面调用
4.Run the following code.
unsigned int i = 0x00646c72;
cprintf("H%x Wo%s", 57616, &i);
He110 World
由于x86是小端模式,代表字的最高位字节存放在最高位字节地址上。假设i变量的地址为0x00,那么i的4个字节的值存放在0x00,0x01,0x02,0x03四处。由于是小端存储,所以0x00处存放0x72('r'),0x01处存放0x6c('l'),0x025. 处存放0x64('d'),0x03处存放0x00('\0').
- In the following code, what is going to be printed after y=? (note: the answer is not a specific value.) Why does this happen?
-267317640 -
Let's say that GCC changed its calling convention so that it pushed arguments on the stack in declaration order, so that the last argument is pushed last. How would you have to change cprintf or its interface so that it would still be possible to pass it a variable number of arguments?
reverse ap
Ex10
用printfmt输出错误信息
p=putdat 然后强制转换下
Ex11
注意个坑:%d里面加号要添加判断,不能直接else
Ex12
movl $(bootstacktop),%esp
%esp也就是bootstacktop的值为0xf0110000。其中 kern/entry.S 的 KSTKSIZE 应该就是堆栈的大小。栈高地址为bootstacktop的值,也就是0xf0110000。
在entry里面搜PG
Ex13
连续的函数调用,传入参数5 4 3 2 1 0依次调用
前三行的push
Ex14
题目里说:You can do it entirely in C, but you may find the read_ebp() function in inc/x86.h useful. 直接拿ebp
ebp=0停止循环
The listed eip value is the function's return instruction pointer: the instruction address to which control will return when the function returns. The return instruction pointer typically points to the instruction after the call instruction
ebp是基址指针,eip是返回指令指针
格式化输出 %08x
Ex15
读kernel.ld:什么都没看出
给的命令:都无法运行
stab binsearch有个读函数的可以依样画葫芦
注释里面有写lline<=rline代表可以找到,否则-1
Ex16
原来还可以直接用函数名作地址,以前都是先放在asm里面搜到再进gdb打断点的。。
start_overflow() ret addr替换为do_overflow()的地址
为了要保证正常退出,需要把ret addr+4的地方填上本来应该返回的地址,以便从do_overflow()返回原本应该的overflow_me(),相当于mask掉做的坏事�
两位两位处理
有个字符串str 256老发报警,改成255就好了
Ex17 搞不定command怎么处理
Ref
https://xinqiu.me/2016/10/15/MIT-6.828-1/