第3章汇编语言及编程_第1页
第3章汇编语言及编程_第2页
第3章汇编语言及编程_第3页
第3章汇编语言及编程_第4页
第3章汇编语言及编程_第5页
已阅读5页,还剩76页未读 继续免费阅读

下载本文档

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

文档简介

第三章汇编语言及编程3.1汇编语言程序结构与汇编语句3.2伪指令语句3.3汇编语言编程环境3.4DOS/BIOS功能调用3.5三种基本结构程序的设计3.6子程序设计与调用3-113.1汇编语言程序结构与汇编语句3.1.1汇编语言源程序结构

3.1.2汇编语言的语句3-23.1.1汇编语言源程序结构80X86/Pentium系列MPU汇编语言都是以逻辑段为基础,按段的概念来组织代码和数据的。因此,源程序结构与逻辑段的定义方法密切相关,而宏汇编语言MASM5.0以上的版本中,逻辑段既可用完整段定义,又可用简化段定义。3-31.标准的单模块源程序框架[.586]

DATASEGMENT[USE16/USE32] ;定义数据段

;数据定义伪指令序列

DATAENDS

STACKSEGMENT[USE16/USE32]STACK ;定义堆栈段

;数据定义伪指令序列

STACKENDS

CODESEGMENT[USE16/USE32] ;定义代码段

ASSUMECS:CODE,SS:STACK,DS:DATA,ES:DATA

START:MOVAX,DATA ;取数据段基址

MOVDS,AX ;建立DS的可寻址性

MOVES,AX ;建立ES段的可寻址性

;核心程序段

MOVAH,4CH ;返回DOS操作系统

INT21H CODEENDS

ENDSTART⑴一个源程序由若干逻辑段组成。一般一个源程序具有数据段、附加数据段、堆栈段和代码段;但只有代码段是必不可少的。

⑵采用完整段定义时,对程序中定义的逻辑段,要说明逻辑段与段寄存器的寻址关系。ASSUMECS:CODE,SS:STACK,DS:DATA,ES:DATA⑶对数据段(有时还有堆栈段),程序中要包含初始化段寄存器的语句。MOVAX,DATAMOVDS,AXMOVES,AX程序中要包含返回DOS的语句。MOVAH,4CHINT21H⑸源程序(模块)以END伪指令结束

ENDSTART3.1.1汇编语言源程序结构3-43.1.1汇编语言源程序结构(1)使用DOS的4CH号功能调用这种方法是在代码段结束前加调用语句:MOVAH,4CH;功能号4CH→AHINT21H;中断调用(2)使用20H号软功能调用调用方式是在代码段结束前加调用语句:INT20H(3)使用DOS的0号功能调用调用方式是在代码段结束前加调用语句:

MOVAH,0INT21H2.返回DOS状态的方法3-5(4)将主程序定义为远过程也称为“标准序”方法。这种方法是在代码段开始处按下述方式定义主程序:

CODE SEGMENT… ASSUME…主过程名 PROCFAR

PUSHDS SUBAX,AX ;标准序

PUSHAX

RET主过程名ENDP

END主过程名3.1.1汇编语言源程序结构3-6指令语句伪指令语句宏指令语句3.1.2汇编语言的语句

语句是汇编语言程序的基本组成单位,用于规定汇编语言的一个基本操作。汇编语言包含三种基本语句:是可执行语句,由硬件(CPU)完成其功能,汇编时产生目标代码。不可执行语句,其功能由相应软件完成,不产生目标代码。用户定义的新指令,汇编时产生相应的目标代码。3-7标号和名字——分别是给指令单元和伪指令起的符号名称,统称为标识符。(注意组成的语法规则)助记符和定义符——分别用于规定指令语句的操作性质和伪指令语句的伪操作功能,统称操作符。操作数——操作数允许有多个,这时各操作数之间要用逗号“,”隔开。3.1.2汇编语言的语句指令语句:[标号:]助记符[操作数][;注释]伪指令语句:[名字]定义符[操作数][;注释]1.语句格式3-82.数据

汇编语言中使用的数据有常数、变量和标号。

