除了前面讲过十六进制数末尾加"H"之外,汇编语言还规定二进制数末尾要加"B"(Binary),八进制数加"O"(Octal),十进制数加"D"(Decimal)。不过有两点需要注意的地方:
① 若一个数末尾不加任何标识,则编译程序默认这个数为十进制;
② 以A-F打头的十六进制数前要补"0"。1111B、15、15D、17O、0FH表示的是同一个数。
在PROG7.ASM中,幻数用二进制数10110110B表示,端口地址都用了十六进制数,而系统功能都用了十进制数。编译程序将自动处理这些不同进制的数据。
在程序头部的尾部还新增了不少"伪操作",伪操作的概念在第三章中已讨论过,它虽然和指令写在一起,但它并不是写给CPU的,而是写给编译系统的。当应用DEBUG编程时这些伪操作要由DEBUG完成,现在要使用真正的汇编语言编译系统,伪操作自然要由编译程序完成。我们先来讨论程序的第一行和倒数第二行:
"SEGMENT"是"段定义"伪操作,它表示一个段的开始。其中"CODE"是这个段的名字,表示这个段的段地址。名字可以是除了汇编语言保留字之外的任何字符串,但要注意打头的字母不能是数字。
为什么要定义段?以前应用DEBUG编制程序时我们并未考虑分段的问题,所有的数据和指令都在一个段内,这就有这样一个问题,一个段长度只有64K,也就是说用DEBUG编制的程序长度不能超过64K,再明确一点,凡是".COM"类的可执行文件都不能大于64K。这个限制使".COM"类文件的应用范围受到制约。
如何突破64K的限制?可以设想只要把代码、数据和堆栈分别放入不同的段内,甚至把代码中的各个子程序(模块)也分散到不同的段内,这样就可以使程序超出64K,这就是".EXE"文件的结构。因此在编制源程序的时候就需要定义不同的段。
ENDS伪操作和SEGMENT是相配合的,表示一个段结束。需要注意的是段的名字表示了这个段的起始段地址,它和段的性质并无关系,所以并不是名为"CODE"的段就一定是代码段。
对于PROG7来说,由于程序只需要一个代码段就可以了,所以只定义了一个"CODE"段,后面我们会谈到定义多个段的方法。
伪指令"ORG"的主要作用就是控制偏移量。它不仅可以用于代码段中,也可用于其它段。而且这个伪指令不仅单用于程序省首部,在程序之中也可以插入使用。
PROG7只有一个代码段,因此它可以编译成.COM类的可执行文件。注意.COM类的程序都要从偏移0100H处开始执行,所以在源程序中也要明确指出程序第一条指令的偏移为0100H,这就是指令"ORG"的作用。
程序中的第三行和倒数第三行是"过程定义"伪操作。讲到这儿我们需要先明确几个概念:大家知道,一个程序往往由一个主程序和若干子程序组成,在汇编语言中,我们称其为"主过程"和"子过程"。而把由"主过程"和"子过程"共同组成的完整的程序称为"进程"。因此在编写一个"进程"时就需要用"过程定义"伪操作将不同的"过程"区分开,这就要用到"PROC"伪指令。
"PROC"伪指令的应用格式很简单,"过程名 PROC 属性"。其中过程名表示了这一过程的起始地址,它和这一过程是"主"还是"子"没有任何联系。名字不决定属性,这个特点同"SEGMENT"一样;属性指的是这一过程是"近程"(NEAR)还是"远程"(FAR),它将决定调用此过程的CALL指令和过程最后的RET指令的编译结果。
结束一个过程在形式上和结束一个段相似,只是END后面加了表示过程(PROCEDURE)的字母"P"而不是表示段(SEGMENT)的"S":"过程名 ENDP"。
在"PROC"与"ENDP"之间的就是真正的代码,最后一行的"END"伪指令用于表示"进程结束",即整个源程序编制完毕。
伪指令"END"的用法很简单:"END 过程名"。跟在它后面的"过程名"指出了整个程序的入口,也就是程序中"主过程",这个过程是DOS调入程序后首先要执行的。当然,这个过程名在某些情况下可以省略,比如在编写"COM"类程序的时候。
所有这些伪操作和实际代码共同组成了完整的源程序,其大致结构为"段"内含着"过程","过程"内含着"指令",最后用"END"结束"进程"并指出"主过程"。
这样的源程序可以用行编辑器(EDLIN)或全屏编辑器(WS、WPS、EDIT)编制并将它们以"ASM"为扩展名保存在磁盘上,接下来的工作就是用编译程序将这些源程序文件译成可执行的程序文件。通常使用的编译程序有两种,一种是由MicroSoft开发的MASM(Macro Assembler),另一种是由Borland开发的TASM(Turbo Assembler)。