第三章 汇编语言程序设计教材_第1页
第三章 汇编语言程序设计教材_第2页
第三章 汇编语言程序设计教材_第3页
第三章 汇编语言程序设计教材_第4页
第三章 汇编语言程序设计教材_第5页
已阅读5页,还剩145页未读 继续免费阅读

下载本文档

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

文档简介

第3章

汇编语言程序设计主要内容:汇编语言源程序的结构汇编语言语句格式伪指令功能调用汇编语言程序设计13.1 汇编语言概述

1、机器语言——二进制数形式的指令和数据。

B064是什么意思?这就是机器语言。既不直观,又不易理解和记忆.

2、汇编语言MOVAL,64H

;很容易记忆理解,这就是助记符。

助记符——用便于记忆的英语单词表示的指令操作码。它反映了指令的功能和主要特征,便于人们理解和记忆。

指令除了操作码以外,还有一个操作数问题。操作数可能放在存储器中,这就涉及操作数的地址。程序中遇到转移指令或调用指令,也需要知道转移地址,若采用具体地址就很不方便,一旦有错,改动也很麻烦。于是人们采用标号或符号来代替地址。2

LP1:movax,VAR…loopLP1

汇编语言——指令助记符,符号地址,标号,伪指令等语言元素的集合以及这些元素使用的规则。用汇编语言编写的程序叫汇编语言源程序。汇编源程序需翻译成机器语言,变成可执行文件,机器才能执行,这个翻译过程叫汇编。——高级语言中称该过程为“解释”或“编译”。执行翻译的程序称为“汇编程序”。源程序的编译程序汇编程序汇编语言源程序机器语言目标程序3汇编语言程序设计与执行过程输入汇编语言源程序源文件.ASM汇编(编译)目标文件.OBJ链接可执行文件.EXE调试最终程序小汇编:ASM宏汇编:MASM3、高级语言:通用性强。例:MATLAB、C、Pascal43.2汇编语言源程序的格式

汇编语言源程序通常由一个或几个程序模块组成,每个模块一般由三个逻辑段组成:

数据段——存放数据、变量DATASEGMENTDATAENDS堆栈段——堆栈区域STACKSEGMENTSTACKENDS

代码段——存放程序指令CODESEGMENT

CODEENDS3.2.1分段结构5一个基本的汇编语言程序框架如下:

stack

SEGMENTPARA‘stack‘DB100DUP(‘stack’)

stackENDS

dataSEGMENT

<数据、变量在此定义>

dataENDS

codeSEGMENT

ASSUMECS:code,DS:data,ES:data

start:MOVAX,dataMOVDS,AXMOVES,AX

<此处加入你自己的程序段>MOVAH,4CH

INT21H

code

ENDSEND

start

堆栈段数据段代码段6例:将两个五字节的16进制数相加DATASEGMENT;定义数据段DATA1DB0F8H,60H,0ACH,74H,3BH;变量一,字节DATA2DB0C1H,36H,93H,0D5H,20H;变量二,字节DATAENDS;数据段结束CODESEGMENT;定义代码段

ASSUMECS:CODE,DS:DATASTART:MOVAX,DATAMOVDS,AX;初始化DS

MOVCX,5;置循环次数送CXMOVSI,0;(SI)=0CLC;(CF)=07LOOPER:MOVAL,DATA2[SI];取一个字节加数ADCDATA1[SI],AL;与被加数相加,带进位加法INCSI;SI加1DECCX;CX减1JNZLOOPER;若(CX)不等于0,转LOOPER

MOVAH,4CHINT21H;返回DOSCODEENDS;代码段结束ENDSTART;源程序结束注:MOVAH,4CHINT21H;DOS功能调用,结束正在运行的程序,返回DOS83.2.2汇编语言语句的类型和组成汇编语言的语句有两种:指令性语句——由8086指令助记符构成的语句指令性语句的格式为:

标号:

指令助记符

目的操作数,源操作数

;注释注:各部分之间至少要用一个空格作为分隔符。指令性语句由CPU执行,每一条指令性语句都有一条机器码指令与其对应指令性语句汇编时生成机器码;例:LOOPER:MOVAL,DATA[SI]9汇编语言的语句有两种:指示性语句——由伪指令构成的语句指示性语句的格式为:

名字

伪指令

操作数1,操作数2,…,操作数n

;注释注:各部分之间至少要用一个空格作为分隔符。指示性语句由汇编程序执行。它指出汇编程序应如何对源程序进行汇编,如何定义变量、分配存储单元以及指示程序开始和结束等。指示性语句无机器码指令与其相对应。

