汇编语言程序设计课件_第1页
汇编语言程序设计课件_第2页
汇编语言程序设计课件_第3页
汇编语言程序设计课件_第4页
汇编语言程序设计课件_第5页
已阅读5页,还剩82页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

汇编语言程序设计

4.1汇编语言与汇编程序

汇编语言就是用与操作功能含义相应的缩写英文字符组成的符号指令作为编程用的语言。因此说汇编语言实际上是一种符号语言,并且是一种面向机器的低级语言。因此,它具有程序编写、阅读、修改方面比较方便的特点,不易出错,而执行速度与机器语言相同。汇编语言程序转换成为计算机可运行的程序的过程如图4.1所示:图4.1汇编语言程序的汇编过程

汇编语言源程序的结构

一个完整的汇编语言源程序通常由若干个逻辑段(segment)组成,包括数据段、附加段、堆栈段和代码段,它们分别映射到存储器的物理段上。每个逻辑段以SEGMENT语句开始,以ENDS语句结束,整个源程序用END语句结尾。右边是一个完整的汇编语言源程序的结构。段名1SEGMENT┇段名1ENDS段名2SEGMENT┇段名2ENDS┅段名nSEGMENT┇段名nENDS

下面以一个具体的例子来说明一个完整的汇编语言程序的结构:【例4-1】编写8个字节无符号数求和的程序

DATASEGMENT;定义数据段

NUMDB12H,54H,78H,56H,36H,4AH,2CH,81H;定义数组NUM SUMDW?;定义存放结果区

DATAENDS ;数据段结束

CODESEGMENT ;定义代码段 ;下面的语句说明程序中定义的各段分别用哪个段存器寻址

ASSUMECS:CODE,DS:DATASTART:MOVAX,DATA MOVDS,AX ;将定义数据段的段地址送DS寄存器

LEABX,NUM ;将数组NUM的地址送BX寄存器

MOVCX,8 ;将数组中数据个数送CX寄存器

MOVAX,0 ;将AX寄存器内容清零

NEXT:ADDAL,[BX];(AL)内容+[BX]地址内容送AL中

ADCAH,0;将两个低字节相加产生进位加到AH中,即求和结果送AX寄存器INCBX;地址+1指向下一个单元DECCX;CX内容-1JNZNEXT;若CX内容不等于0,继续相加,若等于0结束循环MOVSUM,AX ;存和送SUM单元中

MOVAH,4CH ;返回DOS INT21H CODEENDS;代码段结束

ENDSTART;源程序结束汇编语言语句类型及格式

汇编语言源程序的语句可分为两大类:指令性语句和指示性语句。指令性语句

指令性语句就是由指令组成的由CPU执行的语句,指令性语句与机器指令一一对应,汇编程序会把它翻译成机器代码,也就是前面介绍的指令所形成的语句。每个语句可以由4项组成。格式如下:标号:指令助记符操作数;注释标号

标号是给指令所在地址取的名字,必须后跟冒号“:”。标号可以缺省,是可供选择的标识符。MASM中可使用的标识符必须遵循下列规则:(1)由英文字母(A~Z、a~z)、数字(0~9)或某些特殊的符号(@、—、?等)组成;(2)数字不能作为标识符的第一个符号;(3)不能用保留字(助记符、伪指令、寄存器名等)作标识符;(4)标识符有效长度为31个字符,若超过31个字符,则只有前面的31个字符有效。指令助记符

指令助记符是指令名称的代表称号,它是指令语句中的关键字,表示不同操作的指令,可以是指令助记符,也可以是伪指令,不能缺省。它表示本指令的操作类型,必要时可在指令助记符的前面加上一个或多个“前缀”(如LOCK、REP、REPE/REPZ、REPNE/REPNZ),从而实现某些附加操作,如果指令带有前缀,则指令前缀和指令助记符要用空格分开。

操作数

操作数是参加指令运算的数据,有些指令不需要操作数,可以缺省;有些指令有两个操作数,这时必须用逗号将两个操作数分开。操作数可以是常数、寄存器名、标号、变量,也可以是表达式。注释注释部分是可选项,允许缺省。如果带注释,则必须用分号开头。注释本身只用来对指令功能加以说明,给阅读程序者提供方便,汇编程序不对它作任何处理。例如:START:MOVAX,DATA;将立即数DATA送(AX)中指示性语句指示性语句又称为伪指令语句,它没有对应的机器指令,汇编程序无法将它们翻译成机器指令代码,只是在汇编过程中为汇编程序提供有关信息。格式如下:名字伪指令助记符操作数;注释

名字名字是给该指示性语句取的名称,它相当于指令性语句的标号,但是在名字后面不允许带冒号,这是两种语句形式上的最明显区别。当然,它和标号一样,名字也可以缺省,而且有些指示性语句根本不允许有名字。

伪指令助记符

伪指令助记符是由MASM规定的符号,也可称为汇编命令。操作数