(1)常数常数是指那些在汇编过程中已有确定数值的量,分为数值常数和字符串常数两类。主要用作:指令语句中的立即操作数基址、变址或基址加变址寻址中的位移量伪指令语句中用于给变量赋初值3.1.2汇编语言的语句3-9标号是指令的符号化地址,一定在代码段,而变量是数据的符号化地址,一般在数据段,有时也可在代码段定义。变量与标号有三个共同属性:段基址:所在段的起始地址(SEG)偏移值:相对于段基址的位移量(OFFSET)类型:所占字节数(TYPE)(2)变量与标号3.1.2汇编语言的语句3-10变量与标号区别标号可以用作转移控制类指令的操作数,但变量不能。变量可以用作基址、变址或基址加变址寻址的位移量,但标号不能。3.1.2汇编语言的语句3-11例3.1

假设VAR1和VAR2为字变量,LAB为程序中的一个标号,判断下列指令是否正确,若错误请指出错误之处:①ADDVAR1,VAR2②SUBAL,VAR1③JNZVAR1④JMPLAB[SI]⑤JMPNEARLAB⑥MOVAX,VAR1[BX]⑦JMPVAR2[BX]错,不允许存储器变量间直接传数错,源与目的操作数类型不一致错,变量不能用作条件转移指令的操作数错,标号不能用作变址寻址的位移量错,缺PTR运算符正确正确3.1.2汇编语言的语句3-123.表达式表达式是汇编语句操作数的基本形式,由运算符和运算对象组成。●算术运算符●逻辑运算符●关系运算符●汇编语言特定的运算符运算符●常数、变量和标号●操作数●构成程序的段和偏移量…运算对象3.1.2汇编语言的语句3-13指在汇编过程中能够由汇编程序计算出数值的表达式。可作为指令中的立即操作数和数据区中的初值使用。例如:MOVBX,0FFF0HAND0B234HMOVAL,4CHEQ2MOVAH,4CHGT1MOVAX,SEGLABLE表达式又分为数值表达式和地址表达式:3.1.2汇编语言的语句数值表达式3-14其值表示存储器地址,一般都是段内的偏移地址。与变量一样,地址表达式也具有段值、偏移值和类型属性。地址表达式主要用来表示指令语句中的操作数,例如:MOVAX,BASE[EAX][EBX]JMPBASE[EAX]

LEABX,BASE+123.1.2汇编语言的语句地址表达式3-153.2.1程序结构伪指令语句3.2.2符号定义伪指令3.2.3数据定义伪指令3.2.4过程与宏定义伪指令3.2.5结构定义伪指令

3.2伪指令语句3-163.2.1程序结构伪指令语句方式选择伪指令完整段定义伪指令指定地址伪指令模块定义伪指令这类语句是与程序结构紧密相关的基本伪指令语句,用于说明CPU的类型、逻辑段结构、源程序(或模块)起止信息和段内存的安排等。主要包括:3-171.方式选择伪指令方式选择伪指令用于通知汇编程序,当前的源程序指令是哪一种CPU指令,经过汇编链接之后生成的目标程序在哪一种CPU机型上运行。不属于选定CPU的指令均为非法指令。所以,方式选择伪指令本质上也就是指令集选择伪指令。通常,方式选择伪指令放在程序的头部,作为源程序的第一条语句。缺省时默认8086指令集。3.2.1程序结构伪指令语句3-182.完整段定义伪指令采用完整段定义伪指令可具体控制汇编程序(MASM)和链接程序(LINK)在内存中组织代码和数据的方式。主要包括段定义语句和段寄存器说明语句。

3.2.1程序结构伪指令语句3-193.2.1程序结构伪指令语句⑴段定义语句

格式:段名SEGMENT[定位类型][,组合类型][,字长选择][,‘类别’]段体 ;由指令、伪指令和宏指令语句组成段名ENDS

说明:

(1)SEGMENT/ENDS是一对段定义语句,一个逻辑段从SEGMENT语句开始,到ENDS语句结束。(2)段名是用户定义的段的标识符,用于指明段的基址。(3)4个可选参数用于为源程序的汇编、连接提供必要的信息,特别是模块化程序,各个模块如何定位,彼此之间如何连接,将较多地涉及到定位类型和组合类型的选择。指定段起点的边界类型:BYTE(字节)WORD(字)DWORD(双字)PARA(节)PAGE(页)

定位类型告诉链接程序本段与其它模块中同名段的组合连接关系:PUBLIC连接到同一个物理段中STACK连接到同一个物理堆栈段中,并给SS:ESP赋值COMMON产生一个覆盖段。MEMORYAT表达式

组合类型定义段中使用的偏移地址和寄存器的字长USE16──表示该段字长为16位USE32──表示该段字长为32位字长选择3-20组合连接举例:模块2(从模块):DSEGSEGMENTCOMMONARRAY_BDW200DUP(?)DSEGENDSSSEGSEGMENTSTACKDW50DUP(?)SSEGENDSCSEGSEGMENTPUBLIC

