三章 汇编语言程序设计

psp 三章 汇编语言程序设计
本章重点:
了解汇编语言特点汇编 程序功能,汇编语言结构.
掌握汇编语言中的表达试伪指令,宏定义的含义和用法.
掌握DOS功能调用基本I/O,返回DOS的方法,了解文 件管理.
难点:
理解顺序程序,分支程序,循环程序,含子程序的程序设计的基本方法.
编写,运行,调试汇编语言程序.
内 容:第1节 程序设计语言概述
第2节8086汇编语言的基本语法
第3节 汇编语言中的表达式
第4节 伪指令语句
第5节 DOS功能调用简介
第6节 汇编语言程序设计举例
第7节 宏指令语句
§1 程序设计语言概述
汇编语言的特 点
使用助记符表示指令.
能用标识符代替地址,常量和变量.
借助伪指令和汇编程序,程序员不必具体安排程序和数据在存储器中的存 放.
汇编语言源程序
用汇编语言编写的程序
汇编程序
它的作用是把汇编语言源程序自动翻译成机器语言目标程序.
行汇 编:对源程序逐条汇编,特点是小型方便.
宏汇编:对源程序按模块汇编,特点是功能强,开发和调试手段较完善.§2 8086汇编语言的基本语法
标 识符
用来对程序中的变量,常量,段,过程等进行命名,命名规则如下:
标识符是一个字符串,第一个字符必须是字母," ","@"或下划线"_".
后续字符可以是字母,数字," ","@","_".
长度:可由1~31个字符组成.
不能使用系统己 经定义过的符号,如寄存器名,分支条件用标志,助记符,定义等等.
语句类型与结构
类型:
指令性语句:是机器指令的符号表示,经汇 编后能产生对应的机器指令代码,在形成执行文件时执行.
指示性语句(伪指令语句):给汇编程序提拱一些控制信息,帮助汇编程序正确汇编指令性语 句,在汇编时被执行,没有对应的机器码.如:定义数据,分配存储单元,定义一个符号以及控制汇编结束等等.
宏指令语句:是上述二种语句的复合体, 是按照一定规则,根据用户需要定义的新指令;在汇编时被展开,在形成执行文件时执行其展开体.
结构:
指令性语句结构
格式:
[标 号:][前缀]指令助记符[操作数][;注释]
说明:
[]内为可选用或缺省成份.
标号是由标识符紧跟":"组成,代表该行指令在 存储器中的首地址,它可作为转移指令和调用指令的一个操作数.
前缀,如重复前缀REP,总线封锁前缀LOCK等.
操作数可以是一个,两个 或没有.
注释是以";"开始的字符串,不影响程序的汇编与执行,仅用于增加源程序的可读性.
伪指令语句结构
格式:
[名 字]伪指令助记符[操作数][;注释]
说明:
名字可以是符号常量名,变量名,过程名,段名等,其后不能有":".
伪指令共有40 多个,分八类.
宏指令语句结构
格式:
[宏名]宏操作助记符[操作数][;注释]
说明:
宏名即宏指令名,是一标识 符,其后不能有":".
宏操作助记符共有8个,分别是MACRO,ENDM,EXITM,LOCAL,REPT,IRPC,IRP,PURGE.
汇 编语言源程序结构
汇编语言源程序是以模块为单位独立汇编的.一个完整的源程序至少由一个模块组成,各个模块分别汇编成目标代码后,要用连接程序将 其连接成一个可执行程序.
一个模块可分成若干段.§3 汇编语言中的表达式
表达式的组成:
运算对象:常量,变量,标号.
运 算符:算术运算符,逻辑运算符,关系运算符.
表达式的分类:
数值表达式:只产生一个数值结果.
地址表达试:产生一个存储器地址. 若该地址中存放的是数据,则该地址为变量;若存放的是指令,则该地址为标号.
表达式的运算:
由汇编程序汇编时完成,运算所得结果再作为语 句操作数使用.
常量,变量和标号:
均能被汇编程序识别.
常量:
定义:是在汇编时己经确定常数值,可以是数据和字符.
类 型:数值常量,符号常量.
例:ONE EQU 1
DATA=2*12H
MOV AX,DATA+ONE ;AX←25H
变 量:
定义:常以变量名的形式出现在程序中,可看作是存放数据的存储单元的符号地址,用来定义存储器中的数据.
变量具有三种属性:
段 属性:变量所在段的段基址.
偏移地址属性:变量所在段的段内偏移地址.
类型属性:变量占用存储单元的字数.
BYTE:字节型,一 字节,伪指令定义名DB;
WORD:字型,两个字节,伪指令定义名DW;
DWORD:双字型,四个字节,伪指令定义名DD;
QWORD: 四字型,八个字节,伪指令定义名DQ;
TBYTE:五字型,十个字节,伪指令定义名DT.
例:
【例1】Y DW 4981H,1234H
说明:变量Y为字类型,该变量存储区有2个字数据,Y代表第一个字节的偏移地址,存放形式如图所示.
【例2】Z DD 10 DUP(0)
说明:变量Z为双字类型,存放有10个值为0的双字数据.
标号
定义:是给指令性语句所在单元地址取的名 字,它表明该指令在存储器中的位置,可作为转移类指令的操作数.
三种属性:
段属性:标号所在段的段基址.
偏移地址属性:标号所在 段的段内偏移地址.
类型属性:也称距离属性.
NEAR:近标号,表示该标号在段内使用.
FAR: 远标号,~~~~~~段间使用.
表达式中运算符的种类
算术运算符:7种
+,-,*,/,MOD(模除),SHL,SHR
注 意:"/"只取商,MOD只取余.
例:
MOV AX,15*4/7 ; AX=0008H
ADD AX,60MOD7; AX=8+4=12
MOV CX,-2*30-10; CX=-70
逻辑运算符:4种
AND,OR,XOR,NOT
逻辑 运算符:只出现在语句的操作数部分,运算在汇编时完成.
逻辑操作指令:只出现在指令的操作码部分,运算在执行指令时完成.
例:
MOV AL,NOT 10101010B;等效 MOV AL,01010101B
OR AL,10100000 OR 00000101B 等效OR AL,10100101B
关系运算符:6种
EQ(等于),NE(不等于),LT(小于),GT(大于),LE(小于等于),
GE(大 于等于)
关系运算符的两个操作数一定是常数或同一段内的偏移量地址,计算结果为逻辑值:结果为真,表示为0FFFFH;结果为假表示为0
例:
MOV AX,5 EQ 101B; 等效 MOV AX,0FFFFH
MOV BH,10H GT 16; 等效 MOV BH,00H
取值 运算符(数值返回运算符):
操作对象:必须是存储器操作数,即变量,标号,过程名.
格式:〈取值运算符〉〈变量或标号〉
返回的结 果是一个数值常量.
SEG运算符
取段地址运算符:该运算返回变量或标号所在段的段地址.
例:MOV BX,SEG BUF; BX←变量BUF的段地址
OFFSET运算符
取段内偏移地址符:该运算返回变量或标号所在段的段内编移地址.
例:MOV AX,OFFSET START;AX←标号START的偏移地址.
TYPE运算符
取类型属性运算符:该运算返回变量或标号的类型值.若 对象是标号,则返回标号的距离属性值(NEAR:-1;FAR:-2);若对象是变量则返回变量类型所占字节数.变量和标号的类型值对应关系如下:
类 型
类型值