指示性语句汇编时不生成机器码。例:DATADB0FBH,60H10标号有三个属性:

段地址:即标号所在段的段地址;程序中引用一个标号,该标号的段地址应在CS中。

偏移量:标号所代表存储单元的段内偏移地址;16位的无符号数

类型:NEAR或FAR:

NEAR—表示标号所在语句与转移指令/调用指令在同一码段内,跳转时只需改变IP即可。

FAR—标号所在语句与转移指令/调用指令不在同一代码段内。

若没有对类型进行说明,默认为NEAR。标号通常作为转移指令或CALL指令的转移地址。3.2.3名字11汇编语言的一个实例:hello.asm

dataSEGMENTHelloDB‘Hello,world!’,0DH,0AH,’$’dataENDSprogSEGMENT

ASSUME

CS:prog,DS:datastart:MOVAX,dataMOVDS,AX

LEADX,hello

;取字符串首地址

MOVAH,9INT21H ;显示字符串MOVAH,4CHINT21H ;退回DOSprogENDSENDstart名字标号12

3.2.4助记符和伪操作助记符:8086、8088CPU指令的助记符,例如:MOV,ADD,MUL等伪操作指令:如DB、SEGMENT、ENDS、ASSUME、ENDS3.2.5操作数操作数包括常量、寄存器、标号、变量及表达式。1.常量二进制数,以B结尾。如01001101B。十进制数,如85。八进制数,以Q结尾。如174Q。13

十六进制数,以H结尾。第1个数字为A-F时,前面应加0,如0F160H。字符串:用引号括起来的1个或多个字符。如‘ERROR!’,’a’,汇编时被翻译成对应的ASCII码45H,52H,52H,4FH,52H,21H和61H。十进制科学计数法。如:8.75E-4十六进制实数。如:10A4E87R2、寄存器8位寄存器:AH、AL、BH、BL、CH、CL、DH、DL16位寄存器:AX、BX、CX、DX、SI、DI、BP、SP、DS、CS、SS、DS3、标号:代表一条指令的符号地址14

变量名——是存储单元(数据区)的符号地址或名字。变量也有三个属性:段地址—变量所在段的段地址偏移量—变量单元地址与段首地址之间的位移量。类型—有BYTE、WORD和DWORD三种。变量在程序中作为存储器操作数被引用。标号和变量名的使用规则组成:A-Z(不分大小写),0-9,?@._$不能以数字开头长度小于31个字符不能与保留字(指令助记符、伪指令、预定义符号等)重名不能重复定义例如:正确的:LP1,AGAIN,NEXT,_GO,OK_1

错误的:4M,LOOP,AAA,#HELP,+ONE4.变量即内存中的存储单元或数据区。155.表达式表达式是常数、寄存器、标号、变量与运算符的组合。有数字表达式和地址表达式两种。汇编时按优先规则对表达式进行计算,计算出具体的数值或地址。运行时不能改变。表达式中的运算符有6类:算术、逻辑、关系、取地址、属性、杂类。(1)算术运算符——+、-、*、/,MOD用于数字表达式,例:MOVAX,4*1024汇编后的形式为:

MOVAX,4096用于地址表达式,例:LEASI,TAB+3若TAB的偏移地址为1000H,则汇编后的形式为:LEASI,1003H16逻辑运算符只能用于数字表达式中。例:MOV CL,36HAND0FH

经汇编后:MOVCL,06H注意,不要把逻辑运算符与逻辑运算指令混淆:例:ANDAX,3FC0HAND0FF00H汇编后源操作数被翻译为:3F00H,所以上述指令与ANDAX,3F00H等价。(2)逻辑运算符——AND、OR、XOR、NOT关系运算的结果是一个逻辑值:真或假关系为真,结果为全1;

关系为假,结果为全0例:MOVBX,PORTGT300H若PORT的值大于300H,则汇编后为:MOVBX,0FFFFH否则汇编后为:

MOVBX,0(3)关系运算符——EQ、NE、LT、GT、LE、GE17OFFSET:取变量/标号的偏移地址注意,以下指令的异同:

