的简化编程结构

Download Report

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为首地址的数据区中。