指示性语句中包含的操作数的个数随不同伪指令而相差悬殊,有的伪指令不允许有操作数;有的伪指令允许带多个操作数,这时必须用逗号将各个操作数分开。操作数同样可以是常数和表达式。

例如:NUMDW1234H;定义被加数

数据项及表达式

操作数是汇编语言语句中一个重要的组成部分。它可以是寄存器数、存储器单元数或数据项。而数据项又可以是常量、标号、变量和表达式。

常量

在程序运行中,不发生变化的量称为常量。常量分为数值型常量和字符型常量两类。数值型常量又分为常数和符号常量2种。

数值型常量

常数80x86汇编语言允许以下4种常数:① 二进制常数:由若干个“0”、“1”组成,且以字母B结尾,如:00101100B。② 十进制常数:由若干个0~9的数字组成,且以字母D结尾或省略D,如:1234D、1234。十进制常数可以采用科学表示法(浮点数表示法),如:4.635E-2,E表示阶码。③ 八进制常数:由若干个0~7的数字组成,且以字母Q结尾,如255Q、377Q。④ 十六进制常数:由若干个数字0~9或字母A~F组成,以数字打头且以字母H结尾。如56H,0BA3FH等。十六进制常数的首字符为字母A~F时,需加前缀“0”。符号常量

对经常引用的常数,可以用等价语句EQU或等号语句“=”给它定义1个名字,然后在语句中可用这个名字来代表该常数。这个名字称作符号常量。例如:

COUNEQU90VALT=60字符型常量

用引号括起来的1个或多个字符称为字符型常量。引号中的字符的ASCII码值,即是该字符型常量的值。例如“B”的值是42H,而“BA”的值是4241H。因此字符型常量与整型常数可以相互通用。

变量

在程序运行中,会发生变化的量称为变量。在本质上,它是1个或1组连续的存储器单元的名字。变量的名字由字母开头,其长度不超过31个字符。变量可以使用数据定义伪指令DB、DW、DD、DQ和DT来定义。

例如:COUNTDB3;用DB定义字节变量COUNT,其初值为3BUFFDW11,52,23;定义一组连续的存储器单元,BUFF代表这些单元的起始地址

CHARDB‘XYZ’;定义字符串XYZ的ASCII码,CHAR代表这些单元的起始地址

变量具有段属性(SEG)、偏移属性(OFFSET)、类型属性(TYPE)3种属性。标号标号是可执行语句的符号地址,1个标号对应1条指令的地址。标号可以作为JMP指令和CALL指令的目的操作数。作为指令地址的符号表示,标号与变量类似具有段、偏移、类型3种属性。但有以下2点差异:(1)标号的段基址值存在代码段寄存器(CS)中。(2)标号的类型为NEAR和FAR,前者用于段内引用,后者用于段间引用。表达式

通常表达式分为数值表达式和地址表达式2种。各种常量与运算符连接成的式子,称为数值表达式。将常量、变量、标号、寄存器内容和运算符、操作符相组合成的有意义的式子,称为地址表达式。单个常量、变量、标号是表达式的最简形式。

80x86汇编有算术运算符、逻辑运算符、关系运算符取值运算符和属性运算符1)

算术运算符

包括+、-、*、/、MOD(取除法中的余数)、SHR(右移)、SHL(左移)。例如:

MOVBL,5+6;(BL)=11

算术运算符可以用于数值表达式和地址表达式中。在数值表达式中,其操作数为数值型数据,结果也是数值型数据。而在地址表达式中,存储器地址操作数进行操作时,有意义的运算符是加、减。2)逻辑运算符包括AND(与),OR(或),NOT(非)和XOR(异或)。逻辑运算是按位操作的,其操作数只能是数值型常量,结果也是数值型数据。例如:9999HXOR0F0F0H的结果为6969H

AND,OR,NOT,XOR既是运算符也是指令助记符。作为运算符使用时,它是在程序汇编时计算的。而作为指令助记符使用时,则是在指令执行时计算的。例如:ANDDX,35HAND0FEH

第一个AND是指令助记符,第二个AND是逻辑运算符。在汇编时,后一个“AND”将35H与0FEH相“与”,产生1个立即数34H,再作为指令的目的操作数与DX的内容相“与”,结果存在DX中。3)关系运算符

有EQ(=)、NE(≠)、LT(<)、LE(≤)、GT(>)、GE(≥)6个运算符。关系运算符连接的2个操作数,必须都是数值型数据或是在同一段内的存储器地址。而运算结果始终是1个数值型数据。若关系为假,则结果为0;若关系为真,则结果为0FFFFH。例如:MOVBX,PORTLT5

若PORT的值小于5,则汇编程序将把这条指令汇编为:MOVBX,0FFFFH,否则,汇编为MOVBX,0。4)取值运算符和属性运算符取值运算符可分析一个存储器数的属性,属性运算符可以规定存储器数的属性。主要介绍常用的两个取值运算符OFFSET和SEG,一个属性运算符PTR。(1)OFFSET