MOVBX,OFFSETVARLEABX,VAROFFSET只能取静态的偏移地址;LEA指令即可取静态的偏移地址,也可取动态的偏移地址。SEG:取变量/标号的段地址。例:MOVAX,SEGDATAMOVDS,AX;取变量DATA的段地址(4)分析运算符和合成运算符18TYPE取变量的类型(1,2,4)VARDW?;字ARRAYDD10DUP(?);双字STRDB‘Thisisatest’;字节……MOVAX,TYPEVAR;(AX)=2MOVBX,TYPEARRAY;(BX)=4MOVCX,TYPESTR;(CX)=1LENGTH取所定义变量的长度(即变量中元素的个数)未使用重复操作符DUP,变量个数为1;否则如上例中的变量ARRAY的个数为10;19SIZE取所定义存储区的字节数(=TYPE*LENGTH)例:VARDW1,2,3,4,5则TYPEVAR=2,LENGTHVAR=5,SIZEVAR=10合成运算符PTR:用来指定地址操作数的类型格式:<类型>PTR<地址操作数> 类型∈{BYTE,WORD,DWORD,NEAR,FAR}BYTE、WORD、DWORD用于描述数据存储单元(变量)地址NEAR、FAR用于描述转移、调用的目的地址例:MOV BYTEPTR[DI],0;字节类型MOV WORDPTR[DI],0;字类型

MOV [DI],0B5H;类型不定20PTR也可用来进行强制类型转换例:STR1DW?;STR1定义为字类型 MOVAX,STR1;合法MOV AL,STR1;非法MOVAL,BYTEPTRSTR1;合法合成运算符THIS:用来指定存储器操作数的类型合成运算符SHORT:地址操作数21(5)其他运算符方括号[]:存储器地址MOVCL,[BX];间址寻址MOVAL,[SI+5];变址寻址段超越运算符:MOVAX,ES:[DI]HIGH、LOW:获取数值或地址表达式的高位和低位字节VAREQU0ABCDHMOVAH,HIGHVAR;(AH)=0ABHMOVAL,LOWVAR;(AL)=0CDH223.2.6注释注释——以分号开头,可放在指令后,也可单独一行。

注意注解的写法。要写指令(段)在程序中的作用,而不要写指令的操作。例如:以下为同一条指令写的注释1)MOVCX,100;传送100到CX2)MOVCX,100;循环计数器置初值显然,第二种写法要比第一种写法要好。

233.3伪操作命令数据定义伪指令符号定义伪指令段定义和段寄存器指定伪指令过程定义伪指令结束伪指令

由汇编程序执行的指令,它本身不被汇编成机器指令。常用的伪指令有:243.3.2数据定义伪指令

用于定义变量,即内存单元或数据区。数据定义伪指令的格式为:变量名数据定义伪指令操作数,操作数,…常用的数据定义伪指令有如下几种:

DB定义字节、DW定义字、DD定义双字、DQ定义八字节

DT定义十字节操作数可以是常数、变量或表达式例1:DATA_BDB10,5,10HDATA_WDW100H,-4DATA_DDD0FFFBH汇编后的内存分配情况如右图所示。05H10H00H01HFCHFFHFBHFFH00H00H0AHDATA_BDATA_WDATA_D10510H0100H-40FFFBH25例2:DATADB100,0FFH;存入64H,0FFHEXPRDB2*3+7;存入0DH=13DSTRDB‘WELCOME!’;存入8个字符

ABDB‘AB’;存入41H,42HBADW‘AB’;存入42H,41HABDDDD‘AB’;存入42H,41H,00,00OFFABDWAB;存入变量AB的偏移地址ADRSDWTABLE,TABLE+5,TABLE+10;存入3个偏移地址TOTALDDTABLE;先存入TABLE偏移地址,再存段地址NUMDQ0011223344556677H;存入77H,66H,55H,44H,33H,22H,11H,00H,DECMLDT1234567890H;存入90H,78H,56H,34H,12H,00,00,00,00,00HEXTABDB01,02,03,04,05,06,07,08,09DB0AH,0BH,0CH,0DH,0EH,0FH

26例3:操作数可以是字符串,例如STRDB ‘HELLO’汇编后的情况如图:注意下面两个定义的不同之处:DB ‘AB’;41H在低字节,42H在高字节DW‘AB’;42H在低字节,41H在高字节STR‘H’‘E’‘L’‘L’‘O’48H45H4CH4CH4FH操作数?用来保留存储空间,但不存入数据.例4:ABCDB0,1,2,3,4,’OK’,’$’RSVDW?,?,?,?,?,?,?,?27复制操作符DUP:重复的数据可以使用复制操作符DUP,如上面RSV亦可写成:RSVDW8DUP(?)若操作数中若使用$,则表示的是地址计数器的当前值。例:TABLEDB10DUP(?)BUFFERDWTABLE,$+3设TABLE的偏移地址为0080H,则汇编后如下图所示:BUFFER0080H80HTABLE...8FH00H0089H10Bytes283.3.3符号定义伪指令1、EQU格式:名字EQU表达式

