Part 1:
遇到问题1:我将JOS放在Windows的目录下 ,通过VMware设置共享该文件夹来编译JOS,但是Windows更改linux下设置的权限,导致GDB无法调试QEMU.
解决方法:将JOS放在虚拟机下的linux的目录下 2011.12.13
问题2: make qemu-gdb启动qemu后,在令一个终端中gdb调试,则qemu关闭,原因不知
原因:可能是安装qemu时使用的root权限,而使用qemu时,为用户态权限
解决方法:执行make qemu-gdb与执行gdb的两个权限相同。(注意启动gdb时,别忘记进入到lab的目录下)
Part2 :
main.c 的作用是将内核ELF文件读写到内存0x10000开始的地方 2012.1.10
boot loader的入口地址为0x7c00,kernel的入口地址为0x10000c 2012.1.13
问题1: i386-jos-elf-objdump 无法找到?
由于我们采用fedaro,没有自己建立编译链,所以这里使用objdump 2012.1.10
问题2:如果将boot/makefrag中的链接地址由0x7c00改为0x7ccc,则boot部分执行,但是kernel跑不起来
这是为什么呢?2012.1.11 其实并没有执行boot loader,本系统中VMA=LMA,所以当bios跳转到0x7c00时,boot loader无法执行,导致kernel无法加载,进而无法执
行。2012.4.4
Kernel的LMA和VMA的地址不一致?请参看part3开头部分,Kernel的LMA和VMA就是不一样,而boot loader的LMA和VMA 是一样的2012.4.7
问题3:boot.asm中,7d74语句(也就是ELFHDR->e_entry)语句中,call *0x10018, 但是GDB中,如果开始便设置断点0x100018,便开始C命令,执行不到0x10018,便把内核给启动起来了,这是为什么呢?2012.1.13
在0x7d74处设置断点,执行到此处,而后用si命令执行一条指令,就跳转到0x10000c处了,...这个为什么? 难道内核入口地址为0x10000c? 经验证,果然如此,与objdump -f kernel看到的一致
问题4:boot loader编译为ELF格式吗?Kernel编译为ELF格式,那么在硬盘中如何指定boot loader 放在第一个扇区,kernel放在哪里呢? Kernel与bootloader是放在文件系统中吗?2012..4.4
boot loader为ELF格式,在obj/boot中;kernel也为ELF格式,在obj/kern中。而最后 生成的image应该为这两个的结合(猜测)2012.4.7
Part3:
问题1: kernel的LMA和VMA为什么不一致?
因为一般在虚拟地址空间中,操作系统占据高地址内存,而用户程序占用低地址内存,所以kernel的VMA为很大的值0xf0100000开始的。而LMA为kernel的加载地址,这个加载器就是boot loader,boot loader将kernel加载到物理内存LMA地址处,那么怎么让这个地址与VMA地址对应起来,这就需要MMU地址映射来实现了。LMA由程序加载进内存物理地址和加载器有关。(boot/boot.S set up an identity mapping from linear addresses to physical addresses)
操作系统需要在高地址执行,但是只能被boot拷贝到低地址!
Exercise7解答:
将mov %eax,%cr0 注释(comment out)后,执行到0x10002d: jmp *%eax处出错,因为map不成功,则eax中的地址0xf010002f无效,所以出错。这也看出,程序中地址都是virtual地址,gdb调试时也是虚拟地址。2012.4.7此处由于GDT设置,如果没有页机制,则物理地址与虚拟地址一样。2012.7.7
Exercise8解答:
vprintfmt函数中,
case 'o':
num=getuint(&ap,lflag);
base=8;
goto number;
Question1: kern/printf.c中调用lib/printfmt.c中的vprintfmt(),vprintfmt()调用kern/printf.c中的putch函数,putch函数调用kern/console.c中的cputchar函数。最终cputchar函数实现了字符打印。2012.4.7
Question2:当屏幕打满时,需要将第一行去掉。所以进行这些处理。
Question3:请先参看我的文章《esp ebp eip 函数压栈》
ap类型为va_list,指后面的几个参数。fmt指向前面的字符串。
Question4: 打印出来是He110, World ,其中0x00646c72,翻译为ASCII就是rld.
Question5: 这个结果是不可欲知的,原因请看<<c and pointers>>中关于可变参数的介绍
Question6:未做 2012.7.9
Exercise9 :
在文件entry.S中,bootstack与bootstacktop定义了堆栈,KSTKSIZE为堆栈大小,为8页内存大小。使用movl $(bootstacktop),%esp对堆栈指针进行赋值。kernel stack的load地址为KSTACKTOP,值为KERNBASE-PTSIZE.
有些东西未搞明白! 2012.7.9
在entry.s中,Jump up above KERNBASE enterting的做法,说明ld后的这些relocated这样的符号都转化为了vm地址。
Exercies10:
其他
1. 为什么kern/kernel中的makefile文件中,生成OS image的方法为:
$(V)dd if=/dev/zero of=$(OBJDIR)/kern/kernel.img~ count=10000 2>/dev/null
$(V)dd if=$(OBJDIR)/boot/boot of=$(OBJDIR)/kern/kernel.img~ conv=notrunc 2>/dev/null
$(V)dd if=$(OBJDIR)/kern/kernel of=$(OBJDIR)/kern/kernel.img~ seek=1 conv=notrunc 2>/dev/null
$(V)mv $(OBJDIR)/kern/kernel.img~ $(OBJDIR)/kern/kernel.img
这个kernel是什么格式的?是elf还是bin格式? 我感觉应该是ELF格式的两个文件拼接到了一起。ELF 是X86可以执行的二进制文件(ELF binary)
2. boot/main.c中,最后((void *)(void)(ELFHDR->e_entry))(),这个跳转到0xf010000x处,但是gdt表中,这个地址超出了实际物理内存范围,怎么能够跳转到kern/entry.s中去呢?
entry.s中,_start的定义应该是启到了某种作用,但是不明白!!!??????
3. 汇编语言中的标号,经连接后变为线性地址,是以线性地址的值来保存的。 2013.7.12
4.数组在栈上分配时什么意思? 函数传递过程中,参数是什么?是值吗? 应该是的!
5. 汇编器生成ELF,可链接格式,可relocation重定位的多个section, 有section table;连接器将多个section进行合并成segment,生成可执行的elf,有program table.
6. 汇编器生成的为相对地址,而链接后生成为绝对线性地址。使用ld链接脚本来控制内存分布。
7. entry入口点:现在要执行程序B, 如果A知道要调转到B的何处去执行,则不使用entry;如果A不知道跳转到B的何处去执行,则跳转到entry去执行,因为这是B希望的入口点。
8. 可见.shstrtab
段保存着各Section的名字,.strtab
段保存着程序中用到的符号的名字和地址。