BYTE
1
WORD
2
WORD
4
WORD
8
WORD
10
标号
NEAR
-1
FAR
-2
例:N1 DB 30H,31H,32H
N2 DW 4142H,4344H
N3 DD N2
ALD:MOV AL,TYPE N1; AL←1
ADD AH;TYPE N2; AH←AH+2
MOV BL,TYPE N3; BL←4
MOV BH,TYPE ALD;BH←-1(0FFH)
LENGTH运算符:
取数组变量元素个数;如果数组变量是用重复数据操作数DUP说明 的,则返回DUP前面的数值(重复次数);如果没有DUP说明,则返回值总是"1"
例:KA DB 10H DUP(0)
KB DB 10H,20H,30H
KC DB 'ABCDEFGH'
MOV AL,LENGTH KA ;AL←10H
MOV BL,LENGTH KB ;BL←1
MOV CX,LENGTH KC ;CX←1
SIZE运算符:
取数组变量总字节数,该 运算符返回值等于LENGTH和TYPE两个运算返回值的积.
HIGH/LOW运算符:
格式:HIGH 〈表达式〉
LOW 〈表达式〉
功能:用于分离运算对象的高字节和低字节部分.但不能分离某一个存储器或寄存器操作数内容的高字节和低字节.
【例1】 CONST EQU 0ABCDH
则:MOV AH,HIGH CONST 将汇编成:MOV AH,0ABH
【例2】MOV AL,LOW 0ABCDH 将汇编成:MOV AL,0CDH
属性设置运算符:
":"运算符
用来临时给变量,标号或地址表达 式指定一个段属性.
例:MOV AX,ES:[BX]
PTR运算符:
格式:〈类型〉PTR〈表达式〉
功能:临时赋予〈表 达式〉指定的〈类型〉,这些类型有BYTE,WORD,DWORD,NEAR和FAR等.新的类型只在所处的指令内有效.
例:DA_BYTE DB 20H DUP(0)
DA_WORD DW 30H DUP(0)
……
MOV AX,WORD PTR DA_BYTE
ADD BYTE PTR DA_WORD[20],BL
THIS运算符
常用的格式为: 变量或标号=THIS属性
该运算符和"="(或EQU)伪指令连用,把它后面指定的类型属性或距离属性赋给当前的变量或标号.
例:GAMA=THIS BYTE ;变量GAMA的类型属性定义为字节
ST=THIS FAR ;标号ST赋予远标号属性
§4 伪指令语句
一般格 式:
[名字]伪操作指令[操作数][;注]
符号定义伪指令
在汇编语言语言中,所有符号常量,变量名,标号,过程名,记录名,指令 助 记符 ,寄存器名等都称为符号,这些符号可以通过伪指令重新命名或定义新的类型属性.
EQU伪指令
格式:〈名字〉EQU 〈表达式〉
功能:将数值或字符序列与一个指定的名字等价.
说明:EQU定义过的名字不能重新定义.
为常量定义一个符号
例:ONE EQU 1
TWO EQU 2
SUM EQU ONE+TWO
给变量或标号定义新的类型属性并起一个新的名字.
例:FIRSTW EQU WORD PTR BYTES;
给变量BYTES重新定义类型并起名.
可以给地址表达式指出的任意存储单元定义一个名字.
例:XYZ EQU [BP+3]
A EQU ARRAY[BX][SI]
P EQU ES:ALPHA
▲注意:EQU语句的表达式中 如果有变量或标号的表达式,则在该语句前应该先给出它们的定义.
用来为汇编语言中的符号定义一个新名字.
例:COUNT EQU CX
LD EQU MOV
"="伪指令
功能:同EQU指令,但"="伪指令可重复定义.
例:……
EMP=7
……
EMP=EMP+1
……
LABEL伪指令
格式:〈变量或标号名〉 LABEL 〈类型〉
功能:为 当前存储单元定义一个指定类型的变量名或标号.
下面的例子是LABEL伪指令的常见用法:
【用法一】
DA_BYTE LABEL BYTE ;为当前存储单元定义一个字节变量名DA_BYTE
DA_WORD DW 4142H,5152H ;当前存储器单元另有一个字变量名DA_WORD
MOV AX,DA_WORD[0] ;AX←4142H
MOV BL,DA_BYTE[0] ;BL←42H
【用法二】
LOPF LABEL FAR ;为当前存储单元定义一个FAR属性的标号LOPF
LOPN:MOV AX,[BX+DI] ;当前存储单元另定义一个NEAR属性的标号LOPN
┇ ;段间转移使用标号LOPF,段内则使用LOPN
变量定义伪指令
基本 格式:
[变量名]〈DB/DW/DD/DQ/DT〉〈表达式〉
注意:无变量名时,定义常数类型.
表达式类型:
数值表达 式:
这种形式定义的变量具有表达式给定的数值初值(相当于给变量赋值).
【例】BETA DW 4*10H ; BETA为字类型,初值64
DA_BYTE DB 50H,50
DA_WORD DW 0A3F1H,4981H
ASCⅡ字符串 表达式
特点:字符串必须用单引号括起来.
【例】MSG DB 'STUDENT';
MSG1 DW 'AB','CD';(P3.19页图)
DB伪指令为串中每一个字符分配一个字节单元,且自左到右按地址递增的顺序依次存放,字符个数不得超过 255个.
地址表达式
表达式为变量名或标号时为地址表达式,其结果是一个地址,因此只能用DW或DD定义.
如果用DW定义,则 将原变量或标号的偏移地址存入指定新变量;如果用DD定义,则将原变量或标号的偏移地址和段地址分别存入指定新变量的低位和高位字中.
【例】 PARAMETER_TABLE DW PAR1
DW PAR2
INTERSEG_DATA DD DATA1
DD DATA2
表达式:
表示所定义的变量未指定初值.
例:DA_B DB , ;初值为随机数
DA_W DW , ;初值为随机数
带DUP表达式:
DUP格式:〈n〉DUP〈表达式〉
DUP功能:DUP是重复数据操作符,n为重复次数,〈表 达式〉为重复的内容.
例:TAB DB 100 DUP(0)
TAB1 DW 2 DUP(5 DUP(4),7);
数据序列 为:4,4,4,4,4,7,4,4,4,4,4,7共占24个字节.
程序的段结构
8086利用存储器分段技术管理存储器信息,而段定 义伪指令可使我们按段来组织程序和使用存储器.
段定义伪指令(SEGMENT和ENDS)
语句格式:
〈段名〉SEGMENT[定 位方式][组合方式][类别名]
┆ ;段内语句序列
〈段名〉ENDS
说明:
段名:
由用户自己选定,通常使用与 本段用途相关的名字,以便于记忆.如数据段名用DATA,堆栈段用STATCK,代码段用CODE等.
注意:一个段开始与结尾的段名应一致.
定 位方式(类型):
定位方式是通过汇编告知LINK程序如何将组合后的新段定位到存储器中.
PAGE(页):规定段从256的整数倍地址开 始(内存的一页为0到255个字节),称为页边界.这样段基址的最后8位二进制数一定为"0"(即以00H结尾的地址).
PARA(节):如果用 户未选择定位类型,则隐含为PARA.规定段从16的整数倍地址开始,称为段边界.故段基址的后4位一定为"0".
WORD(字):表示本段从一 个偶字节地址开始.即段基址最后一位是0.
BYTE(字节):表示本段可从任一地址开始.
组合方式:
指出如何链接不同模块中的同 名段,把不同模块中的同名段按照指定的方式组合起来.既便于程序运行,又可以达到有效使用存储空间的目的.组合方式有6种:
PUBLIC:表示该 段与其它模块中说明为PUBLIC的同名同类别的段链接起来共用一个段地址,形成一个物理段.
STACK:处理过程同PUBLIC类型,只是组合 后的这个段专用作堆栈段,系统自动对SS初始化为这个段的段首址,并初始化SP.用户程序至少有一个段用STACK说明,否则需要用户自己初始化SS和 SP.
COMMON:产生一个覆盖段.表明该段与其它模块中被说明成COMMON的同名同类段共用一个段起始地址,共享相同的存储区.共享存储区 的长度由同名中最大的段确定.
MEMORY:表明本段在连接时定位在所有段之上,即高址处.若有多个MEMORY,则只把第一个遇到的段当作 MENORY处理,而其它段按COMMON方式处理.
AT表达式:表示该段按绝对地址定位,段地址为表达式的值.
【例】 AT 1234H ; 即段基址为:12340H
NONE:隐含选择.表明本段与其它段无连接关系.装入内存时,本段有自己的物理段,因而有自己的段基 址.
类别名
说明指令对类别名相同的各模块中的所有段如何处理.LINK程序把各模块中分类名相同的所有段(段名不一定同)放在连续的存储 区域,但仍是不同的段.
注:类别名是合法的自定义符,必须用单引号括起来.段连接时按各段出现的先后顺序连.
使用段定义语句的两点说明
源 程序模块中的某一段,可使用一对SEGMENT和ENDS编写完毕,也可以分为多对SEGMENT和ENDS编写,只要使用相同的段名即可.但这些段的 SEGMENT语句的组合方式,定义方式,分类名应相同,不得相互矛盾,或者以先出现的SEGMENT语句为准,其余均省略不写.
LINK程序 链接时,先处理组合方式,后处理定位方式,再处理分类名.
如何链接参见下图
段寻址伪指令
格式:
ASSUME〈段寄存 器〉:段名[,〈段寄存器〉]……
功能:指示汇编程序己定义的段与段寄存器的对应关系.其中段寄器为CS,SS,DS,ES,段名是指用 SEGMENT与ENDS伪指令定义的段名.
【例】DATA1 SEGMENT
VAR1 DB 12H
DATA1 ENDS
DATA2 SEGMENT
VAR2 DB 32H
VAR3 DB 3BH
DATA2 ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA1,ES:DATA2
START:……
:
INC VAR1
INC VAR2
INC VAR3
:
CODE ENDS
END START
说明:
汇编程序在汇编每一条指令时,必须明确指令在运行期 间,内存寻址时应使用哪个段寄存器.即ASSUME伪指令放在CODE SEGMENT与CODE ENDS之间.
可用ASSUME随时修改"段 寄存器名:段名"之间的联系.也可用关键字NOTHING将前面的设置删除.
【例】ASSUME ES :NOTHING;删除前面对ES与某段的联系
ASSUME NOTHING;删除全部4个段寄存器的设置
GROUP伪指令
GROUP 是群或组的意思,它用来把模块中若干不同名的段集合成一个组,并赋予一个组名,使它们都装在同一个逻辑段中(64K). 组内各段名间的跳转都可以看作是段内跳转.
格式:〈组名〉 GROUP 〈段名1,段名2,…〉
组名和段名一样,它表示该组的段地 址.
段寄存器的装入
ASSUME只是建立了当前段与段寄存器之间的联系,还必须用程序把段寄存器装入,即将段基址装入相应的段寄存器中.
DS 和ES的装入
在程序中,引用段名就是以立即数的形式获取该段的段基址,而立即数不能直接传递给段寄存器,因此,一个段的段基址要通过通用寄存器传 送给DS,ES.【例】MOV AX ,DATA1 ;假定DATA1为段名
MOV DS ,AX
SS的装入
系统自动对SS及 SP初始化:
用段定义伪指令SEGMENT定义堆栈段时组合类型选择"STACK"参数,且用ASSUME伪指令把该段指派给段寄存器SS.
【例】 STACK1 SEGMENT PARA STACK
DW 40H DUP( )
STACK1 ENDS
:
CODE SEGMENT
ASSUME CS:CODE,SS:STACK1
:
CODE ENDS
※这样,当这个程 序目标代码装入存储器后,SS中自动装入STACK段的段基址,且堆栈指针也指向堆栈底部+1的存储单元.
用户对SS及SP初始化:
若在 SEGMENT伪指令中未选用"STACK"参数项,或在程序中要调换另一个堆栈段,可用类似DS,ES的装入方法,且需几条指令来实现对SS和SP的装 入.
【例】STACK1 SEGMENT
DW 40H DUP(0)
TOP LABEL WORD
STACK1 ENDS

