第三章汇编语言程序设计.docx
《第三章汇编语言程序设计.docx》由会员分享,可在线阅读,更多相关《第三章汇编语言程序设计.docx(40页珍藏版)》请在冰点文库上搜索。
![第三章汇编语言程序设计.docx](https://file1.bingdoc.com/fileroot1/2023-5/24/89414afb-0d12-4838-bde1-930466bcf09d/89414afb-0d12-4838-bde1-930466bcf09d1.gif)
第三章汇编语言程序设计
第三章汇编语言程序设计
内容提要:
⒈概述:
汇编语言特点,汇编程序功能
⒉汇编语言结构:
语句类别与结构、源程序结构
⒊汇编语言中的表达式:
常量、变量、标号、运算符
⒋伪指令:
符号定义伪指令、变量定义伪指令、段定义伪指令、过程定义伪指令、模块定义与通信伪指令
⒌宏指令:
宏定义、宏调用、宏扩展、用于宏定义的其它伪指令
⒍DOS功能调用简介:
基本I/O,文件管理,其它
⒎汇编语言程序设计举例
顺序结构、分支结构、循环结构、子程序、多模块程序
⒏编程实验
学习目标:
了解汇编语言特点、汇编程序功能、汇编语言结构;
掌握汇编语言中的表达式、伪指令、宏定义的含义和用法;
掌握DOS功能调用基本I/O,返回DOS方法,了解文件管理;
理解顺序程序、分支程序、循环程序、含子程序的程序设计的基本方法,能编写、运行、调试简单的汇编语言程序。
一程序设计语言概述
⒈汇编语言特点
使用助记符表示指令;能用标识符代替地址、常量和变量;借助伪指令和汇编程序,程序员不必具体安排程序和数据在存储器中存放。
⒉汇编语言源程序
用汇编语言编写的程序。
⒊汇编程序
是系统软件中的一种程序,它的作用是把汇编语言源程序自动翻译成机器能识别的机器语言目标程序。
它有两种类型:
①行汇编:
对汇编语言源程序逐条汇编,特点是小型、方便;
②宏汇编:
对汇编语言源程序按模块汇编,特点是功能强,开发和调试手段较完善。
二8086汇编语言的基本语法
⒈标识符
用来对程序中的变量、常量、段、过程等进行命名,它是组成语句的一个常用成分,它的命名应符合下列规定:
①标识符是一个字符串,第一个字符必须是字母、“?
”、“@”、或下划线“—”这四种字符中的一个;
②从第二个开始,可以是字母、数字、“?
”、“@”、“—”;
③一个标识符的长度可以由1~31个字符组成。
注意:
不能使用系统中已经定义过的符号,如寄存器名、分支条件用标志、助记符、定义等等。
⒉语句类型与结构
有三种类型:
指令性语句:
是机器指令的符号表示,经汇编程序汇编后能产生对应的机器指令代码,在形成执行文件时执行;
指示性语句(也称伪指令语句):
指示给汇编程序提供一些控制信息,帮助汇编程序正确汇编指令性语句,在汇编时被执行,没有对应的机器码;
宏指令语句:
是指令性语句和指示性语句的复合体,是按照一定规则,根据用户需要定义的新指令;在汇编时被展开,在形成执行文件时执行其展开体。
㈠指令性语句结构
[标号:
][前缀]指令助记符[操作数][;注释]
说明:
①方括号表示的成分可以选用或缺省;
②标号是后面紧跟“:
”的一个标识符,标号代表该行指令在存储器中的首地址,标号可作为转移指令和调用指令的一个操作数;
③前缀如重复前缀、总线封锁前缀等;
④指令助记符
⑤操作数可以是一个、两个或没有,由指令类型决定,若有两个操作数,前面为目的操作数,后面为源操作数,中间用逗号隔开;
⑥注释是以“;”开始的字符串,不影响程序的汇编与执行,仅用于增加源程序的可读性。
㈡指示性语句结构
[名字]伪指令助记符[操作数][;注释]
说明:
① 名字可以是符号常量名、变量名、过程名、段名等,名字后面不能有“:
”;
②伪指令命令助记符共有40多个,按功能不同分成八类,本章介绍的常用五类共20多个;
③操作数可少到一个没有,多到两个以上,操作数之间须用逗号分隔;
㈢宏指令语句结构
[宏名]宏操作助记符[操作数][;注释]
说明:
① 宏名即宏指令名,是一标识符,宏名后面不能有“:
”;
②宏操作助记符共有8个,分别是MACRO、ENDM、EXITM、LOCAL、REPT、IRPC、IRP、PURGE;
③其余同指示性语句。
⒊汇编语言源程序结构
汇编语言源程序是以模块为单位独立汇编的。
一个完整的源程序,至少由一个模块组成。
较大的应用程序可由多个模块组成,每个模块具有不同的功能,把这些模块分别汇编成目标代码后,再用连接程序把它们连接成一个可执行程序。
一个源程序模块又分成若干个段。
三汇编语言中的表达式
概述:
表达式可以在汇编语言的语句中含有。
●表达式的组成:
运算对象:
可以是常量、变量、标号;
运算符:
算术运算符、逻辑运算符、关系运算符。
●表达式的分类:
数值表达式:
只产生一个数值结果;
地址表达式:
产生一个存储器地址,若地址中存放的是数据,则这个地址为变量,若地址中存放的是指令,则这个地址为标号。
●表达式的运算:
由汇编程序汇编时完成,运算所得结果再作为语句操作数使用。
⒈表达式中的常量、变量和标号
均能被汇编程序识别。
㈠常量
是在汇编时已经确定的常数值,常量可以是数据和字符。
常量分为“数值常量”和“符号常量”两种。
例:
ONEEQU1
DATA=2*12H
MOVAX,DATA+ONE
执行上述程序后,即把25H送到AX中。
㈡变量
常以变量名的形式出现在程序中,可以看作是存放数据的存储单元的符号地址,它用来定义存储器中的数据。
变量具有三种属性:
①段属性:
变量所在段的段地址;
②偏移地址属性:
变量所在段的段内偏移地址;
③类型属性:
变量占用存储单元的字节数:
BYTE:
字节型,一字节
WORD:
字型,两字节
DWORD:
双字型,四字节
QWORD:
四字型,八字节
TBYTE:
五字型,十字节
变量名可以使用伪指令DB、DW、DD、DQ、DT定义。
例:
YDW4981H,1234H;变量Y是字类型,该变量存储区有两个字数据,Y=4981H
ZDD10DUP(0);变量Z是双字类型,该变量存储区有10个值为0的双字数据
㈢标号
是给指令性语句所在单元地址取的名字,它表明该指令在存储器中的位置,可作为转移类指令的操作数。
它有三种属性:
①段属性:
标号所在段的段地址;
② 偏移地址属性:
标号所在段的段内偏移地址;
③类型属性:
(也称距离属性)
NEAR:
近标号,表示该标号在段内使用;
FAR:
远标号,表示该标号在段间使用。
⒉表达式中的各类运算符
㈠算术运算符共七种
+(加)、-(减)、*(乘)、/(除)、MOD(模除)、SHL(左移)、SHR(右移)。
注意:
除(/)只取商,模除(MOD)只取余,SHL一次相当于*2,SHR一次相当于/2。
例:
MOVAX,15*4/7;AX=0008H
ADDAX,60MOD7;AX=8+4=12
MOVCX,-2*30-10;CX=-70
㈡逻辑运算符
AND、OR、XOR、NOT四种。
逻辑运算符:
只出现在语句的操作数部分,运算在汇编时完成;
逻辑操作指令:
只出现在指令的操作码部分,运算在执行指令时完成。
例:
MOVAL,NOT10101010B;等效于MOVAL,01010101B
ORAL,10100000BOR00000101B;等效于ORAL,10100101B
XORAX,0FA0HXOR0F00AH;等效于XORAX,0FFAAH
㈢关系运算符
EQ(等于)、NE(不等)、LT(小于)、GT(大于)、LE(小于等于)、GE(大于等于)共六种。
它们对两个运算对象进行比较操作,若满足条件,表示运算结果为真“TRUE”,输出结果为全“1”;若比较后不满足条件为假“FALSE”,输出结果为全“0”。
例:
MOVAX,5EQU101B;等效于MOVAX,0FFFFH
MOVAL,64HGE100;等效于MOVAL,0FFH
MOVBH,10HGT16;等效于MOVBH,00H
㈣取值运算符
取值运算符的操作对象:
必须是存储器操作数,即变量、标号或过程名。
使用格式为:
取值运算符变量或标号
返回的结果是一个数值常量。
①SEG运算符
取段地址运算符,该运算返回变量或标号所在段的段地址(字常量)。
例:
MOVBX,SEGBUF;BX←变量BUF的段地址
② OFFSET运算符
取段内偏移地址符,该运算返回变量或标号所在段的段内偏移地址。
例:
MOVAX,OFFSETSTART;AX←标号START的偏移地址
③TYPE运算符
取类型属性运算符,该运算返回变量或标号的类型值。
若运算对象是标号,则返回标号的距离属性值,若运算对象是变量,则返回变量类型所占字节数。
例:
N1DB30H,31H,32H
N2DW4142H,4344H
N3DDN2
ALD:
MOVAL,TYPEN1;AL←1
ADDAH,TYPEN2;AH←AH+2
MOVBL,TYPEN3;BL←4
MOVBH,TYPEALD;BH←-1(0FFH)
变量和标号的类型值对应关系如下:
类型
类型值
变
量
BYTE
1
WORD
2
DWORD
4
QWORD
8
TWORD
10
标号
NEAR
-1
FAR
-2
④ LENGTH运算符
取数组变量元素个数运算符,如果变量是用重复数据操作符DUP说明的,则返回DUP前面的数值(即重复次数);如果没有DUP说明,则返回值总是“1”。
例:
KADB10HDUP(0)
KBDB10H,20H,30H
KCDW20HDUP(0,1,2DUP
(2))
KDDB’ABCDEFGH’
MOVAL,LENGTHKA;AL←10H
MOVBL,LENGTHKB;BL←1
MOVCX,LENGTHKC;CX←20H
MOVDX,LENGTHKD;DX←1
⑤SIZE运算符
取数组变量总字节数运算符,该运算符返回数组变量所占的总字节数,相当于LENGTH和TYPE两个运算符返回值的乘积。
⑥ HIGH运算符
取地址表达式或16位绝对值高8位。
例:
CONSTEQU0ABCDH
则:
MOVAH,HIGHCONST将汇编成:
MOVAH,0ABH
⑦LOW运算符
取地址表达式或16位绝对值低8位。
在上例中,MOVAL,LOW0ABCDH将汇编成:
MOVAL,0CDH
㈤设置属性运算符
①“:
”运算符
用来临时给变量、标号或地址表达式指定一个段属性。
例:
MOVAX,ES:
[BX];表示不用DS,而用ES来形成段地址。
②PTR运算符
PTR运算符赋予“表达式”指定的“类型”,新的类型只在所处的指令内有效。
PTR的格式为:
类型PTR表达式
③THIS运算符
该运算符和“=”(或EQU)伪指令连用,把它后面指定的类型属性或距离属性赋给当前的变量或标号。
常用的格式为:
变量或标号=THIS属性
例:
GAMA=THISBYTE;变量GAMA的类型属性定义为字节
ST=THISFAR;标号ST赋予远标号属性
㈥其他运算符
①SHORT运算符
当转移指令的目标地址与该指令之间的距离在-128~+127字节范围内,可用SHORT运算符进行说明,以保证汇编程序能为该指令生成最短的机器码,从而提高运行效率。
例:
L1:
JMPSHORTL2
┆
L2:
MOVAX,BX
标号L1、L2之间的字节距离小于127字节,称为短转移。
②圆括号“()”运算符
用来改变被括运算符的优先级别。
③方括号“[]”运算符
多用在存储器操作数的表达式中
运算规则:
a.方括号的内容表示存储器操作数的偏移地址;
b.有多对方括号顺序排列时,操作数的偏移地址等于各方括号内容之和;
c.一个常量后面跟有方括号时,偏移地址等于该常量与方括号内容之和;
d.一个变量后面跟有方括号时,偏移地址等于该变量的偏移地址与方括号内容之和。
带方括号的地址表达式遵循的规则:
a.只有BX、BP、SI、DI可在方括号中出现;
b.不允许BX、BP同时出现在同一个地址表达式中;
c.不允许SI、DI同时出现在同一个地址表达式中;
d.当多个寄存器出现在方括号中时,只能作加运算;
e. 当方括号中包含BP,则隐含使用SS提供段地址,否则均隐含使用DS提供段地址。
四伪指令语句
伪指令语句格式为:
[名字]伪操作指令[操作数][;注释]
⒈符号定义伪指令
在汇编语言中,所有符号常量、变量名、标号、过程名、记录名、指令助记符、寄存器名等都称为符号,这些符号可以通过伪指令重新命名或定义新的类型属性。
㈠EQU伪指令
使用格式:
名字EQU表达式
功能:
是将数值或字符序列与一个指定的名字等价;
注意:
EQU定义过的名字不能重新定义。
①为常量定义一个符号,以便在程序中使用符号来表示常量。
格式:
符号常量名EQU数值表达式
例:
ONEEQU1
TWOEQU2
SUMEQUONE+TWO
② 给变量或标号定义新的类型属性并起一个新的名字。
格式:
变量名或标号名EQU[类型PTR]变量或标号
例:
FIRSTWEQUWORDPTRBYTES;给变量BYTES重新定义为字类型属性,并赋予新变量名FIRSTW
③可以给由地址表达式指出的任意存储单元定义一个名字。
格式:
符号名EQU地址表达式
例:
XYZEQU[BP+3];基址引用赋予符号名XYZ
AEQUARRAY[BX][SI];基址加变址引用赋予符号名A
PEQUES:
ALPHA;加段前缀的直接寻址引用符号名P
④用来为汇编语言中的任何符号定义一个新的名字。
格式:
新的名字EQU原符号名
例:
COUNTEQUCX;为寄存器CX定义新的符号名COUNT
LDEQUMOV;为指令助记符MOV定义新的符号名LD
㈡“=”伪指令
“=”伪指令与EQU具有相同的功能,区别仅在于“=”伪指令定义的符号允许重新定义,使用更灵活方便。
例:
EMP=60;定义EMP等于常数60
EMP=EMP+1;又定义EMP等于常数61
㈢LABEL伪指令
格式:
变量或标号名LABEL类型
功能:
为当前存储单元定义一个指定类型的变量名或标号。
下面的例子是LABEL伪指令的常见用法:
①用法一:
DA_BYTELABELBYTE;为当前存储单元定义一个字节变量名DA_BYTE
DA_WORDDW4142H,5152H;当前存储器单元另有一个字变量名DA_WORD
MOVAX,DA_WORD[0];AX←4142H
MOVBL,DA_BYTE[0];BL←42H
②用法二:
LOPFLABELFAR;为当前存储单元定义一个FAR属性的标号LOPF
LOPN:
MOVAX,[BX+DI];当前存储单元另定义一个NEAR属性的标号LOPN
┇;段间转移使用标号LOPF,段内则使用LOPN
⒉变量定义伪指令
常用的变量定义伪指令有DB、DW、DD、DQ、DT,分别用来定义字节、单字、双字、四字及十字节类型变量。
基本应用格式如下:
[变量名]{DB│DW│DD│DQ│DT}〈表达式〉
其中,变量名是可选的;{}中的伪操作指令必须选用一种,表达式有以下集中几种方式:
㈠数值表达式
这种形式定义的变量具有表达式给定的数值初值。
例:
BETADW4*10H;BETA为字类型,初值为64
㈡ASCII字符串
字符串必须用单引号括起来。
特点:
DB伪指令为串中每一个字符分配一个字节单元,且自左到右按地址递增的顺序依次存放,字符个数不得超过255个。
例:
MSGDB’STUDENT’
㈢地址表达式
地址表达式运算结果是一个地址,因此只能用DW或DD定义。
如果用DW定义,则将原变量或标号的偏移地址定义为新变量;
如果用DD定义,则将原变量或标号的偏移地址和段地址分别置入新变量的低位和高位字中。
例如:
BETADW3254H,5678H
PBETAWLABELWORD
PBETADDDBETA;变量的初值为BETA的段地址和偏移地址
MOVAX,SEGBETA
MOVBX,PBETAW;BX←BETA的偏移地址
MOVDX,PBETAW[2];DX=AX,为BETA的段地址
MOVCX,PBETAW[0];CX=BX,为BETA的偏移地址
㈣?
表达式
问号表示所定义的变量未指定初值。
例:
BUFDW?
;定义一个字变量BUF,初值为一随机数
㈤〈n〉DUP〈表达式〉
用于定义重复变量,DUP是重复数据操作符,n表示重复次数,括号内的表达式表示要重复的内容。
例:
TABDB100DUP(0);数组变量TAB有100个初值为0的字节元素
DUP操作符可以嵌套使用,即圆括号中的表达式又是一个带DUP的表达式。
例:
TABDW2DUP(5DUP(4),7)
数据序列为:
4,4,4,4,4,7,4,4,4,4,4,7共占24个字。
⒊段定义伪指令
8086利用存储器分段技术管理存储器信息,而段定义伪指令可使我们按段来组织程序和使用存储器。
涉及分段的伪指令主要有SEGMENT、ENDS、ORG、GROUP和ASSUME。
㈠SEGMENT和ENDS伪指令
①语句格式
〈段名〉SEGMENT[定位方式][组合方式][分类名]
┆;段内所有语句
〈段名〉ENDS
段名是为该段起的名字;
定位方式、组合方式和分类名是可选的,若选两个以上时,书写时顺序必须与格式中的顺序一致。
注意:
当某段作为堆栈段使用时,必须至少有组合方式STACK。
②组合方式
指出如何链接不同模块中的同名段,把不同模块中的同名段按照指定的方式组合起来。
既便于程序运行,又可以达到有效使用存储空间的目的。
组合方式有六种:
a.PUBLIC:
表示该段与其他模块中说明为PUBLIC的同名同类别的段链接起来共用一个段地址,形成一个物理段。
b.STACK:
与PUBLIC类型同样处理,只是组合后的这个段专门用作堆栈段。
c.COMMON:
表示该段与其他模块中被说明成COMMON的同名同类别段共用一个段起始
地址,且相互覆盖。
组合后,段的长度是各模块同名段中最大的COMMON段长度。
d.MEMORY:
表示该段定位在其他段之上,即地址较大区域。
如果各模块中不止一个段选用该方式,则把第一个遇到的段作MEMOR处理,而其它段均作COMMON方式处理。
e.AT〈数值表达式〉:
表示该段应按绝对地址定位,段地址为数值表达式的值,位移量为0。
例:
AT1234H
表示该段段基址为12340H。
f.NONE:
即不指定方式,链接时它将是一个独立的段。
如何链接参见图4.1。
③定位方式
定位方式通过汇编告知LINK程序如何将组合后的新段定位到存储器中。
定位方式有四种:
a.PARA定位方式:
规定段从16的整数倍地址(指物理地址)开始,称为段边界。
它使得段间留有1到15个字节的间隙,这也是一种缺省方式。
b.BYTE方式:
规定段可以从任何地址开始,它使得段间不留有任何间隙。
c.WORD方式:
规定段只能从偶地址开始,称为字边界,它使得段间可能留有一个字节的间隙。
d.PAGE方式:
规定段从256的整数倍地址开始,称为页边界,它使得段间可能留有1到255个字节的间隙。
④分类名
指令对分类名相同的各模块中的所有段如何处理,LINK程序把各模块中分类名相同的所有段(段名未必相同)放在连续的存储区域内,但仍然是不同的段。
分类名相同的各个段在链接时,先出现的在前,后出现的在后。
注意点:
分类名应用单引号括起来。
⑤使用段定义语句的两点说明:
a.源程序模块中的某一段,可使用一对SEGMENT和ENDS编写完毕,也可以分为多对SEGMENT和ENDS编写,只要使用相同的段名即可。
但这些段的SEGMENT语句的组合方式、定义方式、分类名应相同,不得相互矛盾,或者以先出现SEGMENT语句为准,其余均省略不写。
b.LINK程序链接时,先处理组合方式,后处理定位方式,再处理分类名。
㈡ORG伪指令
格式:
ORG〈表达式〉
功能:
该指令后生成的目标代码,从表达式提供的偏移地址开始存放。
㈢GROUP伪指令
GROUP是群或组的意思,它用来把模块中若干不同名的段集合成一个组,并赋予一个组名,使它们都装在同一个逻辑段中(64K)。
组内各段名间的跳转都可以看作是段内跳转。
格式:
〈组名〉GROUP〈段名1,段名2,…〉
组名和段名一样,它表示该组的段地址。
㈣ASSUME
格式:
ASSUME〈段寄存器〉:
段名[,〈段寄存器〉:
〈段名〉]
功能:
告诉汇编哪个段寄存器将为哪个段名寻址。
说明:
段名是程序中定义过的任何段名或组名。
⒋过程定义伪指令
子程序:
具有一定功能的程序。
子程序通常以过程的形式编写。
格式:
〈过程名〉PROC[类型]
┆
RET
〈过程名〉ENDP
说明:
①过程名是为该过程取的名字,具有与语句标号相同的属性,即具有段地址、偏移地址和类型三类属性。
②地址属性是指过程中第一个语句的地址。
③类型属性由格式中的类型指明,可以有NEAR和FAR两种。
若类型缺省或为NEAR时,表示该过程只能为所在段的程序调用;若为FAR时,则可被跨段调用。
④RET为过程返回指令,不能省,否则过程将无法返回。
返回指令属于段内返回还是段间返回与过程类型有关。
⑤ 过程既允许嵌套定义,也允许嵌套调用。
注意:
子程序也可以不以过程形式出现,此时CALL指令中的操作数应该是子程序第一条可执行语句的语句标号。
⒌模块定义与通信伪指令
㈠NAME和END
格式:
[NAME〈模块名〉]
┆
END[标号]
说明:
模块名是为该模块起的名字,NAME语句可缺省,若缺省,该模块的源程序文件名就是模块名;
若该模块是主模块,END语句后跟一个标号,它表示该程序的启动地址,是该模块第一条指令性语句的标号;
若不是主模块,END语句后的标号应去除。
被连接的各模块中,只能有一个模块是主模块。
㈡PUBLIC
格式:
PUBLIC〈符号表〉
功能:
表示该模块中符号表中的符号常