CSEGENDS

END模块1(主模块):DSEGSEGMENTCOMMONARRAY_ADW100DUP(?)DSEGENDSSSEGSEGMENTSTACKDW50DUP(?)SSEGENDSCSEGSEGMENTPUBLICASSUMECS:CSEG,DS:DSEG,SS:SSEGSTART:MOVAX,DSEGMOVDS,AX

CSEGENDSENDSTARTCSEGDSEG(共400字节)模块2代码模块2数据SSEG(共200字节)模块1代码模块2堆栈模块1数据逻辑段组合示意图模块1堆栈3.2.1程序结构伪指令语句3-21⑵段寄存器说明语句

格式:ASSUME段寄存器:段名[,段寄存器:段名,…]功能:说明源程序中定义的段由那个段寄存器去寻址。说明:

⑴CS只能用于包含有程序的段,反之含有程序的段也只能以CS作为段寄存器。SS也一样,只能与堆栈段对应。⑵CS所对应的段名必须在该语句之前有定义。⑶该语句是说明性语句。3.2.1程序结构伪指令语句3-223.指定地址伪指令

格式:

ORG偏移地址ORG$+偏移地址功能:该伪指令以其指定的偏移地址或由$给出的当前地址加上指定的偏移地址作为当前开始分配和使用的偏移地址。3.2.1程序结构伪指令语句3-234.模块定义伪指令模块定义伪指令包括模块开始和模块结束语句。

(1)模块开始语句(NAME)

格式:NAME[模块名]

功能:指示源程序开始,并指出该源程序的模块名。(2)模块结束语句(END)

格式:END[标号/过程名]

功能:模块结束语句表示源程序到此结束。3.2.1程序结构伪指令语句3-243.2.2符号定义伪指令格式:赋值语句:符号名EQU表达式功能:都是用符号名代替表达式的值。但赋值语句定义的符号名不能重新定义,而等号语句允许。1.符号常数定义伪指令等号语句:符号名=表达式

3-25

例3.2赋值语句与等号语句举例。赋值语句:

XEQU50 YEQUX+10 COUNTEQU$-ARRY 等号语句:

CON=5 BASE=200H

BASE=BASE+10H ;重新定义BASE3.2.2符号定义伪指令3-262.定义符号名伪指令格式:符号名LABEL类型功能:将紧跟在本伪指令后的标号、操作码、过程或变量建立新的符号名,并刷新其类型,但它并不为新指定的变量或标号分配存储空间。例如:SUB_FARLABELFAR ;远调用入口SUB_NEAR:MOVAL,[SI]

;近调用入口两个标号SUB_FAR和SUB_NEAR均指向同一条指令,前者为远标号,后者为近标号。3.2.2符号定义伪指令3-273.2.3数据定义伪指令伪指令格式:DBDWDDDFDQDT数据项[,数据项,…,数据项][变量名]功能:是为数据项或项表分配存储空间,给它们赋初值,并用一个符号名(称为变量)与之相联系。8位(字节)16位(字)32位(双字)48位(长字)64位(四字)80位(十字节)

3-28使用说明:⑴给变量赋初值可以是赋确定的值,也可以是赋不确定的值(用“?”表示),还可以是用DUP运算符建立的多次拷贝。

例3.3

使用80X86汇编语言的伪操作命令定义:

VALDB93DUP(5,2DUP(2DUP(1,2DUP(3)),4))

则在VAL存储区内前10个字节单元的数据是

解:由内向外逐层展开,分别相当于:①93DUP(5,2DUP(2DUP(1,3,3),4))②93DUP(5,2DUP(1,3,3,1,3,3,4))③93DUP(5,1,3,3,1,3,3,4,1,3,3,1,3,3,4)即表示重复93个数据序列:‘5,1,3,3,1,3,3,4,1,3,3,1,3,3,4’3.2.3数据定义伪指令3-29

⑵使用SEG、OFFSET、TYPE、LENGTH和SIZE运算符求变量的各种属性时,特别要注意:

对LENGTH运算符,如果变量是用重复数据操作符DUP说明的,则返回外层DUP给定的值;如果没有DUP说明,则返回值总是1。

对SIZE运算符有:SIZE=TYPE×LENGTH使用说明:3.2.3数据定义伪指令3-30解:此题有两层DUP定义,但最外层DUP给定的值为100,所以:(BX)=数组ARRAY的偏移地址;(CX)=数组ARRAY的长度=100;(SI)=数组ARRAY的类型=2。

