ubuntu12.04编译调试inux0.11(引导+根文件系统集成盘)

最近看《linux内核设计的艺术》,主要讲述了linux0.11从启动到进入怠速状态的整个过程,讲解的非常透彻,图文并茂。但是如果没有实验环境,纵使把整本书都读懂了,还是不能入木三分。所以一直想搭建一个跟此书配套的实验环境,搞了好几天,终于完成,现总结一下。

集成盘的代码和根文件系统是在赵炯的两个包的基础上修改的:linux-0.11-060618-gcc4.tar.gzbootroot-0.11-040928.zip

一、编译错误有两处,修改比较简单:

①:blk.h86行 #elif  修改为 #elif 1。 

②:fskernelkernel/chr_drv下的MakefileCFLAGS中添加-fno-stack-protector参数。

二、修改根目录下Makefile文件,最终编译成引导+根文件系统的集成盘:

①:第5RAMDISK =  #-DRAMDISK=512 修改为 RAMDISK =  -DRAMDISK=2048

②:第23ROOT_DEV= #FLOPPY 修改为 ROOT_DEV= FLOPPY 

③:第44行后面添加:

dd bs=1024 if=/dev/zero of=bootroot count=1024
dd bs=1024 if=Image of=bootroot conv=notrunc
dd bs=1024 if=bootroot-0.11 of=bootroot conv=notrunc skip=256 seek=256

最后生成的集成盘bootroot前256kImage的内容。后面的内容需要用到bootroot-0.11-040928.zip中的bootroot-0.11,该文件256k后面的内容可以作为根文件系统。

当然,也可以参考赵炯的《Linux内核完全注释》17.7小结自己制作根文件系统的,里面也主要是从现成的系统里面拷贝。这里我就不麻烦了。不过这里让我很好奇,linux0.11一开始的根文件系统是谁开发的呢?源代码不知道网上有没有?

④:为了后面调试方便加了一些反汇编的语句:

objdump -D tools/system > system.dasm

$(AS86) -l setup.list -o boot/setup.o boot/setup.s

$(AS86) -l bootsect.list -o boot/bootsect.o boot/bootsect.s

三、通过上面的修改,就可以编译生成集成盘bootroot了,但调试花了一些时间,虽然总结起来也并不是太复杂:

①:不停的Loading system

通过在关键位置打断点,发现运行到head.s开始处时,反汇编代码并不是head.s的。查看System.map文件,发现main函数被编译到了位置0x0处。这是编译问题,尝试修改编译链接的参数,最后把Makefile文件中CFLAGS的参数-O2 修改为 -O就行了。


②:通过上面的修改,系统还是停留在Loading system处。

系统能运行到sys_pause处,但运行不到init处。在sys_pause打断点,查看系统进程表task的数据状态,发现进程1没有被正常创建,进程0的数据结构没有正常拷贝给进程1


再次把断点copy_process函数的*p = *current处,发现错误是由于df没有被清除导致的。


DF是是在哪里被置位的呢?

查看代码发现前面的get_free_page函数中有sti语句,但并没有配套的cld语句。

网上有一篇文章,对这个问题讲解的不错http://blog.chinaunix.net/uid-27062906-id-3380279.html

谷歌也没有令我失望,我找到了下面这段文字:从gcc4.3开始的,官方文档如下:
GCC no longer places the cld instruction before string operations. Both i386 and x86-64 ABI documents mandate the direction flag to be clear at the entry of a function. It is now invalid to set the flag in asm statement without reseting it afterward.
就是说在string操作之前,编译器不再插入cld指令。因为i386x86-64的官方文档都明确要求在进入一个函数时要把方向标记(DF)清除,汇编指令设置方向标记(std)而不清除属于非法!

最终,解决这个问题应该在在get _free_page函数第77行后添加"cld"语句。

③:修改后还是不能进入系统,panic退出。但虚拟盘正常加载了。


由于有panic消息,就很容易定位了。添加一些printk消息,再次运行后,发现错误是由于s->s_magic != SUPER_MAGIC导致的。


断点到前面的*((struct d_super_block *) s) =*((struct d_super_block *) bh->b_data)处,发现没有读到虚拟盘超级块的内容, bh->b_data所指内存处内容为空。


这样就可以推断是rd_load拷贝根文件系统进入复制虚拟盘时有问题了,难道也是DF位没清除的原因吗?定位到rd_load函数中memcpy处一看究竟。

DF和地址都正确,但循环一次后edi的值就不正确了。


观察反汇编代码可以再次证明是edi值错误导致的。

   1284a: 8b 30  mov (%eax),%esi
   1284c: b9 00 04 00 00  mov $0x400,%ecx
   12851: fc  cld    
   12852: f3 a4 rep movsb %ds:(%esi),%es:(%edi)  这里edi的值会增加
   12854: 89 04 24 mov %eax,(%esp)
   12857: e8 07 8e ff ff  call b663 <brelse>
   1285c: 89 6c 24 04 mov %ebp,0x4(%esp)
   12860: c7 04 24 b0 60 01 00movl $0x160b0,(%esp)
   12867: e8 40 55 ff ff call 7dac <printk>
   1286c: 81 c7 00 04 00 00  add $0x400,%edi  这里edi的值也会增加

最终,修改memcpy的第10行为__asm__ ("pushl %%edi;cld;rep;movsb;popl %%edi" )

再次编译,可以正常进入系统。留图纪念 !


编译:ubuntu12.04  gcc4.6.3

调试:windows7 Bochs-2.4.5 peter-bochs-debugger20120606

相关资料:

bootroot-0.11.7z 已经编译好的集成盘和调试环境

linux-0.11.7z 源码

bootroot-0.11-040928.7z 根系统

linux-0.11-060618-gcc4.tar.gz 基础源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值