现在已经走到了执行第一个任务的地方了,如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12


main()


      |-->init_kernel()


      |


      |-->kernel() -> p_0() -> DosExec(..."COMMAND.COM"...)

官方给出的COMMAND.COM是FreeCom,FreeCom有些复杂,既然我们研究的是COM文件加载执行,何不选择一个较小的COM文件,岂不更方便?

很多编程语言的第一个示例都是”Hello World”,这里我们也不脱俗,也用个只显示Hello World的COM文件作为研究对象。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63


;HelloWrold.asm


	org	0100h		; COM文件必须从偏移 0x100开始





	mov	ax, cs


	mov	ds, ax


	mov	es, ax


	call	ShowHelloWorld	; 调用显示Hello World


	jmp	$		; 死循环


	;mov ah, 4ch		; 回退到DOS系统,在此不需要


	;int 21h





ShowHelloWorld:


	mov	ax, HelloStr


	mov	bp, ax		; ES:BP = 串地址


	mov	cx, 12		; CX = 串长度


	mov	ax, 01301h	; AH = 13,  AL = 01h


	mov	bx, 000ch	; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮)


	mov	dl, 0


	int	10h		; int 10h


	ret


HelloStr:	db	"Hello World!"

编译命令: nasm HelloWrold.asm -o COMMAND.COM

将COMMAND.COM放到Image(虚拟软盘)上,有很多种方法,也可以参考第二节,将这个COMMAND.COM放到build目录下,执行build.bat即可。

运行截图如下,左上角显示Hello World:

pic


先说下COM文件吧,上面的汇编代码设置 org 0100h, 为什么是0x100呢?

1
2
3


在COM执行前,DOS需要给COM分配256个字节的PSP段,用于保存程序状态。详见http://en.wikipedia.org/wiki/Program_Segment_Prefix 将COM载入内存后,设置IP为0x100,即COM起始处。 

下面就分析COM的加载执行过程:

因为是COM文件,所以流程为DosExec() -> DosComloader(),Kernel先设置好环境变量,然后将COMMAND.COM加载进内存,如下图

pic

加载完后,在COMMAND.COM内存前0x100处设置PSP,然后设置新任务的寄存器及栈空间,最后执行跳转:

pic

上面的代码,先在当前段的末尾处划分块空间,保存新任务的寄存器。以当前版本为例,此时mem段为0x13EB,为新任务选择的栈地址为0x13EB:0xFFFE。 切换任务后,CS:IP为 13EB:100,即COMMAND.COM所在内存地址,开始执行COMMAND代码。 下面是任务切换前后CPU的寄存器对比:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48


寄存器   任务切换前      任务切换后,执行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执行时内存分配图:

pic