例3.4若数组ARRAY在数据段中已作如下定义:

ARRAYDW100DUP(123H,3DUP(?)),1234H

试指出下列指令执行后,有关寄存器的内容是多少?MOV BX,OFFSETARRAYMOV CX,LENGTHARRAYMOV SI,0ADD SI,TYPEARRAY3.2.3数据定义伪指令3-31⑶操作符“$”是取地址计数器的当前值,常用于表达式定义数组长度。

例3.5

已知:

ORG0100H ARYDW3,$+4,5,6 CNTEQU$-ARY DB7,8,CNT,9下列指令执行后,AX、BX寄存器的值为多少?

MOVAX,ARY+2MOVBX,ARY+100100H03H0101H00H0102H06H0103H01H0104H05H0105H00H0106H06H0107H00H0108H07H0109H08H010AH08H010BH09H解:画出数组ARY的内存分配图。(AX)=[ARY+2]=[0102H]=0106H(BX)=[ARY+10]=[010AH]=0908H使用说明:3.2.3数据定义伪指令3-32

⑷使用DB、DW、DD定义串数据(用‘’定义的字符串)时,允许定义的串长度不同,字符的存放顺序也不相同:DB是从左至右顺序为每个字符分配一个字节单元;DW是从左至右顺序为每2个字符分配一个字单元,且前面的字符在高字节,串长度不能超过2;DD是从左至右顺序为每4个字符分配一个双字单元,也是按前面的字符在高字节顺序存放,串长度不能超过4。3.2.3数据定义伪指令3-33

例3.6今需在变量名为STRING的数据区中顺次存放数据‘A’、‘B’、‘C’、‘D’、‘E’、‘F’、‘G’、‘H’,请写出分别用汇编命令DB、DW和DD实现的语句。解:用DB、DW和DD实现的语句分别为:

STRINGDB‘ABCDEFGH’

STRINGDW‘BA’,‘DC’,‘FE’,‘HG’

STRINGDD‘DCBA’,‘HGFE’3.2.3数据定义伪指令3-343.2.4过程与宏定义伪指令过程定义伪指令宏定义伪指令宏和过程的比较3-35格式:过程名PROC[属性]

… ;过程体 [RET] … RET

过程名ENDP

说明:②过程允许嵌套调用,还可以递归调用。③过程与逻辑段也可以相互嵌套,但决不允许过程与段交叉覆盖。过程又称为子程序。它是一段必须通过CALL指令调用才能执行的程序段,执行完后通过一条RET指令返回原调用处。过程需先定义才能调用。

①过程体中必须至少包含一条RET指令,这是过程的出口。但也允许过程有多条RET指令,即过程有多个出口。1.过程定义伪指令3.2.4过程与宏定义伪指令

3-36宏定义格式:宏名MACRO[形式参数表]

;宏体 ENDM

说明:宏定义的宏名必须唯一,称为宏指令。宏指令一经定义就可以在源程序的任何地方调用。相当于由用户给汇编程序提供了一个新的操作码。

宏调用格式:宏名[实际参数表]3.2.4过程与宏定义伪指令

宏的概念与过程很相似,也是用一个宏名字来代替源程序中经常要用到的一个程序模块。2.宏定义伪指令

3-373.2.4过程与宏定义伪指令

使用宏定义和宏调用时要注意两个问题:对带参数的宏指令,宏调用时实际参数与形式参数的类型要一致,以免产生无效调用。宏调用是用宏体中定义的指令序列替换宏指令,所以宏体内的标号要用LOCAL伪指令说明为局部标号,以免多次调用宏时,发生标号重复定义错误。LOCAL伪指令格式:

LOCAL标号1[,标号2,…]3-38解:宏定义如下:

MOVEMACROSARY,DARY

LOCALLP MOVSI,0 MOVCX,100LP:MOVAL,SARY[SI] MOVDARY[SI],AL INCSI LOOPLP ENDM例3.7

定义宏MOVE,其功能是将一个有100个字节元素的数组搬移到另一个数据区。进行宏调用:MOVEFIRST,SECOND宏展开如下:

MOVSI,0MOVCX,100??0000:MOVAL,FIRST[SI] MOVSECOND[SI],AL INCSI LOOP??00003.2.4过程与宏定义伪指令

3-393.宏和过程的比较

