Transcript 的简化编程结构
第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 MASM简化编程结构 简化编程结构应用举例 [例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 [例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 子程序设计方法 例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 子程序设计方法 子程序的调用与返回 过程的调用与返回分别由指令CALL和RET来完成。 子程序执行期间应注意维持堆栈使用的平衡。当 发生CALL过程调用时,返回地址入栈;而运行 RET指令时,则由栈顶取出返回地址。 CALL指令执行分成两步;第一步,保护返回地址 (CALL指令下一条指令的地址),利用堆栈实现, 即将返回地址压入堆栈;第二步,转向子程序, 即把子程序的首地址送入IP或CS:IP。 子程序的现场保护与恢复 在子程序设计中,另一个非常重要的问题就是CPU内 部寄存器内容的保护和恢复。在运行主程序时已经占 用了一定数量的寄存器,子程序执行时也要使用寄存 器。子程序执行完返回主程序后,要保证主程序按原 来状态继续执行,这就需要对那些在主程序和子程序 中都要使用的寄存器的内容在子程序体执行之前加以 保护,这就称为保护现场。 子程序执行完再恢复这些主程序中寄存器的内容,称 为恢复现场。为了使程序结构清晰,一般在子程序中 完成现场保护和现场恢复。所以子程序设计时必须注 意寄存器的保护与恢复。又因CPU的可用寄存器数量 有限,为了解决寄存器使用中的冲突问题,一般利用 堆栈实现现场保护和恢复。注意:现场保护和恢复一 定要注意参数的入栈和出栈次序。 8.3 子程序设计应用举例 RET [例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 ;调用子程 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 习题-简答、编程 1.简述子程序的调用与返回过程。 2.编写程序,计算S=2+4+6+…+200 3.编写一个子程序,实现大小写字母互换。要转换的字 符串在STRING内的。 4.试按如下子程序说明编程。 ① 子程序功能。把用ASCⅡ码表示的两位十进制数转换 成二进制数; ② 入口参数。DH=十位数的ASCⅡ码,DH=个位数的 ASCⅡ码; ③ 出口参数。AL=对应的二进制数。 6.编写一个子程序利用XLAT指令把十六进制数转换成 ASCⅡ码。假设ASCⅡ码存放在以DAT1为首地址的数据 区中,对应的16进制数放在以DAT2为首地址的数据区中, 转换结果送以DAT3为首地址的数据区中。