把一个表达式用一个符号表示,以后凡出现该表达式的地方都可用这个符号表示。类似于C语言中的#define。用EQU定义的符号未清除前不能重新定义。清除EQU定义用PURGE伪指令。不占用存储空间,仅是给符号赋值CREQUODH;常数AEQUASCII_TABLE;变量STREQU64*1024;数值表达式ADREQUES:[BP+DI+5];地址表达式CBDEQUAAM;指令助记符292、=格式:名字=表达式区别:可对同一名字重复定义不占用存储空间,仅是给符号赋值例1:FIVEEQU5

COUNTEQUCX

TENEQU10

DIST=BYTEPTR[SI+BP]

GOTO=JMP…MOVAX,TENMOVCX,COUNTADDDIST,FIVE

DIST=WORDPTR[SI+BP+1]ADDDIST,AX

GOTOLABEL

定义引用30例2:COUNT=10MOVCX,COUNT;(CX)=10COUNT=COUNT-1MOVBX,COUNT;(BX)=9例3:COLUMNEQU80

ROWEQU25SCREENFUL

EQUCOLUMN*ROW3、LABEL格式:名字LABEL类型例:AREAWLABELWORD;AREAW类型为WORD313.3.4段定义伪操作1、SEGMENT/ENDS格式:

段名

SEGMENT[定位类型][组合方式][类别]

<汇编语言语句>段名

ENDS汇编语言程序是按段来组织程序和数据的。和存储器的物理段相对应,汇编语言程序中的段称为逻辑段。汇编连接后被映射到物理段中。SEGMENT语句后可以带有可选参数,用以规定逻辑段的其他一些属性。321)定位类型说明如何确定逻辑段的边界。有四种:PARA(Paragraph):逻辑段从一个节(16个字节)的边界开始。即段的起始地址应能被16整除,或这说段起始物理地址应为××××0H。——默认类型BYTE:

逻辑段从字节边界开始,即段可以从任何地址开始。WORD:

逻辑段从字边界开始。即段的起始地址必须是偶数。PAGE:

逻辑段从页边界开始。256字节称为一页,故段的起始物理地址应为×××00H。33

2)组合类型说明不同模块中同名段的组合方式。PUBLIC :所有此类型的同名段组合成一个逻辑段,公用一个段地址,运行时装入同一个物理段中。COMMON:所有此类型的同名段具有相同的起始地址(覆盖),共享相同的存储区域。AT<数值表达式>:按绝对地址定位,段地址就是表达式的值。STACK:专用于说明堆栈段,组合方式同PUBLIC34STACKSEGMENTSTACKDB100DUP(?)STACKENDSDATA1SEGMENTBYTESTRINGDB‘Thisisanexample!’DATA1ENDSDATA2SEGMENTWORDBUFFERDW40DUP(0)DATA2ENDS

35CODE1SEGMENTPAGE……CODE1ENDSCODE2SEGMENTPAGE……CODE2ENDS……START:MOVAX,STACK;MOVSS,AXCODE2ENDSENDSTART

36长度说明:STACK的长度为100*1=100D=64HDATA1的长度为19*1=19D=13HDATA2的长度为40*2=80D=50HCODE1的长度为13*1=13D=0DHCODE2的长度为52*1=52D=34H所占内存地址:STACK:00000H~00063H,占64H=100个字节,从×××00H开始DATA1:00064H~00076H,占13H=19个字节,从任何地址开始DATA2:00078H~000C7H,占50H=80个字节,以偶数地址开始CODE1:00100H~0010CH,占0DH=13个字节,从×××00H开始CODE2:00110H~00143H,占34H=52个字节,从×××00H开始

372、ASSUME伪指令在代码段中,还必须明确段和段寄存器的关系,这由ASSUME语句来指定。如ASSUMECS:code,DS:data,ES:data语句中的code和data为段名。这个语句说明:CS将指向名字为code的代码段DS和ES将指向名字为data的数据段但要注意,ASSUME伪指令只是告知汇编程序有关段寄存器与段的关系,并没有给段寄存器赋予实际的初值。故下面的语句

MOV AX,DATAMOV DS,AXMOV ES,AX将段基址装入段寄存器。如果程序中用到堆栈段,则SS也需装入实际的初值。代码段基地址不需要程序员装入CS寄存器,而由OS负责装入。38例1:CODESEGMENT

ASSUMECS:CODE,DS:DATA1,SS:STACKMOVAX,DATA1MOVDS,AXMOVAX,STACKMOVSS,AX……CODEENDS39例2:.DOSSEG.MODELSMALL.STACK100H.DATAIVARDB5IARRAYDW50DUP(5)STRINGDB‘Thisisastring’

.CODE403.3.5过程定义伪指令PROC、ENDP

过程就是子程序。一个过程可以被其它程序所调用(用CALL指令),过程的最后一条指令一般是返回指令(RET)。过程定义伪指令的格式为

<过程名>

PROC[NEAR/FAR]…RET

<过程名>

ENDP

注意:PROC和ENDP必须成对出现。调用NEAR过程:先将IP内容压入堆栈,再将入口地址传送到IP(SP)←(SP)-2,((SP)+1:SP)←(IP)41调用FAR过程:先将CS内容压入堆栈,再将IP内容压入堆栈,最后将段地址送CS,偏移地址送IP(SP)←(SP)-2,((SP)+1:SP)←(CS);(SP)←(SP)-2,((SP)+1:SP)←(IP)(CS)←SEGfar_proc,(IP)←OFFSETfar_proc,例:NAME1PROCFARCALLNAME2RETNAME2PROCNEAR

RETNAME2ENDPNAME1ENDP

423.3.6模块定义与连接伪操作1、NAME模块名;NAME前面不允许加标号2、END[标号];END后面语句不予处理3、PUBLIC符号[,…];说明某些符号是公共的4、EXTRN名字:类型[,…]若为变量,类型可以是BYTE、WORD、DWORD例:EXTRNALPHA:BYTE,BETA:WORD若为过程,类型可以是NEAR、FAR例:EXTRNSBRT:FAR若为数值,类型可以是ABS433.4DOS系统功能调用介绍系统功能调用——由OS提供的一组实现特殊功能的子程序供程序员在程序中调用,以减轻编程工作量。系统功能调用有两种,一种称为DOS功能调用,另一种称为BIOS功能调用。用户程序在调用这些系统服务程序时,不是用CALL命令,而是采用软中断指令INTn来实现。n=5~1FH,调用BIOS中的服务程序;n=20~3FH,调用DOS中的服务程序;在DOS系统中,功能调用都是用软中断指令INT21H来实现的。44INT2lH功能大致可以分为四个方面:设备管理、目录管理、文件管理和其它。D0S系统功能调用的使用方法如下:① AH←功能号;② 设置该功能所要求的其他入口参数;③ 执行INT21H指令;分析出口参数。以下介绍INT21H的几个最常用的功能。关于数据输入和输出我们这里只讨论键盘输入和显示输出,调用系统功能需要提供入口参数及所调用的功能号,调用结束返回结果。451.DOS键盘功能调用(1)检查键盘状态(功能号=0BH)

MOVAH,0BHINT21H例1:

LOOP:……

MOVAH,OBHINT21HINCALJNELOOP;无键入则循环LOOPRET;有键入停止循环返回

46(2)单字符输入一个字符(功能号=1)

MOVAH,1INT21H<AL中有键入的字符>例2:GET_KEY:MOVAH,1

;等待键入字符

INT21H

;结果在AL中

CMPAL,’Y’ ;是’Y’?JZYES ;是,转YESCMPAL,’N’ ;是’N’?JZNO ;是,转NOJMPGET_KEY ;否则继续等待输入YES: …

…NO: …47(3)输入字符串(功能号=0AH)

此功能调用从键盘输入一串字符并把它存入用户指定的缓冲区中。

MOVAH,0AHLEADX,<字符串缓冲区首地址>INT21H用户定义的输入字符串的缓冲区格式

(预留的N1个字节的存储单元)

0DHN2N1N1:缓冲区长度(最大键入字符数)N2:实际键入的字符数(不包括回车符)

48例:DATASEGMENTBUFSIZEDB25ACTCHARDB?CHARTEXTDB25DUP(?)DB‘$’……CODESEGMENT……

MOVDX,OFFSETBUFSIZEMOVAH,0AHINT21H

49若用户键入的字符数(包括回车)≥定义的N1,本功能调用将不再接收新的键入,且光标不再向右移动。例2:设在数据段定义键盘缓冲区如下:

STR1DB10,?,10DUP(?)

调用DOS功能的0AH号功能的程序段为:

LEADX,STR1MOVAH,0AHINT21H

此程序段最多从键盘接收10个按键(包括回车)。502.DOS显示功能调用(1)在显示器上显示一个字符(功能号=2)

MOVAH,2

MOVDL,<要显示的字符>INT21H

例:在显示器上显示一个字符‘A’MOVAH,2MOVDL,’A’;或MOVDL,

41HINT21H(2)显示字符串(功能号=9)

