地址表达式
地址表达式 是由变量、标号、常量、寄存器(BX、BP、SI、DI)的内容和一些运算符组成的。单个的变量、标号、寄存器的内容是地址表达式的特例。
加、减运算符 变量或标号可以加上或减去一个常量,其结果仍为变量或标号,且它的段地址和类型均不变,只修改其偏移地址。
方括号及寄存器 BX、BP、SI、DI四个寄存器的内容既可做操作数使用,又可作地址使用,但做地址使用时必须使用运算符“[]”(方括号)方括号中可以出现上述四个积存器中的一个或两个,但BX和BP,SI和DI不能同时出现。
段超越前缀 段超越前缀(:)用于临时给变量、标号或地址表达式指定一个段属性,他并不改变地址表达式的偏移地址和类型属性。他有三种格式:
<段寄存器>:地址表达式
<段 名>:地址表达式
<组 名>:地址表达式
分析运算符和合成运算符 分析运算符可分离出变量、标号的段、偏移地址及类型的属性值。合成运算符(PTR)用来指明某个变量、标号或地址表达式的类型属性,或者使它临时兼有与原定义所不同的类型属性,但保持他们原来的段属性和偏移属性不变。其使用的格式为:类型 PTR 地址表达式
根据地址表达式的不同值,类型可以是BYTE、WORD、DWORD、NEAR、FAR等。各类型的值请看相关章节
举例:在语句“MOV BYTE PTR[SI 4],‘ ’”中,PTR指定地址表达式[SI 4]的类型为字节。
无论是数值表达式还是地址表达式,他们使用的运算符都有一定先后顺序,请看下表:
表3.4:汇编语言中运算符的优先级
3.3 常用伪指令语句
汇编语言程序的语句出指令以外还可以有伪指令和宏指令组成,关于宏指令我们将在第3.5节加以说明。这一节我们只讨论伪指令。伪指令不象机器指令那样实在程序运行期间由计算机来执行的,他是汇编程序对源程序汇编期间由汇编程序处理的操作,他们可以完成如数据定义、分配存储区、只是程序结束等功能。MASM共有五十多条伪指令,可分为九大类。本节主要介绍符号定义,数据定义,属性修改,段定义等伪指令语句。
3.3.1 符号定义(Symbol_definetion)伪指令
符号定义(Symbol_definetion)伪指令 汇编语言中所有变量名,标号名,记录名,指令助记符,寄存器等均称为符号。这些符号可通过伪操作重新命名,或定义其它名字和新的类型,这给程序设计带来了很大的灵活性。这类伪指令主要有等值伪指令EQU,等号伪指令=,LABEL伪指令。
符号定义伪指令——等值伪指令EQU、等号伪指令 =和LABEL伪指令
1、 等值伪指令EQU
语句格式:符号名 EQU 表达式
功能及说明:用来为常量、表达式及其他各种符号定义一个等价的符号名,但它并不申请分配存贮单元(在该语句中,符号名一定不可省)。
①常数或数值表达式
例如: COUNT EQU 5
NUM EQU 13 5-4
②地址表达式
例如: ADR1 EQU DS:[BP 14]
③变量、标号或指令助记符
例如: CREG EQU CX
CBD EQU DAA
L1 EQU SUBSTART
WO EQU WORD PTR DA BYTE
等值语句仅在汇编源程序时。作为替代符号用,不产生任何目标代码,也不占有存储单元。因此,等值语句左边的符号没有段,偏移量和类型三个属性。
在同一源程序中,同一符号不能用EQU伪指令重新定义。
2、 等号伪指令 =
语句格式:变量名或标号 = 类型
功能及说明:等号伪指令的功能与EQU基本相同,只是使用等号“=”定义过的符号可以被重新定义,使其具有新的值。
例如: CONST=35 ;定义CONST为常数
CONST=57 ;CONST被重新定义
3、 LABEL伪指令
语句格式:变量名或标号 LABEL 类型
功能及说明:它用来定义或修改变量或标号类型。当定义变量名时类型可以是BYTE、WORD、DWORD、结构名和记录名;而定义标号时,则类型为NEAR或FAR。
例如: DATA1 LABEL BYTE
DB 45
定义变量为定字节变量,以上语句等价于
DATA1 DB 45
3.3.2 数据定义(Data_definetion)伪指令
数据定义(Data_definetion)伪指令 用来定义一数据存储区,并可为其赋予初值,其类型由所使用的数据定义伪指令:DB,DW,DD,DQ,DT来确定。其中变量名是任选的,若有变量名,则将表达式指定类型的数据存入与该变量名相应的地址开始的连续存储单元中;否则将这些数据顺序存放。
数据定义伪指令用来为源程序中被处理的数据安排内存,赋予初值及定义名字的。本小节主要介绍DB、DW、DD,DQ,DT伪指令和分析运算符1(SEG,OFFSET,TYPE)、分析运算符2(LENGTH,SIZE)。
1. DB伪指令
语句格式:变量名 DB 表达式
功能及说明:其右边的表达式可以是以下的几种形式:1.数值表达式或数值表达式串;2.字节常量和字节常量串;3.疑问号:?(表示此变量的初值不确定);4.ASCII码字符串,即可以定义用单引号括起来的字符串(只有用DB定义变量时,才允许字符串长度超过2个字符);5.重复子句,其格式为:(<重复因子> DUP 表达式),重复因子n为正整数,表示定义了n个相应类型的数据单元;6.以上五种形式的组合。
2、DW伪指令
语句格式:变量名 DW 表达式
功能及说明:它与DB不同的是它为程序定义的是一个字数据区,它对数据区中数据的存取是以字(即两个字节)为单位的。
3、DD,DQ,DT伪指令
语句格式:变量名 DD(DQ,DT) 表达式
功能及说明:与DB类似。DD定义双字数据区,DQ定义8个字节数据区,DT定义10个字节数据区。DD和DW只能定义至多两个字符的字符串。
4、 分析运算符1(SEG,OFFSET,TYPE)
语句格式:分析运算符(SEG,OFFSET,TYPE) 变量或标号
功能及说明:
① SEG 取出其后变量或标号所在段的段首址。
当运算符SEG加在一个变量名或标号的前面时,得到的运算结果是这个变量名或标号所在段的段基值。例如:
MOV AX,SEG K1
MOV BX,SEG, ARRAY
如变量K1所在段的段基值为0915H,变量ARRAY的段基值为0947H,那么上面两条指令就分别等效于:
MOV AX,0915H
MOV BX,0947H
由于任一个段的段基值是十六位二进制数,所以SEG运算符返回的数值也是十六位二进制数。
② OFFSET取出其后变量或标号的偏移首址。
当运算符OFFSET加在一个变量名或标号前面时,得到的运算结果是这个变量或标号在它段内的偏移量。
例如:
MOV SI,OFFSET KZ
设KZ在它段内的偏移量是I5H,那么这个指令就等效于:
MOV SI,15H
③ TYPE取出其后变量或标号的类型。 变量类型用字节个数表示,标号类型用NEAR和FAR对应值(见表3.3)。其中变量的类型数字正好分别是它们所占有的存储单元字节数.而标号的类型数字没有什么物理意义。
例如:
V1 DB ‘ABCDE’
V2 DW 1234H,5678H
V3 DD V2
MOV AL,TYPE V1
MOV CL,TYPE V2
MOV CH,TYPE V3
上述三条指令与下面指令完全等价:
MOV AL,01H
MOV CL,02H
MOV CH,04H
表3.4:存储器操作数类型值
存储器操作数 |
类型值 |
字节变量 |
1 |
字变量 |
2 |
双字变量 |
4 |
NEAR标号 |
-1 |
FAR标号 |
-2 |
5、 分析运算符2(LENGTH,SIZE)
语句格式:分析运算符(LENGTH,SIZE) 变量
功能及说明:
①LENGTH 取出其后变量元素的个数(注意LENGTH只对用重复运算符定义过的变量有效)。
这个运算符仅加在变量的前面,返回的值是指数组变量的元素个数。如果变量是用重复数据操作符DUP说明的,则返回外层DUP给定的值:如果没有DUP说明,则返回的值总是1。例如:
K1 DB 1OH DUP(0)
K2 DB 10H,20H,30H,40H
K3 DW 20H DUP(0,1,2 DUP(2))
K4 DB ‘ADCDEFGH’
┆
MOV AL,LENGTH K1 ;(AL):10H
MOV BL,LENGTH K2 ;(EL):1
MOV CX,LENGTH K3 ;(CX):20H
MOV DX,LENGTH K4 ;(Dx)=1
②SIZE 取出其后变量所占存贮空间的总字节数。
这个运算符仅加在变量的前面,返回数组变量所占的总字节数,且等于LENGTH和TYPE两个运算符返回值的乘积。例如对于前面例子中K1,K2,K3,K4变量,下面指令就表示出SIZE运算符的返回值:
MOV AL,SIZE K1 ;(AL)=10H
MOV BL,SIZE K2 ;(BL)=1
MOV CL,SIZE K3 ;(CL)=40H
MOV DL,SIZE K4 ;(DL)=1
三个运算符TYPE,LENGTH,SIZE对处理数组类型变量是很有用的。