利用运算符OFFSET得到一个标号或变量的偏移地址。例如:MOVBX,OFFSETNUM;将变量NUM的偏移地址送BX

这条指令与下边的指令执行相同的功能

LEABX,NUM

(2)SEG

利用运算符SEG得到一个标号或变量的段地址。例如:MOVAX,SEGNUM;将变量NUM的段地址送AXMOVDS,AX;将(AX)的内容送DS段寄存器(3)PTR

属性运算符用来临时指定位于其后的存储器操作数的类型。例如:

CALLDWORDPTR[BX];临时改变存储器操作数属性为4个字节

MOVAL,BYTEPTR[SI];将SI指向的一个字节数送AL

如果一个变量已定义为字变量,利用PTR运算符可以临时改变它的属性。

4) 其他运算符(1)方括号[]

指令中用方括号表示存储器操作数,方括号里的内容表示操作数的偏移地址。例如:MOVAX,[BX];将(BX)和(BX+1)指向的两个存储单元的内容送AX(2)段超越运算符“:”运算符“:”(冒号)跟在某个段寄存器名(DS、ES、SS、CS)之后表示段超越,用来指定一个存储器操作数的段属性,而不管其原来隐含的段是什么。例如:MOVAX,ES:[DI];将ES段中由DI指向的字操作数送AX数据定义伪指令数据定义伪指令用来定义一个变量的类型,给存储器赋初值,或给变量分配存储空间。数据定义伪指令的一般格式为:[变量名]伪操作操作数[,操作数,...][;注释]常用的数据定义伪操作有以下5种:(1)DB(definebyte)伪操作。用来定义字节。它定义的变量中的每个操作数占一个字节(0~0FFH)。DB伪操作也常常用来定义字符串。(2)DW(defineword)伪操作:用来定义字。DW伪操作后面的每个操作数都占用2个字节。在内存中存放时,低字节在前,高字节在后。4.2伪指令(3)DD(delinedoubleword):用来定义双字。DD伪操作后面的每个操作数都占用4个字节。在内存中存放时,低字节在前,高字节在后。(4)DQ(definequadword):定义四字(QWORD,8个字节).在内存中存放时,低字节在前,高字节在后。(5)DT(definetenbytes):定义十字节(TBYTE)。DT伪操作后面的每个操作数都为10个字节的压缩BCD数。这些伪操作可以把其后跟着的数据存入指定的存储单元,形成初始化数据;或者只分配存储空间并不存入确定的数值,形成未初始化数据。

数据定义伪操作后面的操作数可以是常数、表达式或字符串。

一个数据定义伪操作可以定义多个数据元素,但每个数据元素的值不能超过由伪操作所定义的数据类型限定范围。例如,DB伪操作定义数据的类型为字节,则所定义的数据元素的范围为O~255(无符号数)或-128~+127(有符号数)。字符和字符串都必须放在单引号中。超过两个字符的字符串只能用于DB伪指令。如图4.2所示。

数据定义伪操作的操作数除以上几种外,还可以是问号“?”,此时仅给变量保留相应的存储单元,而不赋予变量确定的值.当同样的操作数重复多次时,可用重复操作符“DUP”表示。DUP的一般格式为[变量名]数据定义伪操作nDUP(初值[,初值...])。例如:

DAT1DB10DUP(?);为变量DAT1分配10个字节的空间,初值为任意值

DAT2DW?;为变量DAT2分配2个字节的空间,初值为任意值

DAT3DB5,2DUP(1,2DUP(4),7),35

其变量存储分配示意图如图4.3所示:图4.3变量存储分配示意图符号定义伪指令在汇编语言程序中,有时多次出现同一个表达式,为简单起见,常将该表达式赋予一个名字,以后凡是用到该表达式的地方,就用这个名字来代替。以便修改该表达式的值。符号定义伪指令EQU就是用于给一个表达式赋予一个名字。其一般格式为:名字EQU表达式格式中的表达式可以是一个常数、符号、数值表达式、地址表达式甚至可以是指令助记符。例如:CR EQU 0DH ;常量LEQU 5 ;常量L1 EQU L+4 L2 EQU L1*2+10 ;数值表达式ADDREQU[BX+SI+3] ;地址助记符GOTOEQU JMP ;指令助记符TABLEDB23H,35H;定义变量TABLEL4EQUTABLE;定义符号L4代表变量TABLE…MOVAL,CR ;(AL)=0DHCMPAL,L1 ;AL的内容与L1(=9)进行比较GOTOWORDPTRADDR;转到以字单元[BX+SI+3]的内容为地址的程序段执行利用EQU伪指令,可以用一个名字代表一个数值,或用一个较简短的名字代表一个较长的名字等。但不允许用EQU对同一个符号重复定义。若希望对一个符号重复定义,可用“=”伪指令。例如:FACTOR=10H ;FACTOR代表了数值10H

