微机原理课件第四章宏汇编语言程序设计.ppt_第1页
微机原理课件第四章宏汇编语言程序设计.ppt_第2页
微机原理课件第四章宏汇编语言程序设计.ppt_第3页
微机原理课件第四章宏汇编语言程序设计.ppt_第4页
微机原理课件第四章宏汇编语言程序设计.ppt_第5页
已阅读5页,还剩157页未读 继续免费阅读

下载本文档

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

文档简介

第四章 宏汇编语言程序设计,汇编语言是利用指令的助记符、符号地址、标号来编写的语言,它是机器语言的符号表示,是较低级的语言。,利用汇编语言编写的程序称为汇编语言源程序,上一章讲到的指令系统中的每条指令都是构成源程序的基本语句。但机器不能识别源程序,要通过汇编程序翻译成二进制代码的浮动目标程序,然后由连接程序将目标文件与库文件相连,最后得到可执行的程序,才可在机器上直接运行。,基本概念:,汇编语言:用指令的助记符、符号地址、标号 等来编写的语言。,汇编语言源程序:用汇编语言编写的程序(*.asm),汇编程序:将汇编语言源程序翻译成目标目标程序(代码),这个翻译过程称为汇编,翻译软件就叫汇编程序。,一个完整的汇编语言的语句由下列几部分组成:标号和变量、指令助记符、界符、常数和注释,所有这些都称为标记。,4-1 汇编语言的标记,一、标号和变量 表示指令性语句的符号地址或表示一个数据单元的符号地址。,对标号或变量要注意以下几点: 标号或变量可以由数字、字母、下划线或其它特殊字符组成。,标号或变量不能以数字开头,但可出现在标号的其它地方。,标号或变量最大长度不能超过31个字符。,二、指令助记符 指出指令的性质(功能),三、界符 作为一个程序中或一条指令中两个部分的分隔符号用。,四、常数 二进制:01001101B 十进制:2000或2000D 八进制:1700Q 十六进制:1200H,0FFH 串常数:ABCD ,五、注释 用;开头后面的内容可随意,用来增加程序可 读性的。,表达式由运算对象和运算符组成,在汇编时由汇编程序对它进行运算,运算结果作为一个语句中的操作数来使用。,4-2 汇编语言中的表达式,运算对象:常数、标号或变量,一、算术运算符 有:+、-、*、/、MOD(模,即取除法运算结果之余数)、SHL(左移,左移1位相当于乘2)、SHR(右移,右移1位相当于除以2)。,二、逻辑运算符 有:AND(与)、OR(或)、NOT(非)、XOR(异或),逻辑运算符是按位运算的,只能对常数进行运算,得到结果也是常数。,例4-5 IN AL,PORT AND DX,PORT AND 0FEH OUT DX,AX 前一个AND是指令助记符,而后一个AND是 逻辑运算符。,三、关系运算符 有:EQ(相等)、NE(不等)、LT (小于)、GT(大于),LE(小于或等于)、 GE(大于或等于)。,四、数值返回运算符 数值返回运算符也经常称作分析运算符 有:OFFSET、SEG、TYPE、LENGTH、 SIZE 5种,它们加在变量或标号前,返回运 算对象的某个参数值,例如偏移地址值、段 地址值、类型属性、变量包含的单元数等。,1.OFFSET 格式:OFFSET 变量或标号 OFFSET 返回标号或变量的偏移地址值。,2.SEG 格式:SEG 变量或标号 SEG 返回标号或变量的段地址值。,3.TYPE 格式:TYPE 变量或标号,TYPE加在变量前,返回变量的类型属性。,TYPE加在标号前,返回标号的距离属性。,例4-9 A1 DB 1,2,3 ;变量 A2 DW 1234H ;变量 A3 DD 6 DUP(?);变量 L1: MOV AH,TYPE A1;标号 MOV BH,TYPE A2 MOV CH,TYPE A3 MOV DH,TYPE L1 MOV DX,TYPE L1,4.LENGTH 格式:LENGTH 变量,5.SIZE 格式:SIZE 变量,1.段操作符 格式: 段前缀:变量或地址表达式 段前缀有段寄存器CS、DS,ES,SS后跟冒号 :,用来表示某个变量或地址被修改到哪个 段寄存器提供的段地址。,2.PTR 格式: 类型/距离:PTR 变量或标号,3.THIS 格式:变量或标号 EQU THIS 类型或距离,4.SHORT 格式:SHORT 标号 SHORT用来说明转移类指令中转向地址的 属性,指出转向的目标地址与本指令之间的 距离在-128+127之间,即限制在短转移范 围内。,5.HIGH和LOW 格式:HIGH/LOW 变量或标号 HIGH和LOW称为字节分离运算符,对一个 数或地址表达式,HIGH从中分离出高位字节 LOW从中分离出低位字节。,六、其它运算符 有: 、()、.、MASK和WIDTH等,七、优先级 表达式是常数、变量、标号和运算符的 组合,在计算表达式时,应按优先级高低进 行计算,同时遵循同级运算从左到右的原则 计算。,4-3 伪指令语句,伪指令语句没有对应的机器代码,并不 像指令语句那样由CPU来执行,它是MASM 汇编程序对源程序汇编期间进行处理的。主 要完成变量定义、存储器分配、指示程序开 始和结束、段定义、段分配等。伪指令有以 下几种类型:,一、数据定义语句 格式1:变量名 助记符 操作数,操作数 格式2:变量名 助记符 n DUP(操作数,操作数),例4-21 操作数是常数或表达式 DA1 DB 10H,20H DA2 DW 1122H,34H DA3 DD 5*10H,1234H,例4-22 操作数是字符串 FIRST DB HELLO SECOND DW OK THIRD DB OK,注意:用DW定义字符 串时,只允许包含两个 字符,多于两个字符时, 只能用DB来定义。,例4-23 操作数用?定义不确定值的变量,用 作保留存储空间,以便存放运算结果。 M1 DB ?,? M2 DW 1234H,?,例4-24 操作数用DUP来定义重复变量 ONE DB 5 DUP(0) TWO DW 10 DUP(?) THREE DB 3 DUP(1,2),FOUR DB 2 DUP(1,3 DUP(10H);DUP 嵌套,操作数是变量或标号: 用伪指令DW和DD可以将变量或标号的 偏移地址存入存储器中,当用DD来定义时, 原变量或标号的偏移地址存入低位字中,原 变量或标号的段地址存入高位字中。,例4-25 PP DB 1,2,3;变量PP AD1:MOV AX,BX;标号AD1、AD2 AD2:MOV BX,CX,假设变量的PP的偏移地址为1000H,标号AD1 的偏移地址为2000H,标号AD2的偏移地址为 3000H,段地址为4000H。,二、表达式赋值语句 表达式赋值语句有两种,赋值语句EQU和等号语句=,它们均不占用内存。,1.赋值语句EQU 格式:符号名 EQU 表达式 功能:用来给变量、标号、常数、指令、表达式等定义一个符号名,程序中用到EQU左边的变量、标号时可用右边的常数值或表达式代替,但一经定义在同一个程序模块中就不能重新定义。,2.等号语句= 等号语句=与EQU语句具有相同功能,区别在于EQU中左边的标号不允许重新定义,而用=定义的语句允许重新定义。,三、段定义语句,前面讲过,存储器的物理地址由段地址和偏移地址组合而成,任何一个逻辑段,无论是代码段,数据段,堆栈段,附加段,都必须进行段定义,以便连接程序把不同段和模块连成一个可执行程序。此外还必须明确段和段寄存器之间的关系,这可使用段分配语句来完成。,1.段定义语句 SEGMENTENDS,功能:将一个逻辑段定义成一个整体。,段名 SEGMENT 定位类型 组合类型 分类名 段名 ENDS,2.段分配语句ASSUME 在8086系统中存储器采用分段结构,各段容量64K字节,用户可以设置多个逻辑段,但只允许4个逻辑段同时有效,段分配语句用来完成将逻辑段分别定义成代码段、堆栈段、数据段和附加段。,ASSUME为伪指令助记符,放在代码段的开始,不可省略。提供给汇编程序,说明当前代码段,数据段,堆栈段和附加段4个如何定义。,2.段分配语句ASSUME,例4-29通过表转换指令来实现将57的7段显示段码送到BX寄存器中。,四、过程定义语句,过程也称子程序。在主程序中,经常要用到一些程序段,程序段的功能和结构相同,仅有一些变量赋值不同,此时可以将这些程序段独立编写用过程定义语句进行定义,然后在主程序中对它进行过程调用。这样既节省了内存空间,也便于进行模块化程序设计,使编程清晰,使用灵活。,格式: 过程名 PROC 属性 ;过程内容 RET N 过程名 ENDP,四、过程定义语句,在汇编语言源程序中,使用CALL指令调用过程,过程调用允许嵌套和递归调用。嵌套调用指在一个被调用的过程中,又调用另一个过程;递归调用是指在一个被调用的过程中,又调用了本身的过程。嵌套与递归的深度由堆栈段的容量决定因为过程调用时必须将当前的地址压入堆栈保护起来,使调用返回时能返回到正确的返回地址。另外在子程序入口也有许多参数要保护,以免影响主程序原来的运行状态。,例4-30 近过程定义及调用格式 CCODE SEGMENT ABC PROC NEAR RET ABC ENDP CALL ABC CCODE ENDS,例4-31 远过程定义及调用格式 C1CODE SEGMENT KKK PROC FAR RET KKK ENDP C1CODE ENDS C2CODE SEGMENT CALL KKK C2CODE ENDS,例4-32 过程嵌套调用格式 CCODE SEGMENT KKK PROC NEAR CALL LLL RET KKK ENDP LLL PROC NEAR RET LLL ENDP CCODE ENDS,五、程序开始和结束语句,1.NAME 格式:NAME 程序名 功能:为源程序目标模块赋名字。 2.TITLE 格式:TITLE 文本名 功能:将文本名赋给源程序目标模块作名字。,3.ORG 格式:ORG 表达式,4.END 格式:END 标号名 功能:标记汇编源程序结束,六、结构定义语句,七、外部伪指令及对准伪指令,1.外部伪指令 程序中包含多个模块时,有些程序或数据在各个模块间要相互共享,可用外部伪指令PUBLIC和EXTRN来实现此功能。其中PUBLIC用来定义共享模块,EXTRN用来引用共享模块。,例4-42 DATA SEGMENT A1 DB 10H,20H A2 DW 4 DUP(0) A3 EQU 1000H DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START: MOV AX,DATA TMF LABEL FAR PUBLIC A2,A3,TMF CODE ENDS,PDATA SEGMENT P1 DB 0AH,0BH P2 DB 2 DUP(?) PDATA ENDS PCODE SEGMENT EXTRN A2:WORD,A3:ABS,TMF:FAR MAIN: MOV AX,PDATA MOV BX,OFFSET A2 MOV CX,A3 JMP TMF PCODE ENDS END MAIN,2.对准伪指令 格式:EVEN,3.LABLE(相当于THIS伪指令),LABLE伪指令给已定义的变量或标号取一个名字,并可重新定义它的类型属性,使同一变量或标号在不同地方被引用时,可采用不同的名字,具有不同的类型属性,这样提高了程序的灵活性。,(1)LABLE与变量连用 LABLE与变量连用时,给下一个变量取一个别名,类型属性可修改成BYTE、WORD等。,(2)LABLE与标号连用 LABLE与标号连用时,给下一个语句定 义的标号取一个别名,并可改变距离属性为 FAR或NEAR。,4-4 DOS系统功能调用和BIOS中断调用,一、DOS系统功能调用,DOS系统功能调用分别实现设备管理、文件读/写、文件管理和目录管理等功能。每个子程序对应一个功能号,所有的系统功能调用的格式是一致的,按下面4步进行:,(1)系统功能号送到AH寄存器;,(2)入口参数送到指定寄存器中;,(3)用INT 21H指令执行功能调用;,(4)根据出口参数分析功能调用执行情况。,1. DOS键盘功能调用,键盘提供了字符键、功能键和控制键。每个键都有对应的键值,即标准ASCII码值,通过DOS功能调用可读入键值到AL寄存器或存储器中,表4-7列出DOS键盘功能调用的有关命令。,表4-7 DOS键盘功能调用,(1)键入单字符,1号功能调用:从键盘输入字符并显示, 调用命令为: MOV AH,1 INT 21H,例4-51 交互式程序中用户按下数字键1,2,3,程序 转入相应的服务子程序,若按下其它键就继续等待。 KEY:MOV AH,1 ;读入键值AL INT 21H CMP AL,1 ;键值为1 吗? JE ONE CMP AL, 2 ;键值为2 吗? JE TWO CMP AL,3 ;键值为3 吗? JE THREE JMP KEY ;其它键则继续等待按键 ONE: TWO: THREE:,8号功能调用:从键盘输入字符但不回显,命令为: MOV AH,8 INT 21H,6号功能调用:直接控制台输入/输出,命令为: MOV DL,0FFH MOV AH,6 INT 21H,7号功能调用:直接控制台输入/输出但无回显,命令格式为: MOV AH,7 INT 21H,(2)输入字符串,0AH功能调用:能从键盘接收字符串到内存的输入缓冲区。,例4-52 开辟一个缓冲区,从键盘输入一个字符串,将输入的字符数CL寄存器,并将指针指向字符串的第一个字符。,(3)检验键盘状态 0BH功能调用:检验是否有键按下,若有键按下AL=0FFH,若没有键按下,AL=0,无论检测到是否有键按下,程序将继续执行下一条指令。,(4)清除键盘缓冲区 0CH功能调用:先清除键盘缓冲区,然后执行AL中指定的功能,AL中可以指定1, 6,7,8或0AH功能号,使程序在输入字符前将以前键入的字符清掉。,2. DOS显示功能调用 DOS显示功能调用能够显示字符或字符串,这些功能都自动向前移动光标,表4-8给出了DOS显示功能调用的有关命令。,(1)单字符显示,2号功能调用:2号功能调用实现将字符送到屏幕显示出来。它要求将要显示字符的ASCII码值送到DL寄存器中。,6号功能调用:是直接控制台输入/输出调用,除前面谈到的键盘输入功能外,在DL不等于0FFH时,表示向屏幕输出。它要求将要显示字符的ASCII码值送到DL寄存器中。,(2)字符串显示 9号功能调用:显示字符串,要求DS:DX指向串地址首址,并且字符串必须以$ 字符为结束符。若要求显示字符串后光标自动回车换行,则在$字符前再加上0DH(回车),0AH(换行)字符。,4-5 程序设计方法,前面几章已讨论了指令系统和汇编语言设计基础,而设计出一个好的程序不仅要能正常运行,完成要求的功能,还应该具有下列特点:,(1)程序结构模块化,程序易读,易调试及 维护。,(2)执行速度快。,(3)占用内存空间小。,尤其是结构化设计,在程序复杂的情况下尤为重要。一般来说设计汇编语言源程序的基本步骤如下:,(1)分析问题,抽象出描述问题的数学模型,并确定实现数学模型的算法。,(2)绘制程序流程图,通常先画粗框图,在结构模块中再细画框图。框图一般有起始框,执行框,判断框和终止框。,(3)分配存储空间及工作单元。分配数据段,堆栈段,代码段各在内存什么位置,各个寄存器主要起什么作用。,(4)按流程图设计编写程序。,(5)静态检查,上机调试。,(6)程序运行,结果分析。,在进行汇编语言源程序设计时,通常用到四种程序结构:顺序结构;分支结构循环结构;子程序结构。下面分别加以说明。,一、顺序结构,顺序结构的程序一般是简单程序,程序顺序执行,无分支,无循环,也无转移,图中没有判断框。,例4-64 内存中TABLE开始存放09的平方值,通过人机对话,当任给定一个数X(09),查表得X的平方值,放在AL中。(见程序流程图),.MODEL SMALL .386 .STACK 100H .DATA TABLE DB 0,1,4,9,16,25,36 DB 49,64,81 BUF DB Please input one number(09): DB 0DH,0AH,$ .CODE .STARTUP,MOV DX,OFFSET BUF;显示字符串 MOV AH,9 INT 21H MOV AH,1 ;1号功能调用,键入数送 AL中 INT 21H MOV AH,0 ;查表得键入数的平方值 AND AL,0FH ADD BX,AX MOV AL,BX .EXIT 0 END,二、分支结构,1.分支结构 一般情况下,程序顺序执行,但经常要求程序根据不同条件选择不同的处理方法,这就需要用到分支结构。,例4-65 编程实现以下函数:,核心代码如下:,MOV AL,X CMP AL,0 JG ZHSHU SUB AL,5 JMP OUT ZHSHU:ADD AL,3 OUT: MOV Y,AL,2. 多分支,有的分支结构为多分支,可以利用多个条件转移指令来实现,依次测试条件是否满足,若满足转入相应分支入口,若不满足继续向下测试,直到全部测试完。这种方法编程简单、直观,但运行速度慢,要依次检查才能进入要求的入口。,例4-66 有8个加工子程序,入口地址分别为P1,P2,P8编程实现检测键盘输入命令,使系统分别转向8个加工子程序。(键值为1转向P1,键值为2转向P2,等等。),MOV AH,1 INT 21H CMP AL,1 JE P1 CMP AL,2 JE P2 ,CMP AL,8 JE P8 JMP ST P1: P2: P3: P8: ST: HLT,3. 跳转表实现多分支,利用跳转表实现多分支,就克服了上面 的缺点,可以直接找到相应入口。利用这种 方法要在存储器中先建立一个跳转表,表中包括每个分支的入口地址,跳转指令或关键 字,利用此表就可以实现分支结构。,(1)根据表中入口地址实现分支,跳转表中存放了每个分支程序的入口地址,只要找到表地址,在将其内容取出,即可得到每个分支的入口地址。 表地址=跳转表的首地址+偏移量,例4-67 将例4-66 中程序改成用跳转表来实现:,BASE DW P1,P2,P3,P4 DW P5,P6,P7,P8 ,(2)根据表中指令机器码实现分支,跳转表中存放的是转移指令机器码,查表后程序转到相应的子程序。图4-15给出了转移指令跳转表存放形式。,例4-68 将例4-66 程序用跳转表存放转移指令 机器码实现分支。,MOV AH,1 INT 21H AND AL,0FH MOV AH,0 MOV BL,AL ;将键值保存到BL中 ADD AL,AL ADD AL,BL ;偏移量=键值3 MOV BX,OFFSET BASE ADD BX,AX JMP BX,跳转表中存放关键字,及相应分支地址,图4-16给出了关键字跳转表的格式,图4-17给出了关键字分支流程图。,(3)根据表中关键字实现分支,例4-69 将例4-66用关键字跳转表方式实现分支,BDATA SEGMENT BASE DB 31H ;关键字 DW P1 ;P1入口地址 DB 32H DW P2 DB 38H DW P8 BDATA ENDS,LOP: MOV AH,1 INT 21H CMP AL,0 JE LOP MOV BX,OFFSET BASE NEXT: CMP AL,BX JE DO ADD BX,3 ;加3调整指针 JMP NEXT DO: JMP WORD PTR BX+1 ,三、循环程序结构,1. 循环程序结构形式,循环程序有两种结构形式:一种是“先执行,后判断”结构,另一种是“先判断,后执行”结构。图4-18给出了两种循环程序结构框图。,无论哪种循环结构都包括以下四个部分:,(1)初始化:为循环作准备,设置循环计数值,设置变量 初值。,(2)循环体:循环部分的核心,包括循环的全部执行指令。,(3)修改参数:修改操作数地址,为下次循环作准备。,(4)循环控制:修改计数器值,判断循环控制条件,决定是否跳出循环。,程序流程图如下所示: (先执行,后判断结构),例4-70 将BX中的16进制数转换为ASCII码,存放到BUF开始的内存单元中去,并在屏幕显示出数值。,MOV SI,OFFSET BUF MOV CH,4 NEXT: MOV CL,4 ROL BX,CL MOV AL,BL AND AL,0FH ADD AL,30H CMP AL,3AH JL STORE ADD AL,7 STORE: MOV SI,AL MOV AH,2 MOV DH,AL INT 21H INC SI DEC CH JNZ NEXT HLT,例4-71 AX寄存器中有一个16位二进制数,编程统计其中1的个数,结构放到CL寄存器中。,MOV CL,0 ;初始化 L1: AND AX,AX ;控制循环 JZ STOP SAL AX,1 ;循环体 JNC L2 INC CL L2: JMP L1 STOP:HLT,此程序采用先判断,后执行的循环结构。,2 . 用逻辑尺的方法控制循环,循环控制条件是循环程序设计的关键,必须结合对算法的分析来选择控制条件。有时程序要求按不同次序处理两种函数操作,可以采用逻辑尺的方法控制循环。,DATA SEGMENT LOGRUL EQU 0011010110000000B COUNT EQU 10 ;循环次数 BUF DB 20 DUP(?);采集数据 BLOCK DB 20 DUP(?);处理后数据 DATA ENDS,MOV DX,LOGRUL;逻辑尺DX MOV CX,COUNT ;设循环次数 MOV SI,OFFSET BUF MOV DI,OFFSET BLOCK NEXT: MOV AX,WORD PTR SI ROL DX,1 ;左移一位 JC FUN2 ;进位为1转FUN2 FUN1: ADD AX,5 JMP NEXT1 FUN2: SUB AX,3 NEXT1:MOV WORD PTRDI,AX;送结果 INC SI ;修改地址指针 INC SI INC DI INC DI LOOP NEXT ,3. 多重循环,(2)内循环可以嵌套在外循环中,也可几个内循环并列在外循环中,但各层循环之间不能交叉,可以从内循环跳到外循环,不可以从外循环中直接跳进内层循环。,有些循环结构比较复杂,需要用多重循环完成。多重 循环设计方法与单循环设计方法相同,但应注意:,(1)各重循环的初始控制条件及程序实现。,(3)防止出现死循环,即不能让循环回到初始条件,引起死循环。,例4-72 存储器数据段从BUF开始存放一个字数组,数 组中第一字是存放该数组的长度N,编制一个程序使此数 组中的数据按照从小到大的次序排列。,采用冒泡排序算法。从第一个数据开始相邻的数进行比 较,若次序不对,两数交换位置。第一遍比较(N-1)次 后,最大的数已到了数组尾,第二遍仅需比较(N-2)次 就够了,共比较(N-1)遍就完成了排序,这样共有两重 循环。图4-20给出了程序流程图。,开始,数I数I+1?,结束,初始化 数组起始地址BX 内循环次数N-1CX 外循环次数N-1DX,I=0,地址加2,两数位置交换,内循环计数CX-1,外循环计数DX-1,CX=0?,DX=0?,A,A,Y,N,N,N,Y,Y,图4-20 数组排序冒泡算法流程图,ADATA SEGMENT BUF DW N,15,37,8600,0A768H DW 3412H,1256H,76H ADATA ENDS ASTACK SEGMENT STACK STACK;定义堆栈段 SA DB 100 DUP(?) TOP LABEL WORD ASTACK ENDS ACODE SEGMENT ASSUME CS:ACODE,DS:ADATA,SS:ASTACK MAIN PROC FAR START: MOV AX,ASTACK;将堆栈段段地址送SS MOV SS,AX MOV SP,OFFSET TOP;堆栈指针指向栈顶 PUSH DS ;为返回DOS作准备 SUB AX,AX PUSH AX,MOV AX,ADATA;将数据段段地址送DS MOV DS,AX MOV BX,0;指向BUF第一个字 MOV CX,BUFBX DEC CX ;设计数器CX,内循环次数 L1: MOV DX,CX ;设计数器 DX,外循环次数 L2: ADD BX,2 MOV AX,BUFBX;取BUFI CMP AX,BUFBX+2;若BUFI BUFI+2转 JBE CONTI XCHG AX,BUFBX+2;否则两数交换 MOV BUFBX,AX CONTI: LOOP L2 ;内循环 MOV CX,DX;外循环次数CX MOV BX,0 ;地址返回第一个数据 LOOP L1 ;外循环,RET MAIN ENDP ACODE ENDS END START,四、子程序结构,1. 子程序使用,(1)功能描述:子程序的名称、功能及性能 (2)子程序中用到的寄存器和存储单元 (3)子程序的入口参数,出口参数 (4)子程序中调用其他子程序的名称,例4-74 有一个子程序说明如下: ;名称:BCD2BIN ;功能:将一个字节的的BCD码转换成二进制数 ;所用寄存器:CX ;入口参数:AL存放两位BCD码 ;出口参数:AL存放二进制数 ;调其他子程序:无,子程序形式如下: BCD2BIN PROC NEAR(FAR) PUSH CX MOV CH,AL AND CH,0FH;取BCD码低位 MOV CL,4 ;设置移位次数,SHR AL,CL;取BCD码的高位 MOV CL,10 MUL CL ;高位10+低位 ADD AL,CH POP CX RET BCD2BIN ENDP,过程调用时,主程序使用CALL指令,调用中要处理 好三个问题:,(1)保护调用程序的返回地址,这一点由CALL指令本 身来完成,CPU执行CALL指令时会自动将当前断点的偏 移地址值IP入栈。若是段间调用,将段基址CS和偏移地 址值IP入栈。当子程序返回时,遇到子程序中RET指令, 则自动将当前栈顶值弹出到IP及CS寄存器中,因此要特,别注意堆栈的使用,防止弹出地址值错误。,(2)保护某些寄存器内容,子程序中要用到某些寄存器, 为了不破坏寄存器中原有的信息,要将需要保护的寄存器 内容入栈,一般安排在子程序开头,用一组PUSH指令, 在子程序结尾处,相应安排一组POP指令,将所保护的寄 存器原来的内容恢复。注意堆栈工作方式为先进后出,所 以要注意PUSH和POP指令组的次序。,(3)主程序与子程序相互之间参数的传递,由于相互之 间可以传递参数才使子程序更灵活,更具有通用性,参数 传递的方法有3种: 1. 用寄存器传递参数:适合于参数较少的场合。,2. 用存储器传递参数:适合参数较多的场合,需要事先 在存储器中建立一个参数表。 3. 用堆栈传递参数:适合参数较多的场合,尤其在子程 序嵌套与递归调用的情况下,比较不容易出错。,下面举例说明参数传递的方式。 例4-75 数据段定义两个数组,编程实现数组段分别求和 (不计溢出) DATA SEGMENT ARY1 DW 100 DUP(?);定义数组1 SUM1 DW ? ARY2 DW 100 DUP(?);定义数组2 SUM2 DW ? DATA ENDS,STACK SEGMENT STACK SA DW 50 DUP(?) TOP EQU LENGTH SA STACK ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA,SS:STACK MAIN PROC FAR START: MOV AX,DATA MOV DS,AX MOV AX,STACK MOV SS,AX MOV SP,TOP LEA SI,ARY1;数组1首地址,入口参数 MOV CX,LEGHTH ARY1;数组1长度, ;入口参数 CALL SUM ;调用求和子程序,LEA SI,ARY2;数组2首地址,入口参数 MOV CX,LENGTH ARY2;数组2长度, ;入口参数 CALL SUM ;调用求和子程序 RET MAIN ENDP SUM PROC NEAR ;SUM子程序 XOR AX,AX ;AX清0 L1: ADD AX,WORD PTRSI ;加数组元素 INC SI INC SI LOOP L1 MOV WORD PTRSI,AX;数组和保存 MOV AH,4CH INT 21H RET ;子程序返回 SUM ENDP,CODE ENDS END START 本例是通过存储器来传递参数的,需要传递的数组的数 保留在存储器中,调用前只需将数组偏移地址放入SI寄存 器,在过程中通过寄存器间接寻址就可取得存储器中的操 作数,运算结果直接由过程写回存储器中,回送给调用程序。,例4-76 通过堆栈传递参数,实现十进制数数组求和, 要求主程序和子程序不在同一代码段中,要进行段间调用。 源程序如下: MDATA SEGMENT ARY1 DB 20 DUP(?);定义数组1 SUM1 DW ?,ARY2 DB 100 DUP(?) ;定义数组2 SUM2 DW ? MDATA ENDS MSTACK SEGMENT STACK SB DW 100 DUP(?) TOP LABEL WORD MSTACK ENDS MCODE SEGMENT ;主程序段 ASSUME CS:MCODE,DS:MDATA,SS:MSTACK MAIN PROC FAR START: MOV AX,MSTACK MOV SS,AX MOV SP,OFFSET TOP;SP指向栈顶 PUSH DS ;为返回DOS作准备 MOV AX,0 PUSH AX MOV AX,MDATA,MOV DS,AX MOV AX,OFFSET ARY1 ;PADD过程 ;入口参数进栈 PUSH AX MOV AX,SIZE ARY1 PUSH AX CALL FAR PTR PADD MOV AX,OFFSET ARY2 PUSH AX MOV AX,SIZE ARY2 PUSH AX CALL FAR PTR PADD RET MAIN ENDP MCODE ENDS PCODE SEGMENT ;过程段,ASSUME CS:PCODE,DS:MDATA,SS:MSTACK PADD PROC FAR ;PADD子程序 PUSH BX ;寄存器保护 PUSH CX PUSH BP MOV BP,SP PUSHF ;标志寄存器入栈 MOV CX,BP+10;数组长度CX(?) MOV BX,BP+12;数组首地址BX MOV AX,0 NEXT: ADD AL,BX ;数组元素相加 DAA MOV DL,AL MOV AL,0 ADC AL,AH DAA MOV AH,AL,MOV AL,DL INC BX LOOP NEXT MOV BX,AX ;保存数组元素之和 POPF POP BP POP CX POP BX RET 4 ;返回作废参数 PADD ENDP PCODE ENDS END START,这是一个用堆栈传递参数,完成段间过程调用的实例, 这里要注意几点:,(1)使用堆栈传递参数,调用前要给过程传递两个参数, 主程序中将数组的偏移地址值及数组长度压入堆栈,然后 调用过程,过程完成数组求和运算。 (2)程序设计要求段间过程调用,因此进入过程时要重新 定义代码段,使之指向当前有效代码段PCODE,在过程运 行中可直接调用堆栈中参数,完成累加运算,并将结果送 到指定的存储单元。 (3)过程返回时用返回指令RET 4,要将堆栈中由CALL 指令之前传递过来的4个字节作废,然后才能返回主程序, 以保证下面过程调用时参数传递正确。 (4)在整个程序运行中,堆栈中数据变化见黑板。,2. 子程序嵌套与递归调用,子程序本身又可调用其他子程序,称为子程序嵌套,嵌 套的层数不限,只要堆栈空间足够就可以。但要注意寄存 器的保护和恢复,避免各层子程序之间寄存器使用冲突, 造成程序出错。图5-12给出了子程序嵌套示意图。,子程序调用子程序本身,称为子程序递归调用。 下面举例说明程序嵌套与递归调用:,例4-X3 已知两个无符号数125和368,求它们的和并将 和转换成十六进制数在屏幕上显示。,DATA SEGMENT P DW 125,368 SUM DW ? DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA MAIN PROC FAR START: PUSH DS MOV AX,0 PUSH AX,MOV AX,DATA MOV DS,AX MOV SI,OFFSET P CALL PADD RET MAIN ENDP PADD PROC NEAR ;两数相加子程序 PUSH AX PUSH BX PUSH CX PUSH DX MOV AX,SI ADD AX,SI+2 MOV SUM,AX CALL DISP ;调用显示子程序 POP DX,POP CX POP BX POP AX RET PADD ENDP DISP PROC NEAR ;显示子程序 MOV BX,SUM MOV CH,4 L1: MOV CL,4 ROL BX,CL MOV AL,BL AND AL,0FH ADD AL,30H ;变成ASCII码 CMP AL,3AH JL L2 ADD AL,07H L2: MOV DL,AL,MOV AH,2 INT 21H DEC CH JNZ L1 RET DISP ENDP CODE ENDS END START 此程序中有两个子程序,其中两数相加子程序中又调用 了显示子程序,实现子程序嵌套。下面看一个子程序递归 调用的例子。,例4-77 要求计算N!(N0),这就是一个递归调用的计算方法, N!=N(N-1)(N-2)1 N!=1,N=0 N!=N(N-1)!,N0 由上面公式知道求N!即为计算N(N-1)!,而 (N-1)!要调用N!子程序,只要将调用参数修改即可。 可以通过堆栈将调用参数、寄存器内容等保护起来,每 调用一次将(N-1)有关信息入栈,直到N=0为止,然后 开始返回,返回时将N乘以(N-1)!,直到N为设置值 为止。,N!子程序说明: ;名称:FACT ;功能:阶乘子程序 ;入口参数:AL=N ;出口参数:DX=N!,ADATA SEGMENT D1 DB 4 ;N=4 D2 DW 2 DUP(?) ;存放运算结果 ADATA ENDS ASTACK SEGMENT PARA STACK STACK SA DW 100 DUP(?) TOP LABEL WORD ASTACK ENDS,ACODE SEGMENT ASSUME CS:ACODE,DS:ADATA,SS:ASTACK MAIN PROC FAR START: MOV AX,ASTACK MOV SS,AX MOV SP,OFFSET TOP;SP指向栈顶 PUSH DS MOV AX,0 PUSH AX MOV AX,ADATA MOV DS,AX MOV DX,0 MOV AH,0 MOV BX,OFFSET D1 MOV AL,BX ;AL=N CALL FACT MOV BX+1,DX,RET MAIN ENDP FACT PROC NEAR;N!子程序 CMP AL,0 JNZ CHN MOV DL,1 ;若N=0,则N!=1 RET CHN: PUSH AX ;N入栈 DEC AL ;N-1 CALL FACT ;递归调用FACT子程序 POP AX ;N弹出 MUL DL ;N(N-1)! MOV DX,AX ;送结果到DX RET FACT ENDP ACODE ENDS END START,五、综合举例,4-6 宏汇编和条件汇编,一、宏汇编,在汇编语言程序设计中,有的程序段要多次使用,除了 以前谈到的过程调用的方法外,还可以用宏汇编的方法实 现,尤其在子程序段本身较短,而传递的参数较多的情况 下,使用宏汇编更加有效。宏是源程序中一段独立的程序 段,首先对它进行定义,然后就可以用宏指令语句多次调 用它了。,1. 宏定义 指令使用前必须先进行宏定义,宏定义格式为:,宏指令名 MACRO 形式参数,形式参数, 宏体 ENDM 宏指令名:宏定义的名字,不可缺省,宏调用时要使用它, 第一个符号必须是字母,其后可以上字母或数字 MACROENDM:宏定义伪指令助记符,不可缺省。它 们成对出现,表示宏定义的开始和结束,ENDM 前不带宏指令名。 宏体:一段有独立功能的程序代码段 形式参数:又称哑元,各个哑元之间用逗号隔开,可以缺 省。,2. 宏调用,经宏定义后的宏指令可以在源程序中调用,宏调用格式 为: 宏指令名 实参,实参 宏调用只需有宏指令名,若宏定义中有形参,那么宏调 用时必须带有实际参数来替代形参,实际参数的个数、顺序 类型与形参一一对应,各个实参之间用逗号隔开。原则上实 参的个数与形参的个数相等,但汇编程序不要求它们必须相 等,若实参个数大于形参个数,则多余的实参不予考虑,若 实参个数小于形参个数,则多余的形参作空处理。,3. 宏展开 汇编程序在对源程序汇编时,对每个宏调用作宏展开, 即用宏定义中的宏体取代宏指令名,并用实参一一对应代 替形参,每条插入的宏体指令前带上加号+。下面举例说 明宏定义、宏调用及宏展开。,例4-83 不带参数的宏定义,用宏指令来实现将AL中内 容右移4位。 宏定义: SHIFT MACRO MOV CL,4 SAR AL,CL ENDM,宏调用: SHIFT 宏展开: +MOV CL,4 +SAR AL,CL,4. 宏调用中参数传递 宏定义中的参数可以有多个,实参可以是数字,寄存 器或操作码。下面分别举例说明:,例4-84 宏定义带一个参数,用宏指令实现将AL中内容 右移任意次(256)。 宏定义: SHIFT MACRO N MOV CL,N,SAR AL,CL ENDM 宏调用1: SHIFT 4 宏调用2: SHIFT 7 宏展开1: +MOV CL,4 +SAR AL,CL 宏展开1: +MOV CL,7 +SAR AL,CL,例4-86 宏定义带3个参数,参数可为操作码,用宏指令 实现对寄存器的内容左移或右移任意次。 宏定义:,SHIFT MACRO N,M,P MOV CL,N S&P M,CL ENDM 宏调用1: SHIFT 3,AX,HR 宏调用2: SHIFT 5,BH,AL 宏展开1: +MOV CL,3 +SHR AX,CL 宏展开2: +MOV CL,5 +SAL BH,CL,宏定义可用部分操作码作参数,但在宏定义体中必须用 &作分隔符,&是一个操作符,它在宏定义体中可作为哑 元的前缀,宏展开时,可以把 &前后两个符号合并成一个 符号。,例4-87 宏定义: SJP MACRO X,Y,Z,W MOV AX,X C&W AX,Y J&Z NEXT ENDM 宏调用: SJP BX,SI,NZ,MP 宏展开: +MOV AX,BX +CMP AX,SI +JNZ NEXT,例4-88 宏定义: SLL MACRO P JMP WA&P ENDM 宏调用: SLL Q 宏展开: +JMP WAQ 如果没有&连接,宏展开成+JMP WAP,汇编程序将 WAP看成一个标号,而不是将P看成一个哑元(形参), 这样程序跳转位置就出错。,5. 宏定义嵌套 在宏定义中允许使用宏调用,但必须先定义后调用。,例4-89 宏定义: DBF MACRO P,Q ;宏定义1 MOV BX,P ADD AX,Q ENDM DBFS MACRO X1,X2,X3 ;宏定义2 PUSH AX PUSH BX DBF X1,X2;调用宏DBF MOV X3,AX POP BX POP AX ENDM,宏调用: DBFS 3AC0H,BX,3AC4H 宏展开: +PUSH AX +PUSH BX +DBF X1,X2;此语句不占内存 +MOV BX,3AC0H ;DBF宏定义展开 +ADD AX,BX +MOV 3AC4H,AX +POP BX +POP AX,下面看一个宏定义的形式参数是另一个宏指令名的例子,例4-90 宏定义: DEFM MACRO MACN,OPER MACN MACRO A,B,C PUSH AX MOV AX,A OPER AX,B MOV C,AX POP AX ENDM ENDM 例中MACN为内层宏定义名,又是外层宏定义的哑

温馨提示

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

评论

0/150

提交评论