现在已经走到了执行第一个任务的地方了,如下
main() |-->init_kernel() | |-->kernel() -> p_0() -> DosExec(..."COMMAND.COM"...)
官方给出的COMMAND.COM是FreeCom,FreeCom有些复杂,既然我们研究的是COM文件加载执行,何不选择一个较小的COM文件,岂不更方便?
很多编程语言的第一个示例都是”Hello World”,这里我们也不脱俗,也用个只显示Hello World的COM文件作为研究对象。
编译命令: nasm HelloWrold.asm -o COMMAND.COM
将COMMAND.COM放到Image(虚拟软盘)上,有很多种方法,也可以参考第二节,将这个COMMAND.COM放到build目录下,执行build.bat即可。
运行截图如下,左上角显示Hello World:
先说下COM文件吧,上面的汇编代码设置 org 0100h, 为什么是0x100呢?
在COM执行前,DOS需要给COM分配256个字节的PSP段,用于保存程序状态。详见http://en.wikipedia.org/wiki/Program_Segment_Prefix 将COM载入内存后,设置IP为0x100,即COM起始处。
下面就分析COM的加载执行过程:
因为是COM文件,所以流程为DosExec() -> DosComloader(),Kernel先设置好环境变量,然后将COMMAND.COM加载进内存,如下图
加载完后,在COMMAND.COM内存前0x100处设置PSP,然后设置新任务的寄存器及栈空间,最后执行跳转:
上面的代码,先在当前段的末尾处划分块空间,保存新任务的寄存器。以当前版本为例,此时mem段为0x13EB,为新任务选择的栈地址为0x13EB:0xFFFE。 切换任务后,CS:IP为 13EB:100,即COMMAND.COM所在内存地址,开始执行COMMAND代码。 下面是任务切换前后CPU的寄存器对比:
寄存器 任务切换前 任务切换后,执行COMMAND.COM _exec_user执行前 _exec_user执行后 AX 13EB FFFF BX 0000 0000 CX 0004 0000 DX 0080 0000 SP 283E FFFE BP 286A 0000 SI 0005 0000 DI 0000 0000 CS 0060 13EB DS 0F40 13EB SS 0F40 13EB ES 13EB 13EB IP E421 0100 Flags 0246 0202
最后,是COMMAND.COM执行时内存分配图: