3.1 汇编语言程序的开发
3.1.1 汇编语言程序的语句格式
(1)标号与名字
执行性语句中,:
前的标号表示处理器指令在主存中的逻辑地址,主要用于指示分支、循环等程序的目的地址,可有可无。说明性语句中的名字可以是变量名、段名、子程序名等,反映变量、段和子程序等的逻辑地址。标号采用:
分隔处理器指令,名字采用空格或制表符分隔伪指令,据此也分开了两种语句。
(2)助记符
助记符是帮助记忆指令的符号,反映指令的功能。处理器指令助记符可以是任何一条指令,表示一种处理器操作。例如,程序中使用最多的数据传送指令,其助记符是MOV
。
(3)操作数和参数
处理器指令的操作数表示参与操作的对象,可以是一个具体的常量,也可以是保存在寄存器的数据,还可以是一个保存在存储器中的变量。在双操作数的指令中,目的操作数写在,
前,还用来存放指令操作的结果;对应地,,
后的操作数就称为源操作数。
(4)注释
语句中;
后的内容是注释,通常是对指令或程序片段功能的说明,是为了程序便于阅读而加上的,不是必须有的。必要时,一个语句行也可以由;
开始作为阶段性注释。
3.1.2 汇编语言的源程序框架
(1)简化段定义的源程序框架
MASM各版本支持多种汇编语言源程序格式。MASM 6.x版本的简化段定义典型格式如下:
.model small //定义程序的存储模式(small表示小型模式)
.stack //定义堆栈段(默认是1KB空间)
.data //定义数据段
... //数据定义
.code //定义代码段
.startup //程序起始点,并设置DS和SS内容
... //主程序代码
.exit 0 //程序终止点,返回DOS(0是返回值)
... //子程序代码
end //汇编结束
在简化段定义的源程序格式中,以.
开始的伪指令说明程序的结构。首先,必须具有存储模型伪指令.MODEL
,随后,.STACK、.DATA和.CODE
依次定义堆栈段、数据段和代码段,一个段的开始自动结束上一个段。
例如:显示“Hello Everybody!”,采用简化段定义的源程序框架如下:
.MODEL SMALL
.STACK
.DATA
string DB 'Hello, Everybody!', 0DH, 0AH, '$'
.CODE
.STARTUP
MOV DX, OFFSET string
MOV AH, 9
INT 21H
.EXIT 0
END
(2)完整段定义的源程序框架
上文中的程序完整段定义的源程序如下:
STACK SEGMENT
DB 1024 DUP(?)
STACK ENDS
DATA SEGMENT
string DB 'Hello, Everybody!', 0DH, 0AH, '$'
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA, SS: STACK
START:
MOV AX, DATA
MOV DS, AX
MOV DX, OFFSET string
MOV AH, 9
INT 21H
MOV AX, 4C00H
INT 21H
CODE ENDS
END START
3.1.3 汇编语言程序的开发过程
略
3.1.4 DOS系统功能的调用
调用DOS操作系统功能的一般方法如下:
(1)在AH寄存器中设置系统功能调用号,说明选择的功能;
(2)在指定寄存器中设置入口参数,以便按照要求执行功能;
(3)用中断调用指令INT 21H
执行功能调用;
(4)根据出口参数分析功能调用执行情况。
下表列出了主要使用的基本DOS功能调用:
子功能号 | 功能 | 入口参数 | 出口参数 |
AH=01H | 从标准输入设备输入一个字符 | 无 | AL=输入字符的ASCII码 |
AH=02H | 向标准输出设备输出一个字符 | DL=字符的ASCII码 | 无 |
AH=09H | 向标准输出设备输出一个字符串 | DS:DX=字符串地址 | 无 |
AH=0AH | 从标准输入设备输入一个字符串 | DS:DX=缓冲区地址 | 无 |
AH=0BH | 判断键盘是否有键按下 | 无 | AL=0表示无,AL=FFH表示有 |
AH=4CH | 程序执行终止 | AL=返回代码 | 无 |
(1)字符输出
使用02H号DOS系统功能调用在显示器输出一个字符:
MOV AH, 02H //设置功能号:AH ← 02H
MOV DL, '?' //提供入口参数:DL ← '?'
INT 21H //DOS功能调用:显示
(2)字符串输出
使用09H号DOS功能要事先将欲显示的字符串保存在主存,设置入口参数DS:DX等于该字符串在主存中的首地址,注意字符串必须以’$’(24H)结束,可以输出回车(0DH)和换行(0AH)字符产生回车和换行的作用。
string DB 'Hello, Everybody!', 0DH, 0AH, '$' //在数据段定义要显示的字符串
MOV AH, 09H //设置功能号:AH ← 09H
MOV DX, OFFSET string //提供入口参数:DX ← 字符串的偏移地址
INT 21H //DOS功能调用:显示
(3)字符输入
调用01H号DOS功能时,若无键按下,则会一直等待,直到按键后才读取该键值,并使用AL保存出口参数,即输入字符的ASCII编码。例如:判断按键是Y还是N(大写)。
getkey:
MOV AH, 1 //设置功能号:AH ← 01H
INT 21H //DOS功能调用:等待按键
CMP AL, 'Y' //分析出口参数是否为Y
JE yeskey
CMP AL, 'N' //分析出口参数是否为N
JE nokey
JNE getkey //不是Y或N,继续输入
(4)字符串输入
用0AH号DOS系统功能调用从键盘输入一个字符串:
buffer //定义缓冲区
DB 81 //第1字节填入可能输入的最大字符数
DB 0 //第2字节将用于存放实际输入的字符数
DB 81 DUP(0) //第3字节开始用于存放输入的字符串
...
MOV AH, 0AH
MOV DX, SEG buffer
MOV DS, DX
MOV DX, OFFSET buffer
INT 21H
(5)按键判断
例如:按任意键继续的程序片段:
... //提示“按任意键继续”
getkey:
MOV AH, 0BH //设置功能号:AH ← 0BH
INT 21H //DOS功能调用:判断按键否
OR AL, AL //分析出口参数:AL = 0 ?
JZ getkey //AL = 0,没有按键,继续等待
3.2 参数、变量和标号
3.2.1 数值型参数
略
3.2.2 变量定义伪指令
变量定义伪指令为变量申请固定长度的存储空间,并可以同时将相应的存储单元初始化,其汇编格式为变量名 伪指令 初值表
。
(1)变量名为用户自定义标识符,表示初值表首元素的逻辑地址,即用这个符号表示地址,常称为符号地址。变量名可以没有,在这种情况下,汇编程序将直接为初值表分配空间,无符号地址。
(2)初值表是用,
分隔的参数,主要由数值常数、表达式或?、DUP
组成。其中?
表示初值不确定,即未赋初值;重复初值可以用DUP
进行定义。DUP
的格式为:重复次数 DUP(重复参数)
(3)变量定义伪指令有DB、DW、DD、DF、DQ、DT,它们根据申请的主存空间单位分类,下面逐一介绍。
(1)定义字节单元伪指令
字节定义伪指令DB,用于分配1字节或多字节单元,并可以将它们初始化为指定值。
.DATA
X DB 'a', -5
DB 2DUP(100), ?
Y DB 'ABC'
利用这些变量的汇编指令示例如下:
MOV AL, X //此处X表示它的第一个数据,故AL ← 'a'
DEC X + 1 //对X为起始的第二个数据减一,故成为-6
MOV Y, AL //现在Y这个字符串成为'aBC'
(2)定义字单元伪指令
一个字单元可用于存放任何16位数据。
.DATA
COUNT DW 8000H, ?, 'ab'
MAXINT EQU 64H
NUMBER DW MAXINT
ARRAY DW MAXINT DUP(0)
(3)定义双字单元伪指令
一个双字单元可用于存放任何32位数据。
VARDD DD 0, ?, 12345678H
FARPOINT DD 00400078H
(4)其他数据定义伪指令
DF:定义3字伪指令;
DQ:定义4字伪指令;
DT:定义10字节伪指令。
例:定义一个缓冲区,包含33H、34H、35H和36H四个字节字符,把这四个数据依次复制20次,存入接着的存储区,最后显示出复制结果。
//数据段
source DB 33H, 34H, 35H, 36H
target DB 80 DUP(?)
//代码段
MOV SI, OFFSET SOURCE
MOV DI, OFFSET TARGET
MOV CX, 80
again: