ITEEDU

不难看出EXE程序比COM程序要优越,但有一点要说明:DOS调入EXE程序的速度比调入COM程序要慢,因为DOS要做一些额外的工作来保证EXE程序正确地运行。所以对于一些小程序,即使包括代码和数据,也不一定要用EXE程序的形式,采用COM程序的形式会更紧凑。程序PROG9.ASM给出了一个包括数据和代码的COM源程序:

code	segment							;代码段开始
	assume	cs:code,ds:code				;通知编译程序CS、DS寄存器均指向代码段
	org	100h							;设置偏移地址为0100H
main	proc	near					;主过程开始
	jmp	start 							;跳过数据区 
			
mess	db 'Hello,World!',0dh,0ah,24h 	;定义一个字符串 
			
start:	mov	dx,offset mess				;程序开始,取得字符串首地址
	mov	ah,09 							;选择DOS API的09功能
	int	21h								;显示字符串
	int	20h								;结束程序,返回操作系统
			
main	endp	main 					;主过程结束
code	ends							;代码段结束
	end 								;进程结束 

这个程序是前面给出的PROG3-B的源程序形式,程序中的"START"是一个标号,它表示了指令"MOV DX,OFFSET MESS"的地址,值得注意的是它后面多了一个":",这个冒号是必须的。将这个程序编译成COM文件后我们可以用DEBUG将代码反汇编出来,和PROG3-B作个对比:

 C:\ASM\>DEBUG   PROG9.COM [Enter] 
-u100[Enter]
0A3E:0100		EB10		JMP		0112
0A3E:0102		90			NOP		
0A3E:0103		48			DEC		AX
0A3E:0104		65			DB		65
0A3E:0105		6C			DB		6C
0A3E:0106		6C			DB		6C
0A3E:0107		6F			DB		6F
0A3E:0108 		2C57 		SUB 	AL,57 
0A3E:010A		6F			DB		6F
0A3E:010B		726C		JB		0179
0A3E:010D		64			DB		64
0A3E:010E		210D		AND		[DI],CX
0A3E:0110		0A24		OR		AH,[SI]
0A3E:0112		BA0301		MOV		DX,0103
0A3E:0115		B409		MOV		AH,09
0A3E:0117		CD21		INT		21
0A3E:0119 		CD20		INT 	20

区别是很明显的:字符串本是数据,但DEBUG将它们当成了指令机器码,这是DEBUG不够聪明的地方;最奇怪的是"JMP 0112"下面多了个"NOP",这又是什么呢?

"NOP"是一条真正的指令,它不执行任何实际的动作,是一条"空操作"(No Operation)指令。这就让人有些犯迷糊了,源程序中并没有这个指令,为什么编译后却多了这样一个东西?想搞清这个问题,我们就必须先详细讨论和转移指令有关的"短程、近程与远程"的问题。

JMP指令究竟被编译成什么样子?观察PROG9的反汇编形式,可以看到JMP 0112的机器码是"EB 10"两个十六进制数。如果"EB"是"JMP"指令对应的机器码,那么"10"又是什么呢?目的地址"0112"又在何处呢?

如果把目的地址"0112"同指令"NOP"的地址做一次减法,问题就清楚了:
0112H - 0102H=10H

"10"是目的地址相对"JMP"后面指令所在位置的偏移量,具体的目的地址并不出现在机器码中,而要由CPU自己算出来。这种情况仅限于"短程"和"近程"转移,远程转移时目的地址将以"段:偏移"的形式出现在机器码中。

对于"短"转移来讲,由于偏移量在-128--+127之间,使用一个字节即可记录偏移量,所以短转移指令仅占两个字节。而近转移的偏移量要用两个字节记录,整个指令要占三个字节。

当使用MASM或TASM编译源程序时,编译程序要对源程序作两遍扫描。由于在源程序中未明确给出"JMP"指令是短程还是近程,所以编译程序在第一遍扫描时就默认"JMP"指令是近程的,并在目标程序中为其保留了三个字节空间。然而在第二遍扫描时编译程序算出其偏移量 小于+127,仅占一个字节,因此,编译程序便自动地将另一个字节置成"90H",于是在可执行程序中就有了"NOP"指令。

如果不想程序中出现"NOP"指令,那么就必须在源程序中明确指出"JMP"指令是"短程"跳转,这只需将第一条指令改写成"JMP SHORT START"即可,指令中的"SHORT"就是告诉编译程序将此处的"JMP"指令处理为短程转移。