CODE SEGMENT

MOV AX,STACK1
MOV SS,AX
MOV SP,OFFSET TOP
※注意:在堆栈段的段基址装入SS后,紧接着必须用一条指令初始化堆栈指针SP,中间不要插入另外的指令.
CS 的装入
代码段CS及指令指针IP在程序初始化时装入.源程序结束时有一END伪指令.
格式:END 起始地址
该起始地址为程序装 入内存后,开始执行的起始点.
过程定义伪指令(PROC/ENDP)
在程序设计中,我们通常把具有一定功能的程序段设计成一个子程 序.MASM宏汇编程序用"过程"(PROCEDURE)来构造子程序.
格式: 〈过程名〉PROC [类型]

RET
〈过程名〉ENDP
说明:
① 过程名是为该过程取的名字,具有与语句标号相同的属性,即具有段地址,偏移地址和类型三类属性.
② 地址属性是指过程中第一个语句的地址.
③ 类型属性由格式中的类型指明,可以有NEAR和FAR两种.若类型缺省或为NEAR时,表示该过程只能为所在段的程序调用;若为FAR时,则可被跨段调 用.
④ RET为过程返回指令,不能省,否则过程将无法返回.返回指令属于段内返回还是段间返回与过程类型有关.RET伪指令可出现在过程的任何位置,若一个过程 有多个出口,它可能有多个返回指令,但一个过程执行的最后一条指令一定是RET.
⑤ 过程既允许嵌套定义,也允许嵌套调用.
※注意: 子程序也可以不以过程形式出现,此时CALL指令中的操作数应该是子程序第一条可执行语句的语句标号.
定位伪指令(ORG)和当前位置计数器 ($)
在汇编源程序时,为了指示下一个数据或指令在相应段中的偏移量,使用了一个当前位置计数器,用于记载汇编时的当前偏移量.符号"$"代表当 前位置计数器的现行值.
格式:ORG
功能:把表达式的值赋给当前位置计数器.ORG 语句后的指令或数据以表达式给定的值作起始偏移量.其中表达式的值是以65536为模进行计算的,且一定为正数.表达式中可包含当前位置计数器$的值.例 如:
DATA SEGMENT
ORG 30H ;DB1 在 DATA数据段的偏移量为30H
DB1 DB 12H,23H
ORG $+20H ;保留20H个字节单元
STRING DB 'ABCDEFGHI'
COUT EQU $-STRING
DATA ENDS
标题伪指令(TITLE)
格式:TITLE 文本
功能:给程序指 定一个标题,以便在列表文件的每一页的第一行显示这个标题.该文本可以是用户任意选用的名字或字符串,但字符不得超过60个.
※如果程序中没有使 用NAME伪操作,则汇编程序将用TITLE文本中的前6个字符作为模块名;如果程序中既无NAME又无TITLE伪操作,则将用源文件名作为模块名.所 以,NAME及TITLE伪操作并不是必要的,但一般经常使用TITLE,以便在列表文件中能打印出标题来.
模块定义与通信伪指令
1)NAME 和END
格式: [ NAME 〈模块名〉]