宏和过程都可简化源程序的书写,因而也减少了程序出错的可能性。但两者使用上也有区别:3.2.4过程与宏定义伪指令

(1)宏操作可以直接传递和接收参数,而过程不能直接带参数。当过程之间需要传递参数时,必须通过堆栈、寄存器或存储器来进行,编程比宏要复杂。所以,宏汇编适合于代码较短,传送参数较多的子功能段使用,子程序适合于代码较长,调用比较频繁的子功能段使用。(3)引入宏操作并不会在执行目标代码时增加额外的时间开销,但过程调用由于要保护和恢复现场及断点,因此会延长目标程序的执行时间。(2)子程序不管被调用多少次它都只被汇编一次,即有唯一的一段目标代码;而宏指令则调用多少次就汇编多少次,每次调用都要在程序中展开并保留宏体中的每一行。3-403.2.5结构定义伪指令

在一些应用中,常需要将一些不同类型的数据组合成一个有机整体。这时就要用到汇编语言的结构化数据——结构。

与前述的字节、字类型数据不同,一个结构必须先经定义后才可以说明属于这种结构类型的变量,这是因为结构的组成是千变万化的。所以围绕结构定义,有两种伪指令语句:2.结构变量说明与赋初值语句

1.结构类型说明语句(STRUC/ENDS)3-413.2.5结构定义伪指令

语句格式:结构名STRUC…;结构体,由数据定义语句构成结构名ENDSDATESTRUCMONTHDB?DAYDB?YEARDW?DATEENDS结构DATE的存储形式MONTH(1字节)DAY(1字节)YEAR(2字节)结构的定义明确地描述了该结构的组织形式,它告诉汇编程序属于这种组织形式的变量使用内存的模式。例如:

1.结构类型说明语句(STRUC/ENDS)3-42语句格式:

[变量名]结构名〈[域值表]〉例如:VARDATE<4,3,2004H>结构变量VAR的存储形式MONTH(1字节)DAY(1字节)YEAR(2字节)04H03H04H20HVAR3.结构的引用有两种方法:结构变量名.域名[基址或变址寄存器].域名MOVAX,VAR.YEARMOVCL,VAR.DAY上述引用也可用如下方法:MOVBX,OFFSETVAR

MOVAX,[BX].YEARMOVCL,[BX].DAY3.2.5结构定义伪指令2.结构变量说明与赋初值语句3-433.3汇编语言编程环境与其它程序设计语言一样,汇编语言程序的开发过程可归结为:就需求分析、模块划分和算法确定等工作而言,各种程序设计语言是类似的,均可按软件工程的方法进行,但编程和调试则因程序设计语言而异。

需求分析根据需求和规模等因素划分模块确定各功能模块的求解算法、并定义所需的数据结构进行编程和调试3-44对汇编语言而言,根据数据结构和算法进行编码到形成可用程序的过程如下:

需求分析、数据结构和算法汇编语言源程序文件*.ASM目标代码程序文件*.OBJ可执行程序文件*.EXE可用程序连接编辑汇编调试3.3汇编语言编程环境3-45应用程序外设硬件接口BIOSDOS

DOS操作系统和ROMBIOS系统各为用户提供了一组例行子程序,用于完成基本I/O设备、内存、文件和作业的管理,以及时钟、日历的读出和设置等功能。3.4DOS/BIOS功能调用3-46顺序结构分支结构循环结构3.5三种基本结构程序的设计程序的基本结构形式有三种:理论上,三种基本结构是完备的,即任何功能的程序都可由顺序、分支和循环三种结构实现。3-473.5.1顺序结构程序设计顺序程序又称直线程序。其特点是顺序执行的,无分支,无循环,也无转移,只作直线运行。在实际应用中,纯粹用顺序结构编写的完整程序很少见,但是在程序段中它却是大量的存在。所以掌握它是编写复杂应用程序的基础。3-483.5.2分支结构程序设计

在许多实际问题中,往往需要根据不同的情况和给定的条件做出不同的处理。要设计这样的程序,必须事先把各种可能出现的情况及处理方法都编写在程序中,以后计算机运行程序时,可自动根据运行的结果做出判断,有条件地选择执行不同的程序段,按这种要求编写的程序称为分支程序。3-49分支1条件结束开始YN分支2(b)完全分支结构分支程序条件结束开始YN(a)不完全分支结构分支1结束开始条件ii=1i=n分支2分支n…i=2(c)多分支结构IF条件

THEN分支程序IF条件

THEN分支1

ELSE分支2分支程序的结构有三种形式:

3.5.2分支结构程序设计3-50根据X(-128≤X≤127)的值求出Y。例3.9变量X的符号函数定义如下:Y=1X>00X=0-1X<01.利用比较与条件转移指令实现分支

这种方法适合于不完全分支和完全分支这两种结构,对分支较少的多分支结构也可用。3.5.2分支结构程序设计3-51例3.9程序:DATA SEGMENT XDB0F8H YDB?DATA ENDS

CODE SEGMENT ASSUMECS:CODE,DS:DATASTART:MOV AX,DATA MOV DS,AX MOV AL,X ;取变量X的值

CMP AL,0 ;X与0比较

JG BIGR

JE FINISH ;X=0,Y=0 MOV AL,0FFH ;X<0,Y=-1

JMP FINISHBIGR:MOV AL,1 ;X>0,Y=1FINISH:MOV Y,AL ;保存函数值Y MOV AH,4CH INT 21HCODE ENDS END START3.5.2分支结构程序设计3-52这种方法适应于多分支结构。有三种跳转表:BASE

关键字0ADR0M

(c)根据关键字分支关键字nADRn关键字1ADR1+3+3nBASEJMP

JMPM

(b)根据表内指令分支JMP+3n+3BASEADR0

M

(b)根据表内地址分支ADRnADR1+2n+23.5.2分支结构程序设计2.利用跳转表实现分支

3-53使用跳转表实现分支时,要特别注意表内地址分支和表内指令分支两种结构跳转表的定义方法和正确的寻址方式。表内地址分支在数据段定义跳转表,用存储器间接寻址;表内指令分支在代码段定义跳转表,用寄存器间接寻址。3.5.2分支结构程序设计3-54

设某控制程序可完成8种产品的加工,每种加工程序对应一个数字(1~8)。现要求根据输入的值去加工相应产品。假设8种加工程序段与主程序在同一代码段中。3.5.2分支结构程序设计例3.10方法一:用表内地址分支实现此时,跳转表在数据段定义,转移要用存储器间接寻址的跳转指令。3-55例3.10表内地址分支程序

.486DATASEGMENTUSE16‘DATA’DISPDB‘Errorrepeatinput’DB0AH,0DH,‘$’

BASEDDSBR1,SBR2,SBR3,SBR4

DDSBR5,SBR6,SBR7,SBR8DATAENDSCODESEGMENTUSE16‘CODE’ASSUMECS:CODE,DS:DATASTART:MOVAX,DATAMOVDS,AXINPUT:MOVAH,1;输入数字序号INT21HCMPAL,‘1’

JBERR

CMPAL,‘8’

JAERR

SUBAL,‘1’ANDEAX,0000000FH

JMPBASE[EAX*4]SBR1:…

SBR2:…

SBR8:…

ERR:CMPAL,‘E’JZEXIT

MOVDX,OFFSETDISPMOVAH,09H

INT21HJMPINPUTEXIT:MOVAH,4CHINT21HCODEENDSENDSTART3.5.2分支结构程序设计

此题也可用表内指令分支实现。这时,跳转表要在代码段定义,转移则要用寄存器间接寻址的跳转指令。3-56

.486DATASEGMENTUSE16‘DATA’DISPDB‘Errorrepeatinput’DB0AH,0DH,‘$’DATAENDSCODESEGMENTUSE16‘CODE’ASSUMECS:CODE,DS:DATASTART:MOVAX,DATAMOVDS,AXINPUT:MOVAH,1;输入数字序号INT21HCMPAL,‘1’

JBERR

CMPAL,‘8’

JAERR

SUBAL,‘1’

ANDAX,000FHMOVBX,AXSHLBX,1ADDAX,BX

MOVBX,OFFSETBASEADDBX,AXJMPBXBASE:JMPSUB1;跳转表

JMPSUB2JMPSUB8SUB1:…SUB2:…

SUB8:…ERR:CMPAL,‘E’JZEXIT;按E键结束

MOVDX,OFFSETDISPMOVAH,09H;显示提示信息

INT21HJMPINPUT;转重输入字符EXIT:MOVAH,4CHINT21HCODEENDSENDSTART3.5.2分支结构程序设计方法二:用表内指令分支3-57初始化部分循环体循环修改循环控制3.5.3循环结构程序设计凡要重复执行的程序段都可按循环结构设计。采用循环结构,可简化程序书写形式,缩短程序长度,减少占用的内存空间。循环结构程序的组成