…FACTOR=25H ;从现在开始,FACTOR代表了数值25H段定义伪指令

汇编语言源程序是用分段的方法来组织程序、数据和变量的。一个汇编语言源程序由若干个逻辑段组成。段定义伪指令用来定义汇编语言源程序中的逻辑段。其格式为:段名SEGMENT[定位类型][组合类型][‘类别’]

段名ENDS

源程序中的每个逻辑段由SEGMENT语句开始,到ENDS语句结束。二者总是成对出现,缺一不可。1.定位类型(align)

定位类型告诉汇编程序如何确定逻辑段的地址边界,定位类型有4种。(1)PARA(paragraph)

说明逻辑段从一个节的边界开始。16个字节称为一个节,所以段的起始地址应能被16整除,也就是段起始物理地址应为****0H。在缺省情况下,定位类型默认为PARA。(2)BYTE

说明逻辑段从字节边界开始,即可以从任何地址开始。此时本段的起始地址紧接在前一个段的后面。(3)WORD

说明逻辑段从字边界开始。即本段的起始地址必须是偶数。(4)PAGE

说明逻辑段从页边界开始。256B(字节)称为一页,故本段的起始物理地址应为***00H。2.组合类型(combine)

组合类型主要用在具有多个模块的程序中,一个逻辑段装入存储器时与其他段如何进行组合。组合类型共有以下6种:(1)NONE

表示本段与其他逻辑段不组合。

(2)PUBLICPUBLIC表示,对于不同程序模块中用PUBLIC说明的具有相同段名的逻辑段,汇编时将它们组合在一起,构成一个大的逻辑段。(3)STACK

组合类型为STACK时,其含义与PUBLIC基本一样,但仅限于作为堆栈的逻辑段使用。

(4)COMMON

表示对于不同程序模块中用COMMON说明的同名逻辑段,连接时从同一个地址开始装入,即各个逻辑段重叠在一起。(5)MEMORY

表示当几个逻辑段连接时,本逻辑段定位在地址最高的地方。如果被连接的逻辑段中有多个段的组合类型都是MEMORY,则汇编程序只将首先遇到的段作为MEMORY段,而其余的段均当做COMMON段处理。(6)AT表达式

这种组合类型表示本逻辑段根据表达式求值的结果定位段地址。例如AT8000H,表示本段的段地址为8000H,即本段的起始物理地址为8000H。3.类别(class)

类别是用单引号括起来的字符串。如代码段(‘CODE’)、堆栈段(‘STACK’)等。设置类别的作用是在当几个程序模块进行连接时,将具有相同类别名的逻辑段装入连续的内存区内。类别名相同的逻辑段,按出现的先后顺序排列。没有类别名的逻辑段,与其他无类别名的逻辑段一起连续装入内存。上述3个可选项主要用于多个程序模块的连接。若程序只有一个模块,即只包括代码段、数据段、附加段和堆栈段时,除堆栈段建议用组合类型STACK说明外,其他段的组合类型各类别均可省略。定位类型一般采用默认值PARA。

【例4-2】将两个模块中的同名段进行组合。模块1:STACKSEGMENTSTACKDB100DUP(0)STACKENDSDATASEGMENTCOMMONAREA1DB1024DUP(0)DATAENDSCODESEGMENTPUBLIC…CODEENDS模块2:STACK SEGMENTSTACKDB50DUP(0)STACK ENDSDATA SEGMENTCOMMONAREA1 DB8192DUP(0)DATA ENDSCODE SEGMENT PUBLIC…CODE ENDSEND

汇编连接后,存储器中的分配情况如图4.4所示。这里,两个模块中的代码段的名字相同,组合类型为PUBLIC,故将它们连接成一个大的代码段;数据段的名字也相同,用COMMON说明,则将它们重叠,因为模块2的数据段比模块1的长,所以数段长度为8192B;同理,堆栈段组合成为一个大的堆栈区,共150B。图4.4内存分配示意图设定段寄存器伪指令

该伪指令的一般格式为:

ASSUME段寄存器名:段名[,段寄存器名:段名[,…]]格式中的段寄存器名可以是CS、DS、ES或SS。8088的存储器采用分段结构,每个逻辑段最大不得超过64KB,且可有多个逻辑段。但同时最多只能允许4个逻辑段有效,即一个代码段,一个数据段,一个附加段和一个堆栈段。ASSUME伪指令用来告诉汇编程序用SEGMENT伪操作定义过的段的段地址将要存放在哪个段寄存器中(但代码段寄存器CS不要求用户赋初值)。这样,当汇编程序汇编一个逻辑段时,即可利用相应的段寄存器寻址该逻辑段中的指令或数据。

在一个源程序中,ASSUME伪指令要放在可执行程序开始位置的前面,请看下例。【例4-3】DATASEGMENTTABDB10DUP(?)DATAENDSEDATASEGMENTSUMDW?EDATAENDSSTACKSEGMENT DB100DUP(?)STACKENDSCODESEGMENTASSUMECS:CODE,DS:DATA,ES:EDATA,