END [标号]
说明:模块名是为该模块起的名字,NAME 语句可缺省,若缺省,该模块的源程序文件名就是模块名;
若该模块是主模块,END语句后跟一个标号,它表示该程序的启动地址,是该模块第一条指令性语句的标号;
若不是主模块,END语句后的标号应去除.被连接的各模块中,只能有一个模块是主模块.
2)PUBLIC
格式:PUBLIC 〈符号表〉
功能:表示该模块中符号表中的符号常量,变量,标号,过程名等可以被其它模块引用;
说明:符号表中的符号在该模块中必须有 定义;
符号之间用逗号分隔;
寄存器名,非整数符号常量,值超过字范围的整数符号常量不得出现在符号表中;
PUBLIC语句可安排在模块的任意位置;
符号表中的符号若有过程名,大多是FAR类型;若是NEAR类型,仅供其它模块的同名段引用.
3)EXTRN
格式:EXTRN 〈符号:类型〉[,…]
功能:表示在其它模块中定义过并说明为PUBLIC的那些符号,在本模块中需要引用;
说 明:符号表中的类型可以是BYTE,WORD,DWORD,NEAR,FAR和ABS,ABS表示该符号是符号常量;
符号类型必须与它们在其它模块定义时的符号类型保持一致;
符号表中的符号不允许在本模块中再定义;
符号表中的符号在本模块中只能单独被引用,不得出现在表达式中;
本语句可安排在本模块的任何地方.
4)INCLUDE
格 式:INCLUDE 〈文件名〉
功能:把另一个源文件插入到当前的源文件中一起汇编,直到该文件中语句汇编完毕,汇编程序继续汇编 INCLUDE语句之后的语句.
说明:用作插入的源文件通常编辑成一个不含END伪指令的源程序文件;
INCLUDE可以嵌套.即用INCLUDE伪指令插入的文件还可以包含INCLUDE语句.
§5 DOS功能调用简介
PC-DOS(也称IBM-DOS或MS-DOS)是美国微软公司为IBM-PC微机研制的磁盘操作系统.它不仅提供了许多命令,还给用户提供了80多个 常用子程序,每个子程序对应一个功能号,其编号从0――57H.
所谓DOS功能调用就是指对这些子程序的调用,也称系统功能调用.子程序的顺序 编号称为功能调用号.
DOS功能调用的一般过程:
传送入口参数到指定寄存器中
将功能号送入AH寄存器中
INT 21H
下 面选择一部分常用的功能调用作简要说明:
一,基本输入输出
1. 键盘输入单字符
程序:MOV AH,1
INT 21H
没有入口参数.上述指令执行后,系统等待从键盘输入一个字符,一旦输入,则系统先检查是否Ctrl-Break,若输入的是 Ctrl-Break,程序自动返回到DOS控制下,否则,将该字符的ASCⅡ码置入AL寄存器中,并在屏幕上显示该字符.
2.输出单字符
程 序:MOV DL,'A'
MOV AH,2
INT 21H
执行2号系统功能调用,将置入DL寄存器中的字符从屏幕上显示 输出.调用结果,在屏幕上显示字符A.
3.输出单字符到打印机 ,AH=05H
功能:将DL寄存器的字符输出到打印机.
程 序:MOV DL,'A'
MOV AH,5
INT 21H
4.不带显示的键盘输入,AH=08H
功能同1号功能 调用,只是不在屏幕上显示字符.
5.输入字符串,AH=0AH
功能:从键盘接收字符串到DS:DX所指内存缓冲区,因此必须事先在内存 储器中定义一个缓冲区.要求内存缓冲区的格式为:首字节指出计划接收字符个数,第二个字节留作机器自动填写实际接收字符个数,从第三个字节开始存放接收的 字符串,最后键入回车键表示字符串结束.若实际输入字符数少于指定数,剩余内存缓冲区填零;若实际输入字符数多于指定数,则多出的字符会自动丢失,而且响 铃,向程序员发出警告.DOS自动在输入字符串的末尾加上的回车字符不被计入实际接收的字符数中.例如:
DATA SEGMENT
BUF DB 50 ;缓冲区长度
DB ;为填入实际字符个数保留
DB 50 DUP( ) ;定义50个字节的存储空间
:
DATA ENDS
CODE SEGMENT
:
MOV AX,DATA
MOV DS,AX ; DS←段地址
:
MOV DX,OFFSET BUF ;DX←首字节偏移地址
MOV AH,0AH
INT 21H
:
CODE ENDS
6.输出 字符串,AH=09H
功能:把DS:DX所指单元内容作为字符串首字符,将该字符串逐个显示在屏幕上,直到遇到串尾标志'$'为止($不显示). 例如:
DATA SEGMENT
BUF DB 'HOW DO YOU DO $
:
DATA ENDS
CODE SEGMENT
:
MOV AX,DATA
MOV DS,AX
:
MOV DX,OFFSET BUF
MOV AH,9
INT 21H
:
CODE ENDS
执行本程序 时,屏幕将显示:HOW DO YOU DO
二,文件管理
几个基本概念:
文件:是具有名字的一维连续信息的集合.DOS以 文件的形式管理数字设备和磁盘数据;
文件名:在DOS文件系统中,文件名是一个以零结尾的字符串,该字符串可包含驱动器名,路径,文件名和扩展 名,如:C:/SAMPLE/MY.ASM;
文件句柄式文件管理:该方式先将工作文件名和一个16位的数值相关联,然后,对文件的操作不必使用 文件名,而直接使用关联数值,这个数值就是文件句柄.该方式从PC-DOS2.0版本开始引入.
DOS文件管理功能:包括建立,打开,读写,关 闭,删除,查找文件以及有关的其它文件操作.这些操作是相互联系的,如读写文件之前,必须先打开或建立文件,要设置好磁盘传输区或数据缓冲区,然后才能读 写,读写之后还要关闭文件等.
文件管理中的最基本的几个功能调用如下:
1.AH=3CH,创建一个文件
功能:建立并打开一个新文件,文件名是DS:DX所指的以00H结尾的字符串,若系统中已有相同的文件名称,则此文件会变成空白.
入口参 数:DS:DX←文件名字符串的起始地址;
CX←文件属性.0表示可读写,1表示只读.
出口参数:若建立文件成功,则CF=0,AX=文件句柄;否则CF=1,AX=错误码(3,4或5),其中3表示找不到路径名称,4表示文件句柄已用 完,5表示存取不允许.
2.AH=3DH,打开一个文件
功能:打开名为DS:DX所指字符串的文件.
入口参 数:DS:DX←文件名字符串的始地址,AL=访问码(0表示读,1表示写,2表示读写).
出口参数:若文件打开成功,则CF=0,AX=文件句柄;若失败,则CF=1,AX=错误码(3,4,5或12),其中12表示无效访问码,其它同上.
3.AH=3EH, 关闭一个文件
功能:关闭由BX寄存器所指文件句柄的文件.
入口参数:BX←指定欲关闭文件的文件句柄.
出口参数:若关闭成功,则CF=0,若关闭失败,则CF=1,AX=6表示无效的文件句柄.
4.AH=3FH,读取一个文件
功能:从 BX寄存器所指文件句柄文件内,读取CX个字节,且将所读取的字节存储在DS:DX所指定的缓冲区内.
入口参数:BX←文件句柄,CX←预计读 取的字节数,DS:DX←接收数据的缓冲区地址.
出口参数:若读取成功,则CF=0,AX=实际读取的字符数;若读取失败,则CF=1,AX=出错码(5或6).
5.AH=40H,写文件
功 能:将DS:DX所指缓冲区中的CX个字节数据写到BX指定文件句柄的文件中.
入口参数:BX←文件句柄;CX←预计写入的字节 数;DS:DX←源数据缓冲区地址.
出口参数:若写成功,则CF=0,AX=实际写入的字节数;若写失败,则CF=1,AX=出错码(5或 6).
三,其它
1. AH=00H,程序终止
功能:退出用户程序并返回操作系统.其功能与INT 20H指令相同.
注 意点:执行该中断调用时,CS必须指向PSP的起始地址.PSP是DOS装入可执行程序时,为该程序生成的段前缀数据块,当被装入程序取得控制权 时,DS,ES便指向PSP首地址.
通常,结束用户程序并返回操作系统需要如下指令完成:
PUSH DS
MOV AX,0
PUSH AX ;保存PSP入口地址(DS:00)进栈