循环结构的程序一般包括下面几个部分:

3-58循环结构的组织方式有两种组织循环结构的方式:(a)DO―WHILE结构循环修改条件结束开始YN循环初始化循环体(b)DO―UNTIL结构循环修改条件结束开始YN循环初始化循环体3.5.3循环结构程序设计3-59循环结束的控制方式计数控制条件控制状态控制逻辑尺控制3.5.3循环结构程序设计常用的循环结束控制方式有以下四种:

3-601.计数控制循环程序设计循环次数已知时用计数控制循环,这时常用CX作循环计数器,用循环指令LOOP控制循环。也可用其他通用寄存器作循环计数器,用DEC和JNZ指令控制循环。3.5.3循环结构程序设计

例3.11

编写程序,将ASCII码表示的5位十进制数(≤65535)转换成16位二进制数,并存储起来。

解:设X=Xn-1…X1X0为十进制数,则X转换为二进制数的一般方法为:

X=Xn-110n-1+…+X110+X03-61例3.11程序3.5.3循环结构程序设计DSEGSEGMENTASCDECDB‘23333’BINAYDW0MULTIPLEDW1DSEGENDSCSEGSEGMENTASSUMECS:CSEG,DS:DSEGSTART:MOVAX,DSEGMOVDS,AXMOVCX,10

;SI指向ASCII码数首址LEASI,ASCDEC DECSI

;BX指向ASCII码数个位MOVBX,5NEXT:MOVAL,[BX+SI]ANDAX,0FH

;计算当前十进制位对应的二进制数

MULMULTIPLE

ADDBINAY,AX;累加求和MOVAX,MULTIPLE

;计算下一十进制位对应的权值

MULCX MOVMULTIPLE,AXDECBXJNZNEXT;未完继续MOVAH,4CHINT21HCSEGENDSENDSTART3-62当循环次数未知时,就要用条件或状态信号来控制循环。用条件控制时,常用比较指令CMP与条件转移指令Jcc结合控制循环结束.用状态控制时,状态信号既可由外设提供,也可由其他任务或过程提供,这时常用测试指令TEST与条件转移指令Jcc结合控制循环结束。3.5.3循环结构程序设计2.条件/状态控制循环程序设计3-63例3.12

将16位二进制数,转换成等值的十进制数从显示器输出。3.5.3循环结构程序设计解:设X为任意无符号十进制数,则X可表示为:用10除X,得:即可用连续“除10取余”的方法,依次求得十进制数的个、十、百、千位、…,直到an-1。3-64例3.12程序DATASEGMENTWORD

INTEGERDW12345

;定义存放ASCII码十进制数变量区ASCVALDB5DUP(‘’)DB0AH,0DH,‘$’DATAENDSCODESEGMENTWORDASSUMECS:CODE,DS:DATASTART:MOVAX,DATA MOVDS,AX LEASI,ASCVAL+4

MOVAX,INTEGER

MOVCX,10 ;CX为除数AGAIN:CMPAX,10;商小于10?

JBDONE;小于10结束

XORDX,DX;扩展被除数

DIVCX;(DX:AX)/(CX)

;转换成ASCII码数ORDL,30H

MOV[SI],DL;保存十进制数位 DECSI

JMPAGAINDONE: ORAL,30HMOV[SI],AL

MOVDX,OFFSETASCVALMOVAH,09H ;显示十进制数INT21H

MOVAX,4C00HINT21HCODEENDSENDSTART 3.5.3循环结构程序设计3-65——循环不规则时使用的一种循环控制方法3.5.3循环结构程序设计3.逻辑尺循环程序设计

例3.13

设有数组:定义一个二进制位序列——称为逻辑尺

1100010011每个数组元素zi对应一位,该位为1,表示计算zi时对应数组元素相加,否则相减。3-66例3.13程序START:MOVAX,DATA MOVDS,AX MOVBX,SOCBEH;取逻辑尺

MOVCX,10;置循环次数

MOVSI,0AGAIN:MOVAX,X[SI] ;取xi

SHLBX,1

JNCL1 ADDAX,Y[SI] ;求和

JMPL2L1: SUBAX,Y[SI] ;相减

L2:MOVZ[SI],AX ;保存zi ADDSI,2

LOOPAGAINEXIT:MOVAH,4CH INT21HCODEENDS ENDSTARTDATA SEGMENTXDW x1,x2,x3,x4,x5DWx6,x7,x8,x9,x10YDW y1,y2,y3,y4,y5DWy6,y7,y8,y9,y10ZDW 10DUP(?)