SS:STACKSTART:MOV AX,DATAMOV DS,AXMOV AX,EDATAMOVES,AXMOVAX,STACKMOVSS,AX

…CODEENDSENDSTART汇编时,系统自动将代码段的段地址装入段寄存器CS,所以代码段不需要在程序中初始化。但若定义了数据段、附加段和堆栈段,就需要程序员用指令把DS、ES、SS初始化。过程定义伪指令程序设计中,通常将具有某种功能的程序块看做一个过程(即子程序),它可以被别的程序调用(CALL),或用JMP指令跳转到该处执行。过程定义伪指令的一般格式为:过程名PROC[NEAR/FAR]

…RET

过程名ENDP过程以PROC开始,之间的部分是过程体,以ENDP结束。过程名是子程序的符号地址。过程体内至少要有一条返回指令RET,以便在程序调用结束后能返回原地址。过程的类型有NEAR和FAR。【例4-4】编写一个除10的子程序。

DIV10PROC;定义一个近过程

PUSHDX;保护DX原来的内容

PUSHBX;保护BX原来的内容

MOVDX,0;除法要求在32位数除以16位数中,被除数送给DXAX中

MOVBX,10;

DIVBX;DXAX/BX->结果商在AX中,余数在DX POPBX;恢复BX原来的内容

POPDX;恢复BX原来的内容

RET;过程返回

DIV10ENDP;过程结束宏命令伪指令在汇在编语言源程序中,如果需要多次使用同一个程序段,可以将这个程序段定义为一个宏指令,然后每次需要时,即用宏指令名来代替(称为宏调用)。宏命令伪指令的格式为:宏命令名MACRO[形式参数,…](宏定义体)ENDM宏命令名与过程名类似,是宏定义的标志,它位于宏操作符MACRO之前,但宏定义结束符前不加宏命令名。对宏命令名的规定与对标号的规定一样。宏定义中的形式参数是任选的,可有可无。如有多个参数时,各参数间要用逗号隔开。模块定义与连接伪指令在汇编语言程序较大时,通常将其划分为几个独立的源程序(或称模块),然后再分别汇编生成各自的目标程序,最后将它们连接成为一个完整的可执行程序。在每一个模块的开始,常用伪指令NAME或TITLE为该模块定义一个名字,而在模块的结尾处,要加结束伪指令END,以使汇编程序结束汇编。下边分别来看一下这3条伪指令的格式及操作。(1)NAME伪指令指令格式:NAME模块名

NAME伪指令用于给汇编后得到的目标程序一个名字。NAME伪指令的前面不允许再加标号,例如下面的语句是非法的:

BEGIN:NAME模块名(2) TITLE伪指令

TITLE伪指令为程序清单每一页指定打印的标题。其格式为:TITLE标题名标题名最多允许60个字符。如果程序中没有NAME伪操作,则汇编程序将TITLE伪指令后面的“标题名”中的前6个字符作为模块名。如果源程序中既没有使用NAME,也没有使用TITLE伪操作,则汇编程序将源程序的文件名作为目标程序的模块名。(3) END伪指令

END伪指令表示源程序到此结束,指示汇编程序停止汇编。其格式为:END[标号]【例4-6】将数据段TABLE开始的10个无符号字节数,转存到堆栈段NUM开始的单元中。

DATASEGMENT ;定义数据段

TABLEDB12,23,34,45,56,67H,78H,89H,9AH,OFDH;定义10个数

DATAENDSSTACKSEGMENT ;定义堆栈段

NUMDB10 DUP(?)STACKENDSCODESEGMENT ;定义代码段

ASSUMECS:CODE,DS:DATA,ES:DATA,SS:STACK START:MOV AX,DATA MOVDS,AX ;初始化DS MOVES,AX ;初始化ES

MOVAX,STACK MOVSS,AX ;初始化SS LEABX,TABLE;BX指向TABLELEABP,NUM;BP指向NUM MOVCX,10 ;循环计数器

NEXT: MOVAL,[BX];从数据段中取数据送AL MOV[BP],AL;将AL中数据存到堆栈段中

INCBX ;指向下一个数

INCBP LOOPNEXT ;若未完,继续循环

MOVAH,4CHINT21H ;结束返回DOS CODE ENDS ;代码段结束

ENDSTART ;汇编结束,起始运行地址为STARTDOS是计算机的操作系统,负责管理系统的所有资源,协调微机的操作,其中包括大量的可供用户调用的服务程序.DOS功能调用不依赖于具体的硬件系统。所有的DOS系统功能调用都是利用软中断指令INT21H来实现的.INT21H是一个具有90多个子功能的中断服务程序,这些子功能大致可以分为四个方面:设备管理,目录管理、文件管理和其他。为了便于用户使用这些子功能,INT21H对每产个子功能都进行了编号即称为功能号。DOS系统功能调用的使用方法如下:

AH←功能号;在其它寄存器中放入该功能所要求的入口参数;执行INT21H指令;分析出口参数。4.3DOS功能调用下面介绍INT21H的几个最常用的功能

:1.键盘输入从键盘上输入字符时,实际得到的是字符的ASCII(控制键除外)。如在键盘上按下数字键“3”,则得到一个3字符的ASCII码33H。INT21H提供了若干支持键盘输入的子功能,本节只介绍单个字符输入和字符串输入两种键盘输入功能。(1)单字符输入功能号1、7和8都具有键盘单字符输入功能,得到的字符ASCII码存放在累加器AL中。其中7号和8号功能无回显,1号功能有回显(回显是指键盘输入的内容同时也显示在显示器上)。(2)输入字符串功能号OAH具有键盘输入字符串功能。此功能要求用户在数据段建立一个键盘入缓冲区来存放输入的字符串;缓冲区结构如图4.5所示。第一个字节为用户定义的缓冲区长度。缓冲区第二个字节为实际键入的字符数(不包括回车符),从第三个字节开始存放键入的字符。显然,缓冲区的总长度等于缓冲区长度加2。图4.5用户定义的键入字符串的缓冲区

2.显示器(CRT)输出

功能号2具有单个字符显示功能,此功能要求用户将要显示的字符的ASCII放在DL中。功能号9具有多个字符显示功能,此功能要求用户将存有要显示的字符串缓冲区的首地址放在DX中,并且被显示的字符串必须以“$”字符作为结束符,否则会引起屏幕混乱;显示时如果希望光标能自动转换,则应在字符串结束前加上回车及换行的ASCII码0DH和0AH。【例4-9】从键盘输入大写字符并小写显示输出CODE SEGMENTASSUMECS:CODE

START:MOVAH,1INT21H;从键盘输入字符->AL寄存器(得到字符的ASCII码)CMPAL,0DH;判断是否为回车键?JZEXIT;为回车键->退出

CMPAL,’A’;否,再判断是否为A键?

JBSTART;若小于A的ASCII码重新输入

CMPAL,’Z’;否,再判断是否为Z键?

JASTART;若大于Z的ASCII码重新输入

SUBAL,20H;在A~Z之间,AL-20H为小写a~zMOVDL,AL;将要显示字符的ASCII码->DL寄存器

MOVAH,2INT21H;大写字符变小写显示输出

JMPSTARTEXIT:MOVAH,4CH;返回DOS INT21HCODEENDS ENDSTART程序设计概述

1.程序质量的评价标准

一个高质量的程序不仅要满足设计要求,实现预先设定的功能,还应使程序具备可理解性、可维护性和高效率等性能。衡量一个程序的质量通常有以下几个标准:(1) 程序的正确性和完整性;(2) 程序的易读性;(3) 程序的执行时间和效率;(4) 程序所占内存的大小。4.4汇编语言程序设计基础2.程序设计的一般步骤

依照软件工程理论,汇编语言的程序设计与高级语言的程序设计一样可分为以下几个步骤:(1) 分析问题,抽象出描述问题的数学模型;(2) 确定求解各模块的数据结构及算法;(3) 绘制流程图或结构图;(4) 分配存储空间及工作单元(包括寄存器);(5) 编写程序并保存,形成源程序文件(.ASM)。(6) 通过汇编生成目标代码文件(.OBJ),同时完成静态的语法检查。(7) 通过链接生成可执行文件(.EXE)。(8) 程序测试。

3.源程序的基本结构程序基本结构形式有3种:顺序结构、分支结构、循环结构。顺序结构程序是直线运动的,既无分支,也无循环或转移,是最简单的一种程序结构。分支结构程序是根据不同的情况做出判断、选择,以执行不同的程序。分支程序可以是双分支,也可以是多分支。对于需要反复做同样工作的情况则用循环程序实现。循环结构可以缩短程序长度且便于维护,但循环程序中需要有循环准备、结束判断等指令,故执行速度要比顺序结构的程序略慢一些。

顺序程序顺序程序是最常见、最基本的程序结构。CPU按照指令的排列顺序逐条执行。【例4-11】编写S=45H/07H+67H的程序。分析:运算中要用到除法指令,要求被除数必须送给AX寄存器。程序的流程图如图4.6所示。其程序编写如下:

DATASEGMENTNUMDB45H,07H,67H ;定义源操作数

RESULTDB? ;定义结果存放单元

DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATASTART:MOVAX,DATAMOVDS,AX;DS指向DATA段

LEASI,NUM;NUM的偏移地址送SI MOVAL,[SI] ;(AL)←45HMOVAH,0 MOVBL,[SI+1];(BL)←07H DIVBL ;45H/07H商在AL中

MOVCL,[SI+2];(CL)←67H ADDAL,BL;(AL)←45H/07H+67H MOVRESULT,AL;结果送RESULT单元