RET ;弹出PSP入口地址至CS
之所以能返回 DOS,是因为RET指令使程序转移到PSP入口,执行该入口处的INT 20H指令所至.
2.AH=4CH,进程终止.
功能:没有 入口参数.结束当前执行的程序,并返回DOS操作系统,屏幕显示操作系统提示符.
MOV AH,4CH
INT 21H
3. 设置日期(2BH)
调用2BH 功能时,年号(1980~2099)以装配型BCD码形式置入CX中,DH中存放月份(1~12),DL中放日期.若日期有效,则设置成功,AL=0;否 则AL=0FFH.以后日期会自动修改.例如:
MOV CX,2000H
MOV DH,8
MOV DL,4
MOV AH,2BH
INT 21H
4.取得日期(2AH)
功能:将当前有效日期取到CX和DX寄存器中,存放格式与设置日期时相同,没 有入口参数.例如:
MOV AH,2AH
INT 21H
5.设置时间(2DH)
功能:4个8位二进制数.CH表示小时 (0~23),CL表示分(0~59),DH表示秒(0~59),DL表示百分之一秒(0~99).时间设置成功,则AL=0;否则AL=0FFH.以后 时间会自动修改.例如:设置当前时间8点15分20.5秒.
MOV CX,0815H ;设置8点15分
MOV DX,2050H ;设置20.5秒
MOV AH,2DH
6.取得时间(2CH)
功能:将当前时间置入CX和DX寄存器中.例如:
MOV AH,2CH
INT 21H
※课本P103页程序举例.
§6 汇编语言程序设计举例
一,顺序程序设计
顺序程 序:顺序执行的程序称为顺序程序.
特点:每一条指令在执行过程中只被执行一次.
例1 编制一程序,求出下列公式中x=3时,y的值.
为 了运算方便,可对上式进行变换,得:
这样可以尽量利用寄存器进行运算.
SSEG SEGMENT STACK ;堆栈段
STA DW 100 DUP( )
SSEG ENDS
DSEG SEGMENT ;数据段
Y DW 0 ;存放y值
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS:DSEG,SS:SSEG
BAA:MOV AX,DSEG
MOV DS,AX ;DS段基值装入
MOV AX,3 ;把x=3置入AX
MOV BX,3 ;把x=3置入BX
MOV CX,6
MUL CX ;AX←AX*CX即6x
ADD AX,5 ;6x+5
MUL BX ;(6x+5)*x
ADD AX,2 ;(6x+5)*x+2
MUL BX ;[(6x+5)*x+2]x
ADD AX,7 ;[(6x+5)*x+2]x+7
MUL BX ;{[(6x+5)*x+2]x+7}x
ADD AX,8 ;{[(6x+5)*x+2]x+7}x+8
MOV Y,AX
MOV AH,4CH
INT 21H ;返回DOS
CSEG ENDS
END BAA
例2 把BUF开始的两个字节单元中的压缩BCD数相加,结果存入字单元RES中.
NAME EXAM1
DATA SEGMENT
BUF DB 89H,34H
RES DW
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:MOV AX,DATA
MOV DS,AX
LEA BX,BUF
MOV AL,BUF ;取加数
ADD AL,[BX+1] ;做二进制加法
DAA ;调整为十进制结果
LAHF ;取标志位
AND AH,01H; ;取CF位
MOV RES,AX ;存结果
MOV AH,4CH
INT 21H
CODE ENDS
END START
例3 以BUF为首地址的内存中存有1~15的平方表.查表求X单元中数(在1~15之间)的平方值,并送回X单元.
NAME EXAM2
DATA SEGMENT
BUF DB 1,4,9,16,25,36,49,64
DB 81,100,121,144,169,196,255
X DB 12
DATA ENDS
STACK SEGMENT STACK'STACK'
DB 100 DUP( )
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK ;段地址说明
START:MOV AX,DATA
MOV DS,AX ;数据段地址装填(堆栈段地址由系统装填)
MOV SI,OFFSET BUF ;取BUF的偏移量
XOR AX,AX ;AX清0
MOV AL,X ;取X
DEC AL
ADD SI,AX ;X平方值的地址
MOV AL,[SI] ;取X的平方值
MOV X,AL
MOV AH,4CH
INT 21H ;返回DOS
CODE ENDS
END START
2. 分支程序设计
计算机的一个重要特点在于它能"判断"情况.计算机指令系统中的比较指令, 测试指令和条件转移指令等就反映了这种能力.
例如程序设计中经常会遇到判断"相等"和"不相等","负"和"正","大于"和"小于","满足 条件"和"不满足条件"等等.这种判断使程序的流程不再是一条顺序执行的直线,而变为由两个或多个分支所组成的倒树型结构,其中每一个分支只有在满足条件 时才被执行.
利用比较转移指令实现分支
【例1】 有符号函数
DATA SEGMENT
XX DB
YY DB
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP ( )
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:STACK
START: MOV AX, DATA
MOV DS, AX
MOV AL, XX
CMP AL, 0
JGE BIGR ;X≥0,转移至BIGR
MOV AL, 0FFH ;x0给1的补码值
EQUL: MOV YY, AL
CODE ENDS
END START
利用跳转表实现分支
【例2】
DATA SEGMENT
BASE DW SBR0,SBR1,SBR2,SBR3
DW SBR4,SBR5,SBR6,SBR7
BN DB ;存放编号
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 100H DUP ( )
STACK ENDS
COSEG SEGMENT
ASSUME CS:COSEG,DS:DATA,SS:STACK
START PROC FAR
PUSH DS
PUSH AX
MOV AX,0
MOV AX,DATA
MOV DS,AX
MOV AL,BN ;取编号
MOV AH,0 ;扩展到16位
SAL AX,1 ;编号乘以2
MOV BX,OFFSET BASE
ADD BX,AX ;编号所对应的偏移地址
MOV AX,[BX] ;加工程序的入口地址→AX
JMP AX ;转向编号对应的处理程序
RET
START ENDP
COSEG ENDS
END START
【例3】将内存中以STRI1为首址的50个字节单元中的数据传送到以 STRI2为首址的50个字节单元中.
分析如下:
根据源数据快与目的数据块位置的不同,可分为两种情况:
第一种情况:源数 据块的首址高于目的数据块的首址,考虑到有可能两块部分重叠,用增址方式串传送指令进行数据传送;
第二种情况:源数据块的首址低于目的数据块的 首址,考虑到有可能两块部分重叠,用减址方式串传送 指令 进行数据传送.
NAME EXAM3
DATA SEGMENT
STRI DB 200 DUP( )
STRI1 EQU STRI+30
STRI2 EQU STRI+70
COUNT EQU 50
DATA ENDS
STACK SEGMENT PARA STACK 'STACK '
STAPN DB 100 DUP( )
TOP EQU LENGTH STAPN
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,ES:DATA,SS:STACK ;段地址说明
START: MOV AX,DATA
MOV DS,AX ;数据段地址装填
MOV ES,AX ;附加段地址装填
MOV SP,TOP ;送堆栈指针
MOV CX,COUNT ;送串长
MOV SI,OFFSET STRI1 ;送STRI1地址指针
MOV DI,OFFSET STRI2 ;送STRI2地址指针
CLD ;正向
CMP SI,DI ;两串首地址比较
JA RES ;STRI1首址大于STRI2首地址转RES
ADD SI,COUNT-1 ;源块尾址
ADD DI,COUNT-1 ;目的块尾址
STD ;反向
RES: REP MOVSB ;数据块传送
MOV AH,4CH
INT 21H ;返回DOS
CODE ENDS
END START
【例4】将内存中以BUF为首址的100个字节单元中用原码表示的有符号数依次变成用补码表示的有符号数,仍依次放在原100个字节单元中.
分析 如下:
1)一切正数的原,补,反码均相同,因此符号位为0,不变;
2)负数的补码可通过对应的正数补码求负得到,而负数的原码和对应 正数的原码仅符号位不同,因此,若符号位为1,可将符号位清0,变成对应正数的原码,再求负,即为要求的补码.