SOCBEHDW1100010011000000BDATA ENDS

STACK SEGMENTSTACKSTNDB100DUP(?)STACK ENDSCODESEGMENTASSUMECS:CODE,SS:STACK,DS:DATA3.5.3循环结构程序设计3-673.6子程序设计与调用3.6.0子程序设计概述3.6.1主程序与子程序的接口3.6.2主程序与子程序间的参数传递3-683.6.0子程序设计概述

同一个程序中,往往有许多地方都需要执行同样的一项任务(一段程序),而该任务又并非规则情况,不能用循环程序来实现,这时可以对这项任务独立地进行编写,形成一个子程序或过程。3-69CALLRET子程序语句序列2结束开始语句序列1子程序调用恢复现场返回开始保护现场语句序列3.6.0子程序设计概述从子程序返回主程序则简称为“返主”通常将主程序向子程序转移叫子程序调用或过程调用,简称“转子”子程序结构如图所示:3-70正确使用CALL/RET指令转子和返主过程中的现场保护和恢复

⑴主程序与子程序所使用的存储单元和寄存器尽量分开,互不干扰。现场保护和恢复又有两种方法:3.6.1主程序与子程序的接口主程序与子程序的接口主要解决两大问题:3-71SUBRPROCPUSHAXPUSHBX… ;子程序体POPBXPOPAX

RETSUBRENDP子程序这时,既可在子程序中保存和恢复,又可在主程序中保存和恢复。例如:…PUSHAXPUSHBXCALLSUBRPOPBXPOPAX…

主程序3.6.1主程序与子程序的接口⑵将“现场”通过堆栈保存和恢复3-72主程序在调用子程序时,往往要向子程序传递一些参数;同样,子程序运行后也经常要把一些结果传回给主程序。主程序与子程序之间的这种信息传递称为参数传递。一般将子程序需要从主程序获取的参数称为入口参数,而将子程序返回给主程序的参数称为出口参数。入口参数使子程序可以对不同数据进行相同功能的处理,出口参数使子程序可送出不同的结果至主程序。3.6.2主程序与子程序的参数传递

3-73常用的参数传递方法有:寄存器传递法存储器传递法堆栈传递法具体采用何种方法要根据情况事先约定好,有时可能同时采用多种方法。

3.6.2主程序与子程序的参数传递调用前,主程序将参数保存在某些通用寄存器中,子程序则直接引用寄存器中的参数。出口参数也可通过寄存器返回给主程序。调用前,主程序将参数存放到内存的某一区域或内存变量中,子程序到此约定的参数区或内存变量中获取参数,结果也可通过约定的存储变量返回给主程序。主程序与子程序将要传递的信息放在堆栈中,使用时再从堆栈中取出。3-74子程序设计举例

例3.14从内存ARY开始的数据区中存放着由N个无符号字数据组成的一维数组,编写程序对这N个元素的数组求和。3.6.2主程序与子程序的参数传递方法一、用寄存器传递参数

主程序通过寄存器BX、CX分别将数组的起始地址和长度信息传递给子程序;子程序计算的结果则通过DX:AX寄存器对返回主程序。3-75例3.14用寄存器传递参数的程序如下:3.6.2主程序与子程序的参数传递.486DSEGSEGMENTUSE16ARYDW123,234,…,1234COUNTEQU($-ARY)/2;定义数组长度

SUMDW2DUP(?);定义结果单元DSEGENDSCODESEGMENTUSE16ASSUMECS:CODE,DS:DSEGSTART:MOVAX,DSEGMOVDS,AX

LEABX,ARY;取数组地址MOVCX,COUNT;取数组长度CALLPROADD;调子程序求和

MOVSUM,AX;保存结果MOVSUM[2],DXMOVAX,4C00HINT21HPROADDPROCNEARXORAX,AX;累加器清0MOVDX,AXNEXT:ADDAX,[BX];求和

ADCDX,0ADDBX,2;调整指针

LOOPNEXTRETPROADDENDPCODEENDSENDSTART3-76方法二、用地址表传递参数这是存储器传递与寄存器传递的结合。主程序在内存中先建立该数组和结果变量,然后将数组的起始地址、长度和结果返回地址组成参数表传递给子程序,子程序通过参数表访问主程序规定的数组。3.6.2主程序与子程序的参数传递3-77例3.14用地址表传递参数的程序如下:

温馨提示

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

评论

0/150

提交评论