MOVAH,9LEADX,<字符串>

INT21H;注意:被显示的字符串必须以’$’结束。51附:BIOS功能调用BIOS:基本输入输出系统,是固化在EPROM中的一组实现基本输入输出功能的子程序。BIOS调用通过多个软中断提供,调用方法为:

MOVAH,<功能号> <设置入口参数,一般将参数放在寄存器中> INT <中断类型>

BIOS中的几个主要中断类型如下:

INT10H——屏幕显示

INT13H——磁盘操作

INT14H——串行口操作

INT16H——键盘操作 INT17H——打印机操作 每类中断由包含许多子功能,调用时通过功能号指定。

BIOS功能调用说明见附录。523.5汇编语言程序设计举例例1:源数据区与目标数据区地址可能重叠的数据块传送图3.15

源数据区与目标数据区地址重叠示意图53注1:若源数据区的起始地址低于目标数据区的起始地址,应从高地址开始传送;否则应从低地址开始传送。注2:数据块的长度在CX中。54CODESEGMENTASSUMECS:CODEBLK_MOVPROCFARSTART:PUSHDS;DS压入堆栈MOVAX,0PUSHAX;AX压入堆栈MOVAX,SI;计算源数据区物理地址的高16位

SHRAX,1SHRAX,1SHRAX,1SHRAX,1;AX内容右移4位MOVDX,DS;段地址存入DXADDAX,DX;物理地址高16位存入AX中MOVDS,AX;结果送DSANDSI,0FH;源数据区物理地址低4位送SI55MOVBX,DI;计算目标数据区物理地址的高16位

SHRBX,1SHRBX,1SHRBX,1SHRBX,1;BX内容右移4位MOVDX,ES;段地址存入DXADDBX,DX;物理地址高16位存入BX中MOVES,BX;结果送ESANDDI,0FH;源数据区物理地址低4位送DI

CMPAX,BX;比较DS与ES的高16位JADOWN;若DS高,则转移到DOWNJBUP;若ES高,则转移到UP

56

CMPSI,DI;若相等,则比较低4位地址JADOWN;若SI高,则转DOWNJBUP;若DI高,则转UPJMPEXIT;若相等,则无条件退出UP:STD;(DF)=1,从高地址开始传送MOVAX,CX;将数据段长度送AXDECAX;AX减1ADDSI,AX;(SI)←(SI)+(AX)ADDDI,AX;(DI)←(DI)+(AX)JMPTRANS57DOWN:CLD;(DF)=0,从低地址开始传送TRANS:REPMOVSBEXIT:RETBLK_MOVEENDPCODEENDSENDSTRAT

思考题:1、如何获得的物理地址?2、为什么不用SHRAX,CL?

58例2:将36位BCD数转换为ASCII十进制数注1:前导的0可以不显示;注2:全0时则只显示一个0;59DATASEGMENTBCDBUFDB56H,34H,12H,90H,78H,56H,34H,12HDB90H,78H,56H,34H,12H,90H,78H,56H,34H,12HDATAENDSSTACKSEGMENTSTACKDB100DUP(?);定义100个存储空间,但内容未知STACKENDSCODESEGMENTASSUMECS:CODE,DS:DATA,SS:STACKTRANSPROCFARSTRAT:PUSHDS;将DS压入堆栈MOVAX,0PUSHAX;将AX压入堆栈60

MOVAX,DATAMOVDS,AX

;数据段初始化MOVCX,18;字节数LEASI,BCDBUF;取BCDBUF的偏移地址ADDSI,17;(SI)=17MOVDH,0;(DH)=0LOAD:PUSHCX;将CX压入堆栈MOVAL,[SI];取最后一个BCD数DECSI;SI减1MOVBL,AL;将AL内容送BL暂存MOVCL,4ROLAL,CL;AL内容左移4位,高4位与低4位交换61

ANDAL,0FH;取高4位BCDORDH,AL;判断是否为前导0JZLAST;是的话,转LAST

ADDAL,30H;转换成ASCII码MOVDL,ALMOVAH,02INT21H;输出显示LAST:POPCX;CX出栈CMPCX,1;判断是否为最后一个字节JNZBCDL;否,则转BCDLMOVDH,0FFH;若是,设置标志62BCDL:MOVAL,BL;取暂存在BL的内容ANDAL,0FH;取低4位BCDORDH,AL;判断是否为前导0JZGOON;是的话,转GOONADDAL,30H;转换成ASCII码

MOVDL,ALMOVAH,02INT21H