NAME EXAM4
DATA SEGMENT
BUF DB 200 DUP( )
COUNT EQU 100
DATA ENDS
STACK SEGMENT PATA STACK 'STACK '
STAPN DB 100 DUP( )
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK
BEGIN:MOV AX,DATA
MOV DS,AX
MOV CX,COUNT ;串长送CX
LEA BX,BUF ;BUF首址送BX
L2: TEST BYTE PTR[BX],80H ;[BX]最高位是否为0
JZ L1 ;为0转L1
AND BYTE PTR[BX],7FH ;[BX]最高位清0
NEG BYTE PTR[BX] ;求负
L1: INC BX ;指向下一单元
LOOP L2 ;CX-1→CX,不为0转L2
MOV AH,4CH
INT 21H
CODE ENDS
END BEGIN
3. 循环程序设计
1)循环程序的构成:任何循环程序都可分为循环初始部分,循环体和循环结束部分.
循环初始部分:为进入循环做必要的准备工作;
循环体:是程序中重复执行的程序段,由两部分组成:
① 循环工作部分:用于执行程序的实际任务;
② 循环参数修改及循环控制部分:为进入下一次循环,修改地址指针,计数器内容等项参数;检测循环是否已执行了规定的次数,从而确定继续循环还是结束循环.
循环结束部分:进行循环之后的处理.
2)循环的类型
循环体的结构依照问题的不同,一般可以分为两种类型:
① 先判断后处理;
② 先处理后判断.
3)控制循环次数的方法:
有三种:用计数控制循环,用条件控制循环和用逻辑变量控制循环.其中,前两种方法用的最多.
① 用计数控制循环
对于循环次数已知的程 序,或是在进入循环前可由某变量确定循环次数的程序,通常用计数器来控制循环.
【例5】把BUF开始的10个字节单元中的二进制数据累加,求得 的和放到RES字单元
本例采用图4. 6(a)的程序结构编成如下:
NAME EXAM5
DATA SEGMENT
BUF DB 1,4,9,5,21,64,12,6,10,23
RES DW
DATA ENDS
STACK SEGMENT PARA STACK 'STACK '
DB 100 DUP( )
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK
START:MOV AX,DATA
MOV DS,AX
MOV AX,0 ;AL清0
MOV CX,0AH ;置计数器初值
MOV BX,OFFSET BUF ;置地址指针
LP: ADD AL,[BX] ;取一个数累加到AL上
ADC AH,0
INC BX ;地址加1
LOOP LP ;不为0,循环
MOV RES,AX ;传送结果
MOV AH,4CH
INT 21H
CODE ENDS
② 用条件控制循环
适用于某些循环次数未知的程序,或循环次数可变的程序,可以由问题给出的条件控 制循环结束.
【例6】从STRIN单元开始有一字符串,以'*'作为结束标志.求字符串的长度.
NAME EXAM6
DATA SEGMENT
STRIN DB 'ASDFGHJ123KJ*'
COUNT DW
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP( )
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK
START: MOV AX,DATA
MOV DS,AX
MOV BX,OFFSET STRIN ;置地址指针
MOV CX,0 ;置计数器初值为0
LP: MOV AL,[BX] ;取一个字符到AL中
CMP AL,'*' ;是'*'吗
JE DONE ;是'*'则结束
INC CX ;不是'*'则计数加1
INC BX ;地址加1
JMP LP ;继续
DONE: MOV COUNT,CX ;计数送COUNT单元
MOV AH,4CH
INT 21H
CODE ENDS
END START
4. 子程序设计
1)子程序的定义
在实际编程中,常常回遇到功能完全相同的程序段,或不在同一程序模块,或虽在同一模块而需重复执行,但又不是连续重复执行.为了避免重复编制同一段程序, 节省存储空间,把程序段独立开来,附加少量额外语句,将其编制成公用子程序,供程序其他地方需要时调用.这种程序的设计方法称之为子 程序 设计 .
2)子程序的组成
① 保护现场(一些将在子程序运行时将要被破坏的寄存器的内容);
② 依入口参数从指定位置取要加工处理的信息;
③ 加工处理;
④ 依出口参数向指定位置送经加工处理后的结果信息;
⑤ 返回调用程序.
3)调用子程序时一般应增加如下 功能 语句:
想指定位置送要加工处理的信息;调用子 程 序 .
【例7】将ARRA缓冲区中n个符号数(字),按照从小到大的顺序排序后显示在屏幕上.
分析:排序算法采用 冒泡法.假定待排序数组中有X1,X2,…Xn-1,Xn共n个数据,冒泡排序法的具体作法是:最多有n-1次大循环.每次大循环均从底部开始进行数的两 两比较,若后者大于前者,两者位置不变;若后者小于前者,则两者位置交换.然后两两比较向
前推移,直到本次大循环应完成的两两比较的次数(称为小 循环变量)达到为止.此时,本次大循环结束,最小的数冒到本次大循环的顶部.第一次大循环,两两比较的次数为n-1次,最小数据项冒到X1的位置;第二次 大循环,两
原文链接: 下载文档 - [psp] 汇编语言程序设计
链接地址:http://www.xiadoc.com/doc /0c33ff9bc64293edddafb37f29a4a85e.html

你可能感兴趣的:(汇编,语言,存储,dos,byte,include)