150 likes | 366 Views
第 8 章 子程序设计. 本章重点: 理解 MASM 汇编程序的简化编程结构 . 掌握过程的定义、调用和返回,了解程序调用时必须解决的一些问题 . 掌握过程调用时参数的正确传递,合理使用堆栈并维持其平衡,能通过寄存器或变量实现过程间的参数传递并进行子程序程序设计。. 8.1 MASM (宏汇编)的简化编程结构. 简化的段定义源程序的格式为: . MODEL SMALL ;定义程序的存储模式 ( 一般为 SMALL) . STACK ;定义堆栈段 . DATA ;定义数据段 ... ;数据定义
E N D
第8章 子程序设计 • 本章重点:理解MASM汇编程序的简化编程结构. • 掌握过程的定义、调用和返回,了解程序调用时必须解决的一些问题. • 掌握过程调用时参数的正确传递,合理使用堆栈并维持其平衡,能通过寄存器或变量实现过程间的参数传递并进行子程序程序设计。
8.1 MASM(宏汇编)的简化编程结构 • 简化的段定义源程序的格式为: • .MODEL SMALL ;定义程序的存储模式(一般为SMALL) • .STACK ;定义堆栈段 • .DATA ;定义数据段 • ... ;数据定义 • .CODE ;定义代码段 • .STARTUP ;程序开始点并确定DS,SS,SP的值 • ... ;程序代码 • .EXIT 0 ;程序结束返回DOS • ... ;子程序代码 • END ;汇编结束语句
[例8.1.1]:在屏幕的当前行上显示‘HOW ARE YOU!’ ·MODEL SMALL ·STACK ·DATA BUFF DB ‘HOW ARE YOU!’,0DH,0AH,‘$’ ·CODE ·STARTUP LEA DX,BUFF MOV AH,09H ;显示字符串 INT 21H ·EXIT 0 END
8.1.1 简化段定义伪指令 • (1)代码段定义:.CODE[段名] 表明其下面的内容是代码段中的内容。若没有给出段名,则采用默认段名。 • (2)堆栈段定义:.STACK[堆栈区大小] 定义一个堆栈,段名为STACK。其中‘堆栈区大小’可不写(默认为1KB)。 • (3)数据段定义:.DATA 表明其下面的内容是在数据段中的变量定义。.DATA用于创建一个数据段,段名是‘_DATA’。 • (4)程序开始伪指令:.STARTUP 它能按照给定CPU类型,依据.MODEL语句选择的存储模式、操作系统和堆栈类型,生成程序初始代码,并指定程序入口位置;一般选DOS方式的SMALL模式,它将初始化DS,并调整SS和SP的值。 • (5)返回系统的伪指令:.EXIT[返回数码] 它能产生终止程序执行,并返回DOS操作系统的指令代码。通常用0表示没有错误,.EXIT 0对应代码为: MOV AX,4C00H INT 21H
简化编程结构应用举例 [例8.1.2]:试用简化段定义格式设计一个按任意键后响铃的COM程序。 解:参考源程序如下. ·MODEL SMALL ·CODE ·STARTUP LEA DX,BUFF MOV AH,09H ;显示提示信息 INT 21H MOV AH,01H ;等待按键 INT 21H MOV AH,02H MOV DL,7 ;响铃一次 INT 21H ·EXIT 0 ;程序结束返回DOS BUFF DB ‘Press any key!’,0DH,0AH,‘$’ END MASM简化编程结构
[例8.1.3]:编写程序,把一个16位无符号的二进制数转换成十进制数,并显示出来。[例8.1.3]:编写程序,把一个16位无符号的二进制数转换成十进制数,并显示出来。 分析:采用计数控制法设计程序。我们知道,不管用哪种进制表示,一个数的大小是不变的。假如‘926’这个十进制数(=39EH),应先得到百位上的数字‘9’后显示在屏幕上,怎样得到百位数呢?可以用926除以100的商得到百位上的‘9’,依次类推。转换成ASCⅡ码后调用DOS的2号功能,就显示出来了。16位无符号二进制数对应的十进制数范围是0~65535。该数除以10000的商得到万位,余数除以1000的商得到千位,余数除以100的商为百位,余数除以10的商为十位,最后的余数为个位。
解:参考源程序如下 .MODEL SMALL .STACK .DATA BINBUF DW 926DH ;定义被除数(16位无符号二进制数) QUVAR DW 10000,1000,100,10 ;定义除数 .CODE .STARTUP MOV AX,BINBUF ;取被除数 MOV DX,0 ;DX清0 MOV CX,04H ;置计数器初值 MOV SI,OFFSET QUVAR ;置地址指针 LOP1: DIV WORD PTR [SI] ;进行32位除以16位的除法 MOV BX,DX
.IF AX!=0 MOV DL,AL ;显示万位、千位、百位、十位 ADD DL,30H MOV AH,2 INT 21H .ENDIF INC SI INC SI ;修改地址指针 MOV AX,BX MOV DX,0 LOOP NEXT MOV DX,BX ;循环结束处理,显示个位数 ADD DL,30H MOV AH,2 INT 21H .EXIT 0 END
8.2 子程序设计方法 • 8.2.1 子程序的定义、调用与返回 • 1、过程定义语句PROC和ENDP • 在程序设计中,可将具有一定功能的程序段看成为一个过程(相当于一个子程序),它可以被别的程序调用。一个过程由伪指令PROC和ENDP来定义,其格式为: • 过程名 PROC [NEAR/FAR] • 过程体 • RET • 过程名 ENDP
8.2.1 子程序的定义、调用与返回 其中过程名是为过程所起的名称,不能省略,NEAR/FAR定义了过程的属性,NEAR属性的过程,只能被同代码段的程序调用(称段内近调用);FAR属性的过程,只能被不同代码段的程序调用(称为段间远调用)。如果缺省类型,则该过程就默认为近过程。ENDP表示过程结束。过程体内至少应有一条RET指令,以便返回被调用处。过程可以嵌套,也可以递归使用。
例8.2.1]:一个延时100ms的子程序,其过程可定义如下,例8.2.1]:一个延时100ms的子程序,其过程可定义如下, DELAY PROC NEAR ;定义子程序DELAY PUSH BX PUSH CX MOV BL,10 ;延时10ms,改变BL和CX中的值,即可改变延时时间。 AGAIN:MOV CX,2801 WAIT: LOOP WAIT DEC BL JNZ AGAIN POP CX POP BX RET DELAY ENDP CALL DELAY ;调用该过程 远过程调用时被调用过程必定不在本段内。例如,有两个程序段,其结构如下: CODE1 SEGMENT ;定义代码段CODE1 ASSUME CS:CODE1 FARPROC PROC FAR RET FARPROC ENDP CODE1 ENDS CODE2 SEGMENT ;定义代码段CODE2 ASSUME CS:CODE2 CALL FARPROC ... CODE2 ENDS CODE1 段中的FARPROC 过程被另一段CODE2调用,故为远过程。 8.2 子程序设计方法
8.2 子程序设计方法 子程序的调用与返回 • 过程的调用与返回分别由指令CALL和RET来完成。子程序执行期间应注意维持堆栈使用的平衡。当发生CALL过程调用时,返回地址入栈;而运行RET指令时,则由栈顶取出返回地址。 • CALL指令执行分成两步;第一步,保护返回地址(CALL指令下一条指令的地址),利用堆栈实现,即将返回地址压入堆栈;第二步,转向子程序,即把子程序的首地址送入IP或CS:IP。
子程序的现场保护与恢复 • 在子程序设计中,另一个非常重要的问题就是CPU内部寄存器内容的保护和恢复。在运行主程序时已经占用了一定数量的寄存器,子程序执行时也要使用寄存器。子程序执行完返回主程序后,要保证主程序按原来状态继续执行,这就需要对那些在主程序和子程序中都要使用的寄存器的内容在子程序体执行之前加以保护,这就称为保护现场。 • 子程序执行完再恢复这些主程序中寄存器的内容,称为恢复现场。为了使程序结构清晰,一般在子程序中完成现场保护和现场恢复。所以子程序设计时必须注意寄存器的保护与恢复。又因CPU的可用寄存器数量有限,为了解决寄存器使用中的冲突问题,一般利用堆栈实现现场保护和恢复。注意:现场保护和恢复一定要注意参数的入栈和出栈次序。
[例8.3.2]:编写一个程序,累加数组中的元素,并将和存入SUM单元。[例8.3.2]:编写一个程序,累加数组中的元素,并将和存入SUM单元。 分析:编制一个字节的加法子程序,然后对其进行调用。 解:采用完整的段定义格式来编写程序。程序清单如下: DATA SEGMENT ;定义数据段 ARY DW 1,2,3,4,5,6,7,8,9,10 COUNT DW 10 SUM DW ? DATA ENDS CODE SEGMENT MAIN PROC FAR ASSUME CS:CODE,DS:DATA START: PUSH DS SUB AX,AX PUSH AX MOV AX,DATA MOV DS,AX CALL PROADD ;调用子程序 RET MAIN ENDP;出口参数:[SUM] PROADD PROC NEAR ;完成一个字节相加 PUSH AX ;保护现场 PUSH CX PUSH SI LEA SI,ARY MOV CX,[COUNT] ;循环初值 XOR AX,AX NEXT: ADD AX,[SI] ADD SI,2 LOOP NEXT MOV [SUM],AX POP SI ;恢复现场 POP CX POP AX RET PROADD ENDP CODE ENDS END START 8.3 子程序设计应用举例
习题-简答、编程 • 1.简述子程序的调用与返回过程。 • 2.编写程序,计算S=2+4+6+…+200 • 3.编写一个子程序,实现大小写字母互换。要转换的字符串在STRING内的。 • 4.试按如下子程序说明编程。 • ① 子程序功能。把用ASCⅡ码表示的两位十进制数转换成二进制数; • ② 入口参数。DH=十位数的ASCⅡ码,DH=个位数的ASCⅡ码; • ③ 出口参数。AL=对应的二进制数。 • 6.编写一个子程序利用XLAT指令把十六进制数转换成ASCⅡ码。假设ASCⅡ码存放在以DAT1为首地址的数据区中,对应的16进制数放在以DAT2为首地址的数据区中,转换结果送以DAT3为首地址的数据区中。