六、内存管理

几个调试心得,一个小的不起眼的bug(完全由自己的不细心造成),导致自己饶了弯路,调了2天。好在也积累了一些经验,吃一堑长一智嘛!尽快记录一下,免得下次再犯。

  • GP exception(General Protection):出现这个处理器异常的,显然就要考虑是特权级错误,因为在保护模式下,有可能是段描述符初始化的时候特权级设置错误。
  • 要特别注意循环语句中修改代码的时候,一些特殊的continue分支的加入,可能导致会跳过循环变量的更新,特别是while循环这种需要把循环变量更新写在循环体里的语句,或者是for语句有多个要更新的循环变量的时候,最好更新都写在for里。
  • 有意思和写法相近的几个变量时,不要被智能提示误导,要注意区分。
  • 低特权级的代码无法直接调用高特权级的代码。但是由于我们在写OS的时候,各种特权级的代码可能都写在一起,容易造成混淆。比如,在kernel/main.c的kernel_main()函数里,很明显这是一个ring0的代码,但是如果使用printl甚至是printf来进行打印字符的话,显然就会出现这个错误,因为这两个函数都属于用户库函数,处于ring3,在执行ring0代码的时候,很有可能printf等机制还没建立。
  • 对一个主要的结构体添加了一个成员变量后就要立即考虑它的初始化和更新,因为这时往往结构体中其他变量的初始化和更新都早就完成,如果不立即完成新变量的更新,后面很容易忘记。比如在给struct proc也就是进程结构体里添加文件相关的filp[]->fd_cnt时,就忘记了在涉及到filp[]初始化或者更新相关的地方更新相关操作(比如忘记更新close()里的操作),导致在fork()和exce()时进程占用文件部分操作没能正确更新,从而使得通过fork产生的新的shell进程(分别对应tty1和2)在分别打开/dev_tty1和/dev_tty2设备文件的时候 出现问题,两个shell对应的文件描述符有问题,tty1的输出也会输出到tty2,然后卡住。

将lib/里的函数制作C运行时库(CRT)并和自己写的应用程序链接

  • 制作CRT链接库yescrt.s的时候并没有问题,但是在将自己写的程序echo和yescrt.a链接起来的时候却 出现了以下错误:
../lib/yescrt.a(exit.o):在函数‘exit’中:
exit.c:(.text+0x2b):对‘send_recv’未定义的引用
../lib/yescrt.a(write.o):在函数‘write’中:
write.c:(.text+0x38):对‘send_recv’未定义的引用

受这篇博文启发,我找到了原因。原文链接

出现这种情况的原因,主要是C/C++编译为obj文件的时候并不需要函数的具体实现,只要有函数的原型即可。但是在链接为可执行文件的时候就必须要具体的实现了。如果错误是未声明的引用,那就是找不到函数的原型,解决办法这里就不细致说了,通常是相关的头文件未包含。

所以,应该是因为send_recv()函数的定义没有在我们制作yescrt.a这个库的那些.o文件里。经过查找,果然,在写IPC部分的时候,为了图方便/home/ye/study/makeOS/YesOS/ch11/2.Boot_from_HD/xxd.sh,我把对sendrec这个系统调用进行多一层封装的函数send_recv也放在了kernel/proc.c文件里,所以这个接口的函数体定义没有在lib文件夹中的文件里,也就造成了yescrt.a里只有声明没有定义。

你可能感兴趣的:(一个操作系统的实现)