1、源程序的基本组成
汇编语言源程序的组成部分有:模块、段、子程序和宏等。一个模块对应一个目标文件,当开发较大型的应用程序时,该程序可能由若干个目标文件或库结合而成的。
1.1、段的定义
微机系统的内存是分段管理的,为了与之相对应,汇编语言源程序也分若干个段来构成。8086CPU有四个段寄存器,在该系统环境下运行的程序在某个时刻最多可访问四个段,而80386及其以后的CPU都含有六个段寄存器,于是,在这些系统环境下开发的运行程序在某个时刻最多可访问六个段。
不论程序在某个时刻最多能访问多少个段,在编程序时,程序员都可以定义比该段数更多的段。在通常情况下,一个段的长度不能超过64K,在80386及其以后系统的保护方式下,段基地址是32位,段的最大长度可达4G。
段的长度是指该段所占的字节数:
①如果段是数据段,则其长度是其所有变量所占字节数的总和;
②如果段是代码段,则其长度是其所有指令所占字节数的总和。
段定义的一般格式如下:
段名 SEGMENT [对齐类型] [组合类型] [类别]
… ;段内的具体内容
…
段名 ENDS
其中:
①“段名”必须是一个合法的标识符,前后二个段名要相同。程序中的段名可以是唯一的,也可以与其它段同名。在同一模块中,如果有二个段同名,则后者被认为是前段的后续,这样,它们就属同一段。当同一模块出现二个同名段时,则后者的可选项属性要么与前者相同,要么不写其属性而选用前者的段属性。
②对齐类型(ALIGN):对齐类型表示当前段对起始地址的要求。连接程序(LINK.EXE)按表6.1的地址格式来定位段的起始地址。在进行段定位时,会根据其定位类型进行定位的,所以,各段之间就有可能出现一些空闲字节,即可能浪费几个字节单元。
段对齐类型PARA是一个适用于所有段类型的对齐类型,它也是缺省的对齐类型。对齐类型BYTE和WORD通常用于数据段的定位,对齐类型DWORD通常用于80386及其以后CPU代码段的定位。
③组合类型(COMBINE):组合类型是告诉连接程序如何把不同模块中段名相同的段合并在一起。
④类别(CLASS): 类别是一个由程序员指定的用单引号括起来的字符串。缺省为空。类别是用于段的分类,连接程序利用该类别来调整同名、同类别的段,并使它们相邻。典型的类别是"Data"和"Code"。
一个数据段的定义例子:
DATA1 SEGMENT
word1 DW 1, 9078H, ?
byte1 DB 21, 'World'
DD 12345678H
DATA1 ENDS
1.2、段寄存器的说明语句
在汇编语言源程序中可以定义多个段,每个段都要与一个段寄存器建立一种对应关系。
建立这种对应关系的说明语句格式如下:
ASSUME 段寄存器名:段名[, 段寄存器名:段名, ……]
其中:段寄存器是CS、DS、ES、SS、FS和GS,段名是在段定义语句说明时的段名。
例如:
ASSUME CS:CODE1, DS:DATA1
上面的语句说明了:CS对应于代码段CODE1,DS对应于数据段DATA1。
在ASSUME语句中,还可以用关键字NOTHING来说明某个段寄存器不与任何段相对应。
例如:ASSUME ES:NOTHING
在通常情况下,代码段的第一条语句就是用ASSUME语句来说明段寄存器与段之间的对应关系。在代码段的其它位置,还可以用另一个ASSUME语句来改变前面ASSUME语句所说明的对应关系,这样,代码段中的指令就用最近的ASSUME语句所建立的对应关系来确定指令中的有关信息。
ASSUME说明语句只起说明作用,它不会对段寄存器赋值,所以,必须对有关段寄存器赋值。
注意:代码段寄存器不能由程序员在源程序中对其赋值,其值是由操作系统在装入它进入系统运行时自动赋值的。
1.3、堆栈段的说明
堆栈段是一个特殊的段,在程序中可以定义它,也可以不定义。除了要生成COM型执行文件的源程序外,一个完整的源程序一般最好定义堆栈段。如果在程序中不定义堆栈段,那么,操作系统在装入该执行程序时将自动为其指定一个64K字节的堆栈段。
在程序没有定义堆栈段的情况下,在由连接程序生成执行文件时,将会产生一条如下的警告信息,但程序员可以不理会它,所生成的执行文件是可以正常运行的。
warning xxxx: no stack segment (其中:xxxx是错误号)
在源程序中,可用以下方法来定义堆栈段:
STACK1 SEGMENT STACK ;定义一个堆栈段,其段名为STACK1
DB 256 DUP(?)
STACK1 ENDS
系统会自动把段寄存器SS和栈顶寄存器SP与该堆栈段之间建立相应的关系,并设置其初值。
2、简化的段定义
2.1、存储模式
在使用简化的段定义方式之前,必须使用存储模式说明伪指令来描述源程序所采用的存储模式。
该伪指令说程序所使用的存储模式,汇编程序将用该存储模式生成相应的ASSUME和GROUP语句,同时也为其它的简化段创建等价的预定义。
程序存储模式说明伪指令的格式如下:
.MODEL 存储模式[,语言类型] [,操作系统类型] [,堆栈类型]
伪指令.MODEL必须写在源程序的首部,且只能出现一次,其前内容只能是注释。
①存储模式:程序可选的存储模式有:TINY、SMALL、COMPACT、MEDIUM、LARGE、HUGE和FLAT。
②语言类型:可以是任何一种有效的程序设计语句类型,由它来告诉汇编程序将使用什么样的标识符的命名风格、子程序的调用和返回约定。
③操作系统类型:OS_DOS是当前唯一支持的选项值,也是该选项的缺省值。
④堆栈类型:该选项有二个可选值:NEARSTACK(缺省)和FARSTACK.
NEARSTACK——堆栈段和数据段是同一段;
FARSTACK——堆栈段和数据段是不同的段,且堆栈不在段组DGROUP中。
例如:
.MODEL SMALL, C, OS_DOS, FARSTACK
2.2、简化段定义伪指令
简化段定义伪指令在说明一个新段即将开始的同时,也说明了上一个段的结束。在本段定义结束时,也不必用伪指令“ENDS”来标识。
①代码段定义:.CODE
②堆栈段定义:.STACK [堆栈字节数]
③数据段定义:.DATA / .DATA? / .CONST
伪指令.DATA?说明下面是一个未初始化数据段的开始,伪指令.CONST说明下面是一个常数数据段的开始。这二条伪指令很少使用,除非在与高级语言编写的程序相结合时,为了遵守高级语言的某些约定,而需要特殊说明时才使用。
汇编程序在处理简化的堆栈段和数据段定义时,它会自动地把伪指令.STACK、.DATA、.DATA?和.CONST所定义的段组合成一个段组。如果想定义一个独立的、不与其它段组合在一起的数据段的话,那么,就可选用下面的数据段定义方式。
④远程数据段定义:.FARDATA [段名] / .FARDATA? [段名]
例子:
.MODEL TINY ;存储模式
.STACK 128 ;128字节堆栈段
.DATA
MSG DB "My first asm, ha ha.$" ;数据段定义
.CODE
.STARTUP ;在代码段的开始,用于自动初始化寄存器DS、SS和SP
MOV DX,OFFSET MSG
MOV AH,9H
INT 21H ;调用DOS中断的9H功能号,打印变量中的字符
.EXIT ;用于结束程序的运行,它等价于下列二条语句:MOV AH, 4CH/INT 21h
END
说明:
.STARTUP和.EXIT是MASM的伪指令。
3、程序的基本结构
汇编语言的源程序有三大结构:顺序结构、分支结构和循环结构。
2.1、顺序结构
2.2、分支结构
2.3、循环结构