MOVAH,4CH ;返回DOS INT21HCODEENDS ENDSTART图4.6顺序程序流程图分支程序设计

图4.7分支程序基本结构【例4-13】编写程序,统计数据区中以字节变量BUFFER为首地址的10个单元中零的个数。分析:这是一个有两个分支的分支程序,首先判断每个单元数据是否为零,若为零计数加1;其次判断数据个数是否到10,否则就继续,是退出该程序。

DATA SEGMENT BUFFERDB-2,4,9,0,-6,0,15,0,-78,35 COUNTDB0 ;定义统计0个数单元

DATA ENDS CODE SEGMENT ASSUMECS:CODE,DS:DATA START:MOVAX,DATAMOVDS,AX ;初始化数据段

MOVCX,10;置单元长度

LEABX,BUFFERAGAIN:MOVAL,[BX] ;取数据

CMPAL,0;判断是否=0?

JNZNEXTINCBYTEPTRCOUNT;0个数+1NEXT:INCBX;地址+1DECCX;判断数据取完否?

JNZAGAIN;否,继续

MOVAH,4CH INT21HCODE ENDS ENDSTART循环程序在解决实际问题过程中,往往需要重复地做某些工作,因此在编程序时可采用循环结构结构实现。而在循环结构结构程序中,某些指令重复执行多次,可使程序长度大为缩短。循环程序在结构上包括循环初始化、循环体和循环控制三个部分。在形式上有两种,一是先执行循环体,再判断条件看是否继续循环(如图4.8(a)所示);二是先检查条件是否满足,满足则执行循环体,否则就退出(如图4.8(b)所示)。

图4.8循环程序的基本结构【例4-15】把从NUM单元开始的10个16位有符号数按从小到大的顺序排列.分析:(1)这是一个排序问题。由于是有符号数的比较,可以直接用比较指令CMP和条件转移指令JL来实现;

(2)这是一个双重循环程序.先使第一个数与下一个数比较,若小于则使其位置保持不变,大于则将小数放低地址,大放高地址(即两数交换位置);

(3)以上完成了一次排序工作。再通过第二重的9次循环,即可实现对10个有符号数的大小排序。程序:DATASEGMENTNUMDW 23,-45,1000,-500,8,100,0,-300,3000,-4000,90DATAENDSCODESEGMENT ASSUMECS:CODE,DS:DATASTART:MOVAX,DATA MOVDS,AXLEABX,NUM;BX指向要排序的数的首址

MOVCX,9;外循环只需9次循环从此开始

NEXT1:PUSHCX;CX也为内循环计数,并且逐次减1MOVSI,BX ;SI指向当前要比较的数 NEXT2:MOVAX,[SI] ;取第一个数Ni ADDSI,2 ;指向下一个数Nj CMPAX,[SI] ;Ni<Nj?

JLNEXT3 ;若小于则不交换

XCHGAX,[SI] ;否则交换Ni和Nj MOV[SI-2],AXNEXT3:LOOPNEXT2 ;内循环结束?若未结束则继续

POP CX LOOPNEXT1;外循环结束?若未结束则继续

MOVAH,4CH ;返回DOS INT21HCODE ENDS ENDSTART子程序设计在使用子程序时应注意以下2点:(1)参数传递。在子程序调用时,经常需要将一些参数传给子程序,而子程序也常常需要在运行后将结果和状态等信息返回给调用程序。这种程序和调用程序之间的信息传送,就称为参数传递。参数的传递可通过寄存器、变量、地址表、堆栈等方式进行。(2)寄存器保护。由于子程序要用到的一些寄存器,在调用程序中也要用到,为防止破坏调用程序中寄存器的内容,需在子程序开始处将所要用到的寄存器内容压入堆栈保存。

【例4-16】从一个字符串中删去一个字符分析:利用堆栈实现参数的传递。即在调用程序中将参数或参数地址保存在堆栈中,在子程序里再从堆栈中取走,实现参数的传送。示例程序如下:

DATA SEGMENT STRING DB ‘Exxperience’ LENGTH DW$-STRING KEY DB ‘x’;要删的字符

DATA ENDS CODE SEGMENT ASSUMECS:CODE,DS:DATA MAIN PROC FAR START:MOVAX,DATAMOVDS,AX LEA BX,STRINGLEACX,LENGTH PUSHBX PUSHCX;将STRING和LENGTH的地址压栈

MOVAL,KEY CALL DELCHAR;调用删除一个字符的子程序

MOV AH,4CH INT21HMAIN ENDPDELCHAR PROC PUSH BP ;保存BP内容

MOV BP,SP ;将BP指向当前栈顶

PUSH SI PUSH DI PUSH CXCLD

MOV SI,[BP+4] ;得到LENGTH地址

MOV CX,[SI] ;取串长度

MOV DI,[BP+6] ;得到STRING地址

REPNE SCASB ;查找要删除的字符

JNE DONE ;若没有找到则退出