;输出显示GOON:LOOPLOADRETTRANSENDPCODEENDSENDSTRAT63例3:要求从键盘输入一个小写英文字母,将其转换成大写英文字母后屏幕上显示出来。源程序设计如下:STACKSEGMENTSTACK ;定义堆栈段

DB100DUP(?) ;开辟100个存储单元STACKENDS ;堆栈段结束CODESEGMENT;定义代码段

ASSUMECS:CODE,SS:STACKSTART:MOVAH,01H;1号调用,从键盘输入一字符存入ALINT21H

SUBAL,20H;将AL中字符的ASCII码减去20H变成大写字母

MOVDL,AL ;结果送DL

64

MOVAH,02H ;2号调用,在屏幕上显示DL中的内容

INT21H

MOVAH,4CH ;返回DOS INT21H

CODEENDS

;代码段结束

ENDSTART ;程序汇编结束

65

例4:试计算(S=(W-(X×Y+Z-340))/X)DATASEGMENT;定义数据段

WDW-245 ;变量初始化

XDW15YDW-32ZDW280RESULTDW2DUP(?) ;定义结果保存单元DATAENDS ;数据段结束CODESEGMENT ;定义代码段

ASSUMECS:CODE,DS:DATA

START:MOVAX,DATA ;初始化DSMOVDS,AX

MOVAX,X ;取出被乘数X存入AX中

IMULY ;执行X×Y操作

66MOVCX,AX;乘积的低位字转存至CXMOVBX,DX;乘积的高位字转存至BXMOVAX,Z;取出加数Z存入AX中CWD;将Z扩展成双字ADDCX,AX;X×Y的低位字与Z的低位字相加ADCBX,DX;X×Y的高位字与Z的高位字及进位相加

SUBCX,340;X×Y+Z的低位字减340SBBBX,0;X×Y+Z的高位字减低位的借位67

MOVAX,W ;取出W存入AXCWD ;将W扩展成双字

SUBAX,CX ;(W-(X×Y+Z)-340)低位运算

SBBDX,BX ;(W-(X×Y+Z)-340)高位运算

IDIVX ;(W-(X×Y+Z)-340)/X

MOVRESULT,AX;商存入RESULT单元

MOVRESULT+2,DX;余数存入RESULT+2单元

MOVAH,4CHINT21H ;返回DOS

CODEENDS ;代码段结束

ENDSTART;汇编结束68例5:已知在内存中有一个字节单元X,存有带符号数据,要求计算出它的绝对值后,放入RESULT单元中。分析:根据数学中绝对值的概念知道,一个正数的绝对值是它本身,而一个负数的绝对值是它的相反数加1;要计算一个数的相反数,需要完成减法运算,即用0减去这个数。8086指令系统中有专门的取负求其补数的指令NEG。程序流程如图所示。源程序设计如下:69程序段如下DATA SEGMENT

X DB-25 ;定义变量

RESULT DB? ;定义结果保存单元DATA ENDSCODE SEGMENTASSUMEDS:DATA,CS:CODESTART:MOV AX,DATA MOV DS,AX ;初始化DS

MOV AL,X;X取到AL中

TEST AL,80H;测试AL正负

JZ NEXT;为正,转NEXT

NEG AL;否则AL求补NEXT: MOV RESULT,AL ;送结果

MOV AH,4CHINT 21H ;返回DOSCODE ENDS

END START ;汇编结束70例6:设变量X为带符号整数,试编写一个程序,完成下面的分段函数计算:

题目分析:为了实现上述分段函数的计算,首先要利用上一个例题求出X的绝对值,然后根据X的绝对值判断Y的取值。程序流程如图所示。程序段如下(DOS下演示)

:71DATA SEGMENT

XDB-36YDB?DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATASTART:MOVAX,DATA MOVDS,AX

MOVAL,X CMPAL,0JGENEXT ;为正,转NEXT

NEGAL ;AL中的内容求补NEXT:CMPAL,5 ;|X|和5比较

JGEP1 ;≥5,转P1

MOVAL,1 ;否则1送ALMOVBL,X ;X送BL中

SUBAL,BL ;结果送AL中

JMPEXIT ;转EXITP1: MOVAL,0 ;0送AL中EXIT:MOVY,AL ;结果送Y单元

MOVAH,4CHINT21H ;返回DOSCODE ENDS

ENDSTART ;汇编结束

72

例7:编写程序,完成下面的分段函数的计算(X为单字节带符号数据)。题目分析:这是1个3路分支的程序设计,X为内存中的一个带符号数,首先判断其正负,若为负,-1作为函数值;若为正,再判断是否为0,如果为0,函数返回值为0,否则返回值为1,流程图如图所示。73

