汇编语言源程序语句的格式2007-04-20 09:48汇编语言源程序中的每个语句可以由四项组成,格式如下:
[名字] 操作 操作数 [ ;注释]
其中:
名字项是指一个标号或变量。
操作项是一个操作码的助记符,它可以是指令、伪指令或宏指令名。
操作数项由一个或多个表达式组成,它提供为执行所要求的操作而需要的信息。操作数项可以是常数、寄存器、标号、变量或由表达式组成。
注释项用来说明程序或语句的功能。";"为识别注释项的开始。";"也可以从一行的第一个字符开始,此时整行都是注释,常用来说明下面一段程序的功能。
上面四项中带方括号的两项是可选项。各项之间必须用"空格"(space)或"水平制表"(Tab)符隔开。
(1) 名字项
(2) 操作项
(3) 操作数项
(4) 注释项
(1) 名字项
源程序中用下列字符来表示名字:
字母A~Z
数字0~9
专用字符 ?、·、@ 、-、$
除数字外,所有字符都可以放在源语句的第一个位置。名字中如果用到·则必须是第一个字符。可以用很多字符来说明名字,但只有前面的31个字符能被汇编程序所识别。
一般说来,名字项可以是标号或变量。它们都用来表示本语句的符号地址,都是可有可无的,只有当需要用符号地址来访问该语句时它才需要出现。
· 标号:标号在代码段中定义,后面跟着冒号:,它也可以用LABEL或EQU伪操作来定义。此外,它还可以作为过程名定义,这将在以后的章节中加以说明。
· 变量:变量在数据段或附加数据段中定义,后面不跟冒号。它也可以用LABEL或EQU伪操作来定义。变量经常在操作数字段出现。
(2)操作项
操作项可以是指令、伪指令或宏指令的助记符。对于指令,汇编程序将其翻译为机器语言指令。对于伪指令,汇编程序将根据其所要求的功能进行处理。对于宏指令,则将根据其定义展开。宏指令在第七章中将会专门论述。
(3) 操作数项
操作数项由一个或多个表达式组成,多个操作数项之间一般用逗号分开。对于指令,操作数项一般给出操作数地址,它们可能有一个,或二个,或三个,或一个也没有。对于伪操作或宏指令,则给出它们所要求的参数。
操作数项可以是常数、寄存器、标号、变量或由表达式组成。
(4) 注释项
注释项用来说明一段程序、一条或几条指令的功能。对于汇编语言程序来说,注释项的作用是很明显的,它可以使程序容易被读懂,因此汇编语言程序必须写好注释。注释应该写出本条(或本段)指令在程序中的功能和作用,而不应该只写指令的动作。读者在有机会阅读程序例子时,应注意学习注释的写法,在编制程序时,更应学会写好注释。
4.3.2 表达式
表达式是常数、寄存器、标号、变量与一些操作符相组合的序列,可以有数字表达式和地址表达式两种。在汇编期间,汇编程序按照一定的优先规则对表达式进行计算后可得到一个数值或一个地址。
常用的表达式操作符介绍如下:
(1) 算术操作符
算术操作符有+、-、*、/ 和MOD。
MOD是指除法运算后得到的余数,如19/7的商是2,而19 MOD 7则为5(余数)。
(2) 逻辑操作符
逻辑操作符有:AND(与)、OR(或)、XOR(异或)、NOT(非)。
逻辑操作符都是按位操作的,只能用于数字表达式中。逻辑操作符要求汇编程序对其前后两个操作数(或表达式)作指定的逻辑操作。
(3) 关系操作符
关系操作符有:EQ(相等)、NE(不等)、LT(小于)、GT(大于)、LE(小于或等于)、GE(大于或等于)。
关系操作符的两个操作数必须都是数字或是同一段内的两个存储器地址。计算的结果应为逻辑值:结果为真,表示为0FFFFH;结果为假,则表示为0。
(4) 数值回送操作符
数值回送操作符有:TYPE、LENGTH、SIZE、OFFSET、SEG等。
数值操作符把一些特征或存储器地址的一部分作为数值回送。
· TYPE
格式为:TYPE 表达式
如果表达式是变量,则汇编程序将回送该变量的以字节数表示的类型:DB为1,DW为2,DD为4,DF为6,DQ为8,DT为10。如果表达式是标号,则汇编程序将回送代表该标号类型的数值:NEAR为 -1,FAR为 -2。如果表达式为常数,则应回送0。
· LENGTH
格式为:LENGTH 变量
对于变量中使用DUP的情况,汇编程序将回送分配给该变量的单元数,而对于其他情况则送1。
· SIZE
格式为:SIZE 变量
汇编程序应回送分配给该变量的字节数。但是,此值是LENGTH值和TYPE值的乘积。
· OFFSET
格式为:OFFSET 变量或标号
汇编程序将回送变量或标号的偏移地址值。
· SEG
格式为:SEG 变量或标号
汇编程序将回送变量或标号的段地址值。
(5) 属性操作符
属性操作符主要有:PTR、段操作符、SHORT、THIS、HIGH、LOW等。
· PTR
格式为:类型 PTR 符号地址
PTR用来给已分配的存储地址(用符号地址表示)赋予另一种属性,使该地址具有另一种类型。
类型可有BYTE、WORD、DWORD、FWORD、QWORD、TBYTE、NEAR和FAR等几种,所以PTR也可以用来建立字、双字、四字或段内及段间的指令单元等。
· 段操作符
段操作符用来表示一个标量、变量或地址表达式的段属性。
格式为:
段寄存器∶地址表达式
段名∶地址表达式
组名∶地址表达式
· SHORT
用来修饰JMP指令中转向地址的属性,指出转向地址是在下一条指令地址的±127个字节范围之内。
· THIS
格式为: THIS 属性或类型
THIS可以象PTR一样建立一个指定类型(BYTE、WORD、DWORD)或指定距离(NEAR或FAR)的地址操作数。该操作数的段地址和偏移地址与下一个存储单元地址相同。
· HIGH和LOW
称为字节分离操作符,它接收一个数或地址表达式,HIGH取其高位字节,LOW取其低位字节。
· 操作符的优先级
我们知道表达式是常数、寄存器、标号、变量和操作符的组合,在计算表达式时,应该首先计算优先级高的操作符,然后从左到右地对优先级相同的操作符进行计算。括号也可以改变计算次序,括号内的表达式应优先计算。
(1) 算术操作符
算术操作符可以用于数字表达式或地址表达式中,但当它用于地址表达式时,只有当其结果有明确的物理意义时才是有效的结果。例如两个地址相乘或相除是无意义的。在地址表达式中,可以使用 + 或 - ,但也必须注意其物理意义。
例如把两个不同段的地址相加也是无意义的。经常使用的是地址 ± 数字量,它是有意义的。例如SUM +1是指SUM字节单元的下一个字节单元的地址(注意:不是指SUM单元的内容加1),而SUM-1则是指SUM字节单元的前一个字节单元的地址。
例: 如果要求把首地址为BLOCK的字数组的第6个字传送到DX寄存器,可用指令如下:
MOV DX, BLOCK+ (6-1) * 2
例: 如数组ARRAY定义如下,写出把数组长度(字数)存入CX寄存器的指令。
ARRAY DW 1, 2, 3, 4, 5, 6, 7
ARYEND DW ?
其中ARYEND是为计算数组长度而建立的符号地址,所需指令如下:
MOV CX, (ARYEND-ARRAY)/2
汇编程序在汇编期间将计算出表达式的值而形成指令:
MOV CX, 7
(2) 逻辑操作符
例:
OUT PORT_VAL AND 0FEH, AL
上例中PORT_VAL为端口号,OUT指令中的表达式说明只为偶数号端口输出数据。
例:
AND DX, PORT_VAL AND 0FEH
上例在汇编时由汇编程序对指令中的表达式进行计算得到一个端口号,而在程序运行时,该指令的执行是把DX寄存器的内容与汇编程序计算得到的端口号进行"与"操作,结果保存在DX寄存器中。
注意:表达式中的AND是运算符,汇编时由汇编程序计算出一个值;而AND指令是在运行时由CPU执行。
(3) 关系操作符
例如:
MOV BX,((PORT_VAL LT 5) AND 20) OR ((PORT_VAL GE 5) AND 30)
则当PORT_VAL < 5时,汇编结果应该是:
MOV BX, 20
否则,汇编结果应该是:
MOV BX, 30
(4) 数值回送操作符
· TYPE
举例:
ARRAY DW 1, 2, 3
则对于指令ADD SI, TYPE ARRAY
汇编程序将其形成为:
ADD SI, 2
· LENGTH
举例1:
FEES DW 100 DUP (0)
对于指令MOV CX, LENGTH FEES
汇编程序将使其形成为:
MOV CX, 100
举例2:
ARRAY DW 1, 2, 3
对于指令MOV CX, LENGTH ARRAY
汇编程序将使其形成为:
MOV CX, 1
举例3:
TABLE DB 'ABCD'
对于指令MOV CX, LENGTH TABLE
汇编程序将使其形成为:
MOV CX, 1
· SIZE
例如:
MOV CX, SIZE FEES
将形成为 MOV CX, 200
又例如:
MOV CX, SIZE ARRAY
将形成为 MOV CX, 2
又例如:
MOV CX, SIZE TABLE
将形成为 MOV CX, 1。
· OFFSET
举例:
MOV BX, OFFSET OPER_ONE
汇编程序将OPER_ONE的偏移地址作为立即数回送给指令,而在执行时则将该偏移地址装入BX寄存器中。所以这条指令的功能与指令
LEA BX, OPER_ONE
是等价的。
· SEG
举例:如果DATA_SEG是从存储器的05000H地址开始的一个数据段的段名,OPER1是该段中的一个变量名,则
MOV BX, SEG OPER1
将把0500H作为立即数插入指令。实际上,由于段地址是由连接程序分配的,所以该立即数是连接时插入的。执行期间则使BX寄存器的内容成为0500H。
(5) 属性操作符
· PTR
举例:已有数据定义如下:
TWO_BYTE DW ?
可以用以下语句对这两个字节赋予另一种类型定义:
ONE_BYTE EQU BYTE PTR TWO_BYTE
OTHER_BYTE EQU BYTE PTR ( TWO_BYTE + 1)
后者也可以写成:
OTHER_BYTE EQU ONE_BYTE + 1
这里ONE_BYTE和TWO_BYTE两个符号地址具有相同的段地址和偏移地址,但是它们的类型属性不同,前者为1,后者为2。
此外,有时指令要求使用PTR操作符。例如用
MOV [BX], 5
指令把立即数存入BX寄存器内容指定的存储单元中,但汇编程序不能分清是存入字单元还是字节单元,此时必须用PTR操作符来说明属性,应该写明:
MOV BYTE PTR [BX],5
或 MOV WORD PTR [BX],5
· 段操作符
例如,用段前缀指定某段的地址操作数
MOV AX,ES:[BX + SI]
· SHORT
例如: JMP SHORT TAG ;转移属性为短转移
.
.
.
TAG: MOV...
· THIS
例如: FIRST_TYPE EQU THIS BYTE
WORD_TABLE DW 100 DUP (?)
此时FIRST_TYPE的偏移地址和WORD_TABLE完全相同,但它是字节类型的;而WORD_TABLE则是字类型的。
又如: START EQU THIS FAR
MOV CX, 100
这样,MOV指令有一个FAR属性的符号地址START,这就允许其他段的JMP指令直接跳转到START来。
· HIGH和LOW
例如:
CONST EQU 0ABCDH
则 MOV AH, HIGH CONST
将汇编成 MOV AH, 0ABH
指令 MOV AH, LOW CONST
将汇编成 MOV AH, 0CDH
· 操作符的优先级
操作符的优先级别从高到低排列如下:
1. 在圆括号中的项,方括号中的项,结构变量(变量,字段。),然后是LENGTH、SIZE、WIDTH和MASK。
2. 名:(段取代)。
3. PTR,OFFSET,SEG,TYPE,THIS及段操作符。
4. HIGH和LOW。
5. 乘法和除法:*,/,MOD。
6. 加法和减法:+,-。
7. 关系操作:EQ,NE,LT,LE,GT,GE。
8. 逻辑:NOT。
9. 逻辑:AND。
10. 逻辑:OR,XOR。
11. SHORT。
汇编语言程序中表达式的值实际上是由汇编程序计算的,而程序员应该正确掌握书写表达式的方法,以减少出错的可能性。
4.3.3 汇编语言源程序格式举例
例1.完整段定义格式
; TITLE 文件名- 程序主要功能描述
;EQU 语句
这里要说明几点:
第一、其中关于建立过程的PROC和ENDP伪操作对将在以后的章节中说明。这里只要知道利用这一对伪指令把程序段分为若干个过程,使程序的结构加清晰就可以了。
第二、本例只定义了最基本的代码段和数据段,如果程序中还需定义附加段和堆栈段,则定义的方式及建立段寄存器的方法是相同的,学员可自行设计。
第三、本例把主程序建立为过程,由DOS调用该过程。进入程序后,首先把DS的内容和0作为段地址和偏移地址入栈,以便在程序结束时用RET指令返回DOS,这是一种工作方式。如果在主程序开始时没有用上面三条指令在堆栈中建立返回信息,则在程序结束时就不能直接用RET返回指令,而应该使用编号为4C的功能调用返回DOS,如下所示:
MOV AX,4C00H
INT 21H
这种方式用得更加普遍。
例1所给出的汇编语言源程序格式适用于MASM的各种版本,对于MASM5.0、6.0版可采用例2所示的汇编语言源程序格式。
例2.简化段定义格式
例1.完整段定义格式
; TITLE 文件名- 程序主要功能描述
;EQU 语句
;* * * * * * * * * * * * * * * * * * * * * * * * * *
datarea segment ;定义数据段
;数据定义语句
datarea ends
;* * * * * * * * * * * * * * * * * * * * * * * * * *
prognam segment ;定义代码段
;---------------------------------------------------
main proc far ;主程序
assume cs:prognam,ds :datarea
start: ;程序起始执行地址
;为程序返回DOS设置堆栈值
push ds ;入栈保存原DS段址
sub ax,ax ;设置偏移地址为0
push ax ;入栈保存偏移地址
;置DS寄存器为当前数据段
mov ax,datarea ;datarea段地址
mov ds,ax ; 存入DS寄存器
;主程序部分
ret ;返回 DOS
main endp ;主程序结束
;----------------------------------------------------
sub1 proc near ;定义子程序
;子程序部分
sub1 endp ;子程序结束
;------------------------------------------------------------------------------
prognam ends ;代码段结束
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
end start ;汇编结束
例2.简化段定义格式
.model small ;定义存储器模型
.stack 100h ;定义堆栈段
.data ;定义数据段
; ;数据定义语句
.code ;定义代码段
main proc far
start:
mov ax,@data ;数据段地址
mov ds,ax ; 存入DS寄存器
;主程序部分
mov ax,4c00h
int 21h ;返回DOS
main endp ;主程序结束
end start ;汇编结束