MOV SI,[BP+4] DEC WORDPTR[SI] ;串长度减1 MOV SI,DI DEC DI REP MOVSB;被删除字符是否依次向前移位DONE:POPCX ;恢复积存器内容

POP DI POP SI POP BP RET 4 ;调整栈指针并返回DELCHARENDPCODE ENDS END START程序执行中堆栈最满时的状态如图4.10所示。图4.10堆栈最满时的状态

【例4-18】键盘输入4位16进制数,并转换成二进制,转换结果放MBIN中。分析:从键盘上输入的数都是以ASCII码的形式存在。对十六进制数来讲,0~9的ASCII码分别为30H~39H。所以,对这10个数的转换,只需减去30H,就可得到对应的二进制值;而A~F的ASCII码分别为41H~46H,故要减去37H,而a~f的ASCII码分别为61H~66H,故要减去57H。程序: DATASEGMENT MBINDW?

DATAENDS CODESEGMENTASSUMECS:CODE,DS:DATA BEGIN:MOVAX,DATA MOVDS,AX MOVBX,0 MOVCX,4;循环次数送CX4.5常见程序设计举例NEXT1:MOVAH,1INT21HCMPAL,‘0’JLNEXT1;若(AL)<30H重新输入

CMPAL,‘9’ JGNEXT2;若(AL)≥39H则转NEXT2 SUBAL,30H;若为数字0~9,则转为二进制数

JMPNEXT5NEXT2:CMPAL,’A’JLNEXT1;若(AL)<’A’重新输入

CMPAL,’F’ JGNEXT3;若(AL)>’F’,则转NEXT3 SUBAL,37H;若为数字A~F,则转换为对应二进制数

JMPNEXT5NEXT3:CMPAL,’a’ JLNEXT1;若(AL)<’a’重新输入

CMPAL,’f’ JGNEXT1;若(AL)>’f’,重新输入

SUBAL,57H;若为数字a~f,则转换为对应二进制数NEXT5:MOVAH,0;一个数的转换结果送(BX) XCHGAX,BXMOVDX,16MULDXADDBX,AX LOOPNEXT1;未完则转NEXT1 MOVMBIN,BX;最后结果送MBIN MOVAH,4CH;返回DOS INT21HCODEENDS ENDBEGIN【例4-19】把存放在BUFF中的16位二进制数转换为ASCII码表示的等值数字字符串.例如,FFFFH应转换成等值的数字字符串‘65535分析:将一个二进制数转换为对应的ASCII码,可采用除10取余的方法,即任何一个用十六进制表示的二进制数,其除以10后的余数即是它的最低位,且一定在0~9之间。如:12345除以10,余数为5.用得到的余数加上30H,就得到了最低位对应ASCII码。程序:DATASEGMENT BUFFDW4FB6H;要转换的数

ASCCDB5DUP(20H),0DH,0AH,24H;ASCII码结果存放单元

DATAENDS CODESEGMENT ASSUMECS:CODE,DS:DATA START:MOVAX,DATA MOVDS,AX MOVCX,5;最多不超过5位十进制数(65535) LEADI,ASCC+4;DI指向结果存放单元

XORDX,DX MOVAX,BUFF;取要转换的二进制数

MOVBX,0AH;基数10AGAIN:DIVBX;用除10取余的方法转换

ADDDL,30H;十进制数转换为ASCII码

MOV[DI],DL;保存当前位的结果

DECDI;指向下一个位保存单元

ANDAX,AX;商为0?(转换结果?) JZSTO;若结束,退出

MOVDX,0 LOOPAGAIN;否则循环继续

STO:LEADX,ASCC;显示转换结果

MOVAH,9INT21H MOVAH,4CH INT21H;返回DOSCODEENDSENDSTART【例4-20】

两个多字节二进制数求和程序。分析:由于8088/8086CPU的内部寄存器均为16位。所以,在进行两个多字节数的求和运算时,一次只能完成一个字节或一个字的相加。低位字节(或字)相加的和可能会产生进位,那么在高位字节(或字)相加时则必须考虑该进位,否则就会使结果出错。因此,在多字节数求和运算中,要使用ADC指令。示例程序如下: DATASEGMENTBUFF1DW4FB6H,7C34H,561FH;数1BUFF2DW1324H,5768H,0FD9AH;数2 SUMDW3DUP(?);和 CONTDB3;数的字长为3 DATAENDS; CODESEGMENT ASSUMECS:CODE,DS:DATASTART:MOVAX,DATAMOVDS,AX MOVSI,OFFSETBUFF1+4;SI指向数1 MOVDI,OFFSETBUFF2+4;DI指向数2 MOVBX,OFFSETSUM+4;BX指向和单元

MOVCL,CONT;共3个字,要做3次加法

MOVCH,0 CLC;CF←0GOON:MOVAX,[SI];取数1的一个字

ADCAX,[DI];加上数2的相应字 SUBSI,2;修改指针

SUBDI,2 MOV[BX],A

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论