DATASEGMENTXDB-25YDB?DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATA

START:MOVAX,DATA

MOVDS,AX;初始化DS

MOVAL,X;X取到AL中

CMPAL,0;AL和0比较

JGEBIG;≥0,转BIGMOVBL,-1;否则-1送BLJMPEXIT;转到结束位置

74BIG:JEEE;AL=0转EEMOVBL,1;否则1送BLJMPEXIT;转到结束位置

EE:MOVBL,0;0送BLEXIT:MOVY,BL;BL中内容送Y单元

MOVAH,4CHINT21H

CODEENDSENDSTART;汇编结束75例8:设计一个程序,统计在内存W单元保存的无符号字变量中有多少个二进制“1”,统计结果送内存N单元保存。分析:要统计内存W单元保存的无符号字变量中有多少个二进制“1”,可以将该数据送寄存器AX中,通过移位指令将AX中的每一位依次移入进位标志CF中,若CF=1则计数器CL的值加1,这样就可以统计出AX中1的个数。设计源程序如下:DATASEGMENTWDW00FFH ;定义字数据NDB? ;定义结果保存单元DATAENDSCODESEGMENT ASSUMECS:CODE,DS:DATA76START:MOVAX,DATA ;初始化DSMOVDS,AX

MOVCL,0 ;计数器清零

MOVAX,W ;取数到AXAA: ANDAX,AX ;逻辑与,判AX=0?

JZCC ;结果为0转移到CCSHLAX,1 ;逻辑左移1位

JNCBB ;无进位转BB

INCCL ;有“1”则计数BB: JMPAA ;无条件转AACC: MOVN,CL ;结果送N单元

MOVAH,4CH ;返回DOSINT21HCODEENDS

ENDSTART ;汇编结束77例9:编制程序完成求1~50之间的自然数中的奇数之累加和,结果送到RESULT单元中。该题属于循环次数已知,即将50以内的25个奇数进行累加和计算,可采用递增计数法来实现求累加和,程序设计如下:DATA SEGMENTRESULTDW? ;定义结果保存单元CNEQU25 ;定义计数次数变量DATA ENDSCODE SEGMENT

ASSUMEDS:DATA,CS:CODE78START:MOVAX,DATAMOVDS,AX ;初始化DS

MOVAX,0 ;循环初始化

MOVCX,CNMOVBX,1NEXT:ADDAX,BX ;求累加和

ADDBX,2 ;(BX)←(BX)+2LOOPNEXT ;(CX)-1≠0转NEXT

MOVRESULT,AX ;计算完毕保存结果

MOVAH,4CHINT21H ;程序结束CODEENDS

ENDSTART ;汇编结束79

例10:编制程序完成求1+2+3+……+N的累加和,直到累加和超过1000为止。统计被累加的自然数的个数送CN单元,累加和送SUM单元。该题的循环次数预先是不确定的,只能按照循环过程中的某个特定条件来决定循环是否继续执行。可通过测试条件是否成立来实现对循环的控制。程序设计如下:80DATA SEGMENT SUMDW? CNDW?DATA ENDSCODE SEGMENT

ASSUMECS:CODE,DS:DATASTART:MOVAX,DATA MOVDS,AX ;初始化DS

MOVAX,0 ;0送AX MOVBX,0 ;0送BXLP: INCBX ;BX加1 ADDAX,BX ;求累加和

CMPAX,1000 ;比较

JBELP ;结果≤1000转LP

MOVSUM,AX MOVCN,BX ;送结果

MOVAH,4CH INT21H ;返回DOSCODE ENDS

ENDSTART ;汇编结束81例11:已知在内存中从TABLE单元起存放0~10的平方值。在X单元中有一个待查数据,用查表的方法求出X的平方值送到Y单元中。程序如下:DATA SEGMENT

TABLEDW0,1,4,9,16,25,36,49,64,81,100 X DB4 Y DW?DATA ENDSCODE SEGMENT

ASSUMEDS:DATA,CS:CODESTART:MOVAX,DATA MOVDS,AX ;初始化DS

82

MOVBX,OFFSETTABLE ;BX指向表格首地址

MOVAL,X ;X中内容取出送至AL中

MOVAH,0 ;X中的值扩展为字

SHLAX,1 ;计算X乘2

ADDBX,AX ;BX指向要查找的位置

MOVDL,[BX];取出要查找的内容的低位字节

MOVDH,[BX+1];取出要查找的内容的高位字节

MOVY,DX;结果保存到内存中

MOVAH,4CH INT21H

温馨提示

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

评论

0/150

提交评论