MIT_OS_lab1
小记
前两周面了华为和腾讯的安全岗,嗯,面得和屎一样,另外趋势和360也笔试就挂了,长亭今天邮件发来说我作为实习生可能都不够格,说到底是自己太菜了,都问到了操作系统和内核的问题,都不会。。。这方面知识太缺乏了,应该是各个方面的知识都太缺乏了,下定决心要潜心学习了,暑假看到过这个MIT的课程但是当时没有坚持下来,毕竟是英文的,而且自己还很菜,现在不打算去搞秋招了,把时间用来专心地研究!加油!
前奏
从MIT下载的JOS系统刚开始make后,make qemu一直不成功,出现这样的错误
模拟器的画面如下
在另一终端同一文件夹我们使用gdb来打印错误信息
可以看到系统运行停止的位置eip为0xf01015e8,x/i显示是memset函数,这样我们找到函数出错的地方了,那么我们在memset函数入口设置断点,查看是哪一个指令出现错误,上面系统已经终止运行,所以无法获取内存中的内容,重新make qemu-gdb,gdb,这样会在boot程序入口设置断点:
可以看到发生错误时eip为 0xf01015e8 <+73>: rep stos DWORD PTR es:[edi],eax,这个指令适用于在edi位置存储ecx个eax,也就是说从edi开始到edi到edi+ecx的内存的每个DWORD全部被覆盖成eax,我们在这个地方设置断点看看,刚开始是否可以运行,
可以看到这个指令可以运行2次了,那么我们就不步进了,直接continue到错误发生地点
可以看到这里,程序终止时ecx=0x1a9,edi=0xf0113000,ecx并没有变成0,也就是说还需要继续覆盖,但是这里终止了,由于操作系统可以访问任意地址,不存在无法读的问题,覆盖行为是写操作,导致终止的原因就很明显了,那就是向只读(readonly)区域执行了写操作,可以看到0xf0113000是charcode的内存,同时gdb告知了错误指令在lib/string.c:131,那么我们去查看string.c
这里发生错误的原因在于传入的地址v是错误的,那么我们就要找到是哪个函数传入了这个参数,使用grep
程序都有一个entry入口,整个内核的执行顺序也和这个make的编译顺序差不多,结合上面的搜索,我们把memset错误参数的传入的位置初步确定在init.c,查看源代码
结合之前发生错误时的截屏中没有打印
所以我们把传入错误参数的位置最终确定在init.c i386_init(void)这个函数中的memset(edata, 0, end - edata),接下来就要找这edata在哪里定义,是extern变量,那么我们用grep继续查找
其他地方都是引用,只有在kern/kernel.ld: PROVIDE(edata = .);出现了类似定义的字样,赶紧去学一会链接器的知识,发现这个语法确实是定义。结合前面i386_init函数memset前的三句注释,我们可以得知这个edata是bss段的开始地址,end是bss段的结束位置。
打开kern/kernel.ld,找到定义该变量的位置
好像是没什么问题这个定义,我又去xv6-os的ld文件看了一下,也是这样定义的,那问题处在哪呢?我们可以看一眼最终可执行文件的段的地址,objdump
可以看到0xf0113000是.data.rel.ro.local这个段的地址,这个段是用来于重定位的,并设置了readonly标志,显然edata不是bss段的开始,那么要修改它变成bss的开始地址(在xv6-os中的edata是可用的原因是xv6编译时完全重载,所以没有这个重定位的段got,plt等等,data段直接与bss段相连)。
把edata放入.bss定义中,总算成功了,不知道这样做规范不规范,whatever,it works.