ch03 汇编程序设计_第1页
ch03 汇编程序设计_第2页
ch03 汇编程序设计_第3页
ch03 汇编程序设计_第4页
ch03 汇编程序设计_第5页
已阅读5页,还剩71页未读 继续免费阅读

下载本文档

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

文档简介

第三章汇编程序设计

编制汇编语言程序的步骤:(1)分析题意,确定算法(2)根据算法画出程序框图(3)根据框图编写程序(4)上机调试程序分支结构子程序结构程序结构:

复合结构:多种程序结构的组合…

顺序结构循环结构按照指令执行的顺序,程序的结构可以划分成以下三种。

顺序结构:程序按照它编写的顺序执行,每条指令只执行一

次,这样的程序称为“顺序结构”的程序。

循环结构:一组指令被反复地执行,这样的程序称为“循环结

构”或者“重复结构”的程序。

选择结构:根据某个条件,一部分指令被执行,另一部分指

令没有被执行,这样的程序称为“选择结构”或者

“分支结构”的程序。

程序基本结构3.1顺序程序设计顺序程序:没有分支、循环等转移指令,按指令书写的前后顺利依次执行最基本的程序结构完全采用顺序结构编写的程序并不多见例题顺序程序设计实例采用查表法,实现一位16进制数转换为ASCII码显示例数据段;数据段ASCII db30h,31h,32h,33h,34h,35h,36h,37h,38h,39h

;对应0~9的ASCII码

db41h,42h,43h,44h,45h,46h

;对应A~F的ASCII码hex db04h,0bh ;假设两个要显示的数据例代码段

;代码段movbx,offsetASCII ;BX指向ASCII码表moval,hex ;AL取得一位16进制数 ;恰好就是ASCII码表中的位移andal,0fh ;只有低4位是有效的,高4位清0Xlat

;换码:AL←DS:[BX+AL]movdl,al ;入口参数:DL←ALmovah,2 ;02号DOS功能调用int21h ;显示一个ASCII码字符例代码段(续)moval,hex+1 ;转换并显示下一个数据andal,0fhxlatmovdl,almovah,2int21h【例3‑1】将16进制数字转换为对应七段码七段数码管:7段LED发光管通过7个发光段的不同组合,能较好地显示16进制数字(0,…,9,A,b,C,d,E,F)。每一段由一个二进制位控制它的亮或暗。可用一个字节来控制七段数码管的显示。各段顺时针分别称为a、b、c、d、e、f、g,有的产品还附带有一个小数点h,依次对应D0~D7位。假定0表示对应段亮,1表示对应段暗,那么显示数字0对应的控制码应为11000000B,显示数字1对应的控制代码为11111001B,依此类推,显示数字F对应的控制代码为10001110B。这种用于控制七段数码管亮暗的代码就称为七段码。hgfedcbaDSEGSEGMENT

LEDTB DB0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H DB80H,90H,88H,83H,0C6H,0C1H,86H,8EH XDATA DB9 ;要显示的16进制数字

XCODE DB? ;存放要显示数字对应的七段码DSEG ENDSCSEG SEGMENT ASSUMECS:CSEG,DS:DSEGSTART:MOVAX,DSEG MOVDS,AX

MOVBX,OFFSETLEDtb MOVAL,XDATA ;取16进制数字

ANDAL,0FH XLAT ;查表取得对应的七段码

MOVXCODE,AL ;保存

MOVAX,4C00H INT21HCSEG ENDS ENDSTART3.2分支程序设计根据条件是真或假决定执行与否判断的条件:各种指令(如CMP、TEST等)执行后形成的状态标志分支控制:转移指令Jcc和JMP可以实现分支结构有单分支结构双分支结构多分支结构3.2.1单分支结构条件成立跳转,否则顺序执行分支语句体注意选择正确的条件转移指令和转移目标地址【例3-2】求绝对值计算AL中有符号数的绝对值

cmpal,0

jgenonneg

;条件满足(AL≥0),转移

negal

;条件不满足,求补nonneg:

movresult,al

;条件满足

;不恰当的分支

cmpal,0

jlyesneg

;条件满足(AL<0),转移

jmpnonnegyesneg:

negal

;条件满足,求补nonneg:

movresult,al

;条件不满足3.2.2双分支结构条件成立跳转执行第2个分支语句体,否则顺序执行第1个分支语句体注意第1个分支体后一定要有一个JMP指令跳到第2个分支体后【例3-3】显示BX的最高位显示BX的最高位

shlbx,1 ;BX最高位移入CF标志

jcone

;CF=1,即最高位为1,转移

movdl,30h ;CF=0,即最高位为0:DL←30H=‘0’

jmptwo

;一定要跳过另一个分支体one: movdl,31h ;DL←31H=‘1’two: movah,2 int21h ;显示可以用JNC替换JC显示BX的最高位(另解1)

shlbx,1 ;BX最高位移入CF标志

jncone

;CF=0,即最高位为0,转移

movdl,31h ;CF=1,即最高位为1:DL←31H=‘1’

jmptwo

;一定要跳过另一个分支体one: movdl,30h ;DL←30H=‘0’two: movah,2 int21h ;显示转换为单分支结构显示BX的最高位(另解2)

movdl,’0’ ;DL←30H=‘0’ shlbx,1 ;BX最高位移入CF标志

jnctwo

;CF=0,即最高位为0,转移

movdl,’1’

;CF=1,即最高位为1:DL←31H=‘1’two: movah,2 int21h ;显示编写分支程序,需留心分支的开始和结束显示BX的最高位(无分支)

movdl,0 shlbx,1 ;BX最高位移入CF标志

adcdl,30h ;CF=0,DL←0+30h+0=30H=‘0’

;CF=1,DL←0+30h+1=31H=‘1’two: movah,2 int21h ;显示大小写字母转换

;如果DL是一个小写字母,则转换为大写

cmpdl,‘a’ ;小于小写字母a,不需要处理

jbdisp cmpdl,‘z’ ;大于小写字母z,也不需要处理

jadisp

subdl,20h

;是小写字母,则转换为大写disp: ……转换原理大小写字母的比较和转换‘A’=41H=01000001B‘B’=42H…‘Z’=5AH=01011001B‘a’=61H=01100001B‘b’=62H…‘z’=7AH=01111001B结论1:大小写字母的ASCII码值相差20H结论2:大小写字母的ASCII码值仅D5位不同方法1(加减指令):“ADDDL,20H”“SUBDL,20H”方法2(逻辑指令):“ORDL,20H”“ANDDL,0DFH”大小写互换(异或指令):“XORDL,20H”[例3-4]将4位二进制转换成对应的十六进制字符

MOV AL,X CMP AL,9 JA ALPH

ADD AL,30H JMP DONEALPH:

ADD AL,37HDONE: MOV Y,AL

MOV AL,X OR AL,30H CMP AL,‘9’ JBE DONE

ADD AL,7DONE: MOV Y,AL3.2.3多分支结构如果可供选择的程序块多于两个,这样的结构称为多分支选择结构,如下图(a)所示,下图(b)是汇编语言程序的实现方法。【例3‑5】编程实现符号函数:变量X和Y均为数据段中字节变量。

1(X>0)Y=0(X=0)X范围:(-128~+127)-1(X<0)

MOVAL,X CMPAL,0 JGEBIGER

MOVAL,0FFH;X<0,-1送Y单元

JMPOKBIGER:JEOK;X=0,0送Y单元

MOVAL,1;X>0,1送Y单元

OK: MOVY,AL

DATA SEGMENTPROMPT DB 0DH,0AH,“Inputanumber(1~3):$”MSG1 DB 0DH,0AH,“FUNCTION1EXECUTED.$”MSG2 DB 0DH,0AH,“FUNCTION2EXECUTED.$”MSG3 DB 0DH,0AH,“FUNCTION3EXECUTED.$”DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATASTART: MOV AX,DATA MOV DS,AX[例3-6]从键盘上输入数字“1”到“3”,根据输入选择对应程序块执行。INPUT: LEA DX,PROMPT MOV AH,9 INT 21H ;输出提示信息

MOV AH,1 INT 21H ;输入一个数字

CMP AL,‘1’ JB INPUT ;“0”或非数字,重新输入

JE F1 ;数字“1”,转F1 CMP AL,‘2’ JE F2 ;数字“2”,转F2 CMP AL,‘3’ JE F3 ;数字“3”,转F3 JMP INPUT ;大于“3”,重新输入F1: LEA DX,MSG1 ;F1程序块

JMP OUTPUTF2: LEA DX,MSG2 ;F2程序块

JMP OUTPUTF3: LEA DX,MSG3 ;F3程序块

JMP OUTPUTOUTPUT: MOV AH,9 INT 21H

MOV AX,4C00H INT 21HCODE ENDS END START

DATA SEGMENT

PROMPT DB0DH,0AH,“Inputanumber(1~3):$” MSG1 DB0DH,0AH,“FUNCTION1EXECUTED.$” MSG2 DB0DH,0AH,“FUNCTION2EXECUTED.$” MSG3 DB0DH,0AH,“FUNCTION3EXECUTED.$”ADDTBL DWF1,F2,F3DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATA用地址表实现多分支START:MOVAX,DATA MOV DS,AXINPUT:LEA DX,PROMPT MOV AH,9 INT 21H ;显示提示信息

MOV AH,1 INT 21H ;输入一个数字

CMP AL,‘1’ JB INPUT ;不正确输入,重新输入

CMP AL,‘3’ JA INPUT ;不正确输入,重新输入

SUB AL,‘1’ ;将数字字符“1”到“3”转换为0,1,2 SHL AL,1 ;转换为0,2,4 MOV BL,AL MOV BH,0 ;转入BX

JMP ADDTBL[BX] ;相对寻址,转移到对应程序块F1: LEA DX,MSG1 ;F1程序块

JMP OUTPUT F2: LEA DX,MSG2 ;F2程序块

JMP OUTPUTF3: LEA DX,MSG3 ;F3程序块

JMP OUTPUT ;这条指令可以省略OUTPUT: MOV AH,9 INT 21H

MOV AX,4C00H INT 21HCODE ENDS END START3.3循环程序设计

循环结构也称“重复结构”,一般由以下3个部分组成:(1)初始化部分:为循环做准备。 如:累加器清零,设置地址指针和计数器的初始值等。

工作部分:实现循环的基本操作。

修改部分:修改指针、计数器的值,为下一次循环做准备。

控制部分:判断循环条件,确定结束或继续循环。(3)结束部分:用来分析和存放程序的结果。(2)循环体部分两种结构的循环:WHILE循环:先判断循环条件,条件满足则进入循环,循环次数最少为0次。DO-WHILE循环:先执行工作部分,然后判断循环条件,条件满足则转向工作部分继续循环,循环次数最少1次。计数循环:循环的次数事先已知,用一个变量(寄存器或存储 器单元)记录循环的次数(称为“循环计数器”)。条件循环:循环的次数事先并不确定,根据某个条件是否满足 来决定是否继续循环。按照循环结束的条件,有以下两类循环:用循环计数器的值来控制循环,也可以结合其它条件共同控制。[例]从键盘上输入一个字符串(不超过80个字符),将它逆序后输出。DATA SEGMENT BUFFERDB 81,?,81DUP(?) MESS DB 0AH,0DH,“Inputastringplease:”0AH,0DH,“$”DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATASTART:MOV AX,DATA MOV DS,AX LEA DX,MESS MOV AH,09H INT 21H ;输出提示信息

MOV AH,0AH LEA DX,BUFFER INT 21H ;输入字符串

LEA BX,BUFFER ;缓冲区首地址送BX MOV CL,BUFFER+1 MOV CH,0 ;输入字符个数送CX(循环次数) ADD BX,CX

INC BX ;计算字符串末地址送BX(指针)DISP: MOV DL,[BX] MOV AH,02H INT 21H ;逆序输出一个字符

DEC BX ;修改指针

LOOP DISP ;计数循环

MOV AX,4C00H INT 21HCODE ENDS END START【例3-7】字节数组ARRAY存放有10个有符号数,找出最大数送字节变量MAX。DATASEGMENT

ARRAYDB-1,59,23,-45,116,107,159,25,218,-14 MAXDB?

DATAENDS

CODESEGMENT ASSUMECS:CODE,DS:DATASTART:MOVAX,DATA MOVDS,AX

MOVAL,ARRAY ;取数组第一个元素预设为最大数初值

MOVBX,OFFSETARRAY ;设置地址指针初值

MOVCX,9 ;设置比较次数3.3.1计数循环LOOPl:INC

BX

;修改地址指针,指向下一个要比较的数

CMPAL,[BX];比较

JGENEXT

;AL的数较大,直接结束本次比较,采用带符号数转移指令

MOVAL,[BX]

;AL的数较小,将该数置入AL,使AL始终是当前较大值NEXT: LOOPLOOPl

;计数循环控制,cx是否为0

MOVMAX,AL

;比较结束,保存最大值

MOVAX,4C00H INT 21HCODEENDS ENDSTART3.3.2条件循环DATA SEGMENT STRING DB “Astringfortesting.”,0

LENTH DW?DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATASTART:MOV AX,DATA MOV DS,AX[例]字符串STRING以代码0结束,求这个字符串的长度(字符个数)

LEA SI,STRING ;设置地址指针初值

MOV CX,0 ;设置计数器初值TST: CMP BYTEPTR[SI],0;比较

JE DONE ;字符串结束,转向DONE保存结果

INC SI ;修改指针

INC CX ;计数

JMP TST

;转向TST,继续循环DONE: MOV LENTH,CX ;保存结果

MOV AX,4C00H INT 21HCODE ENDS END START

……

LEA SI,STRING-1 ;装载字符串指针

MOV CX,-1

;装载计数器初值TST: INC SI ;修改指针

INC CX ;计数

CMP BYTEPTR[SI],0

;比较

JNE TST ;未结束,转TST继续循环

MOV LENTH,CX ;字符串结束,保存结果

……比较一下,您喜欢这种风格吗?【例3-8】编程完成求1+2+3+…N的累加和,直到累加和超过1000为止。统计被累加的自然数个数送N,累加和送SUM。假定N和SUM为已定义的字变量。DATASEGMENT

SUMDW?NDW?DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATASTART:MOVAX,DATAMOVDS,AX;设置DS

MOVAX,0;累加器AX清0

MOVBX,0;BX统计累加自然数个数,清0

LP:

INCBX;BX加1

ADDAX,BX;求累加和

CMPAX,1000;比较累加和是否大于1000

JBELP;≤1000转,继续累加

MOVSUM,AX;否则结束累加,保存累加和

MOVN,BX;保存累加的自然数个数

MOVAX,4C00HINT21H;返回DOSCODEENDSENDSTART;汇编结束【例3-9】统计BX寄存器中1的个数,并将结果存放在DL寄存器中。方法一:条件循环

MOVAX,BX XORDL,DL

L: ANDAX,AX

;测试AX中的数据是否为0,形成循环判断条件

JZEXIT

;循环控制

SALAX,1

;循环体:实现一次统计。将AX中的最高位移入CF中

JNCL

;如果CF=0,转L

INCDL

;如果CF=1,则(DL)+1→DL

JMPL

;转L处继续循环

EXIT: …方法二:计数循环

MOVAX,BX MOVCX,16 XORDL,DLNEXT:SALAX,1

;循环体:实现一次统计。

;将AX中的最高位移入CF中

JNCL

;如果CF=0,转L处结束本次循环

INCDL;如果CF=1,则(DL)+1→DL

L:

LOOPNEXT

;循环控制:CX减1,判断CX是否为0,不是0则循环EXIT: …DATA SEGMENT POSITION DW ? STRING DB “Thisisastringforexample.”,0DATA ENDSCODE SEGMENT ASSUME DS:DATA,CS:CODESTART:MOV AX,DATA MOV DS,AX

[例]查找字母’a’在字符串STRING中第一次出现的位置,如果未出现,置位置值为-1。 MOV SI,-1 ;SI用作字符串字符指针

MOV CX,30 ;字符串长度30L0: INC SI

;修改指针

CMP STRING[SI],‘a’ ;一个字符与’a’进行比较

LOOPNE L0 ;字符串未结束,未找到,继续

JNE NOTFOUND ;未找到,转“NOTFOUND”

MOV POSITION,SI ;保存位置值

JMP EXITNOTFOUND:MOV POSITION,-1 ;未找到,置位置值为-1EXIT: MOV AX,4C00H INT 21HCODE ENDS END START

字符串内找到字符’a’:循环结束时ZF=1,SI内是字符的出

现位置(从0开始);字符串内未找到字符’a’:循环结束时ZF=0,SI内是字符串

的长度-1(30-1=29)。程序使用LOOPNE指令来控制循环,既有计数控制,又有条件控制。循环结束有两种可能性:3.3.3多重循环如果一个循环的循环体内包含了另一个循环,称这个循环为“多重循环”,各层循环可以是计数循环或者条件循环。例:在多重循环的程序结构中,CX计数器的保存和恢复

MOVCX,MAGAIN:

……

PUSHCXMOVCX,NNEXT:……LOOPNEXT……

POPCX

LOOPAGAIN

MOVDI,MAGAIN:……MOVCX,NNEXT:……LOOPNEXT

……

DECDIJNZAGAIN【例3-10】有符号字节元素数组存有N个有符号数,要求将这N个数由小到大排列。DATA SEGMENT

ARRAY1DB 15H,0A7H,34H,55H,90H,7EH,3CH,25H,56H,0D6H N EQU$-ARRAY1DATA ENDSCODE SEGMENT ASSUME CS:CODE,DS:DATASTART: MOV AX,DATA MOV DS,AX ;***********开始排序***************

MOV CX,N-1

;设置外层循环计数器,CX中为排序的“遍数”(N-1);===================外层循环循环体开始=============LOOP1:PUSH CX ;保存外循环计数器

MOV BX,0

;BX=整序元素在数组内的位移,每一遍从第一个元素开始;-------内层循环循环体开始,CX的值是内层循环的次数------LOOP2:MOVAL,ARRAY1[BX] CMPAL,ARRAY1[BX+1] ;邻元素比较

JLENEXT ;不需要整序,转NEXT

XCHGAL,ARRAY1[BX+1] ;交换邻元素位置

XCHGAL,ARRAY1[BX]NEXT:

INC BX ;修改指针

LOOP LOOP2 ;本遍未结束,转LOOP2继续;----------内层循环循环体结束---------------

POP CX ;恢复外层循环计数器

LOOP LOOP1 ;“遍数”未满,转LOOP1继续;=============外层循环循环体结束================ MOV AX,4C00H INT 21HCODE ENDS END START【例3-11】有4名学生参加5门课程的考试,试计算每个学生的平均成绩和每门课的平均成绩。DATASEGMENT

GRADEDB80,95,76,83,92DB65,81,78,84,78DB90,86,96,100,83DB79,69,88,73,56 STUDB4DUP(?)

COURSEDB5DUP(?)DATAENDS

CODESEGMENT

ASSUMECS:CODE,DS:DATASTART:MOVAX,DATA MOVDS,AX

;*****************求每个学生的平均成绩****************

MOVDI,4;设置外层循环计数器,DI中为学生人数

LEABX,GRADE;设置地址指针,BX指向成绩表GRADELEASI,STU;设置地址指针,SI指向学生平均分表STU;===================外层循环循环体开始=============

L11:MOVAX,0;累加器清0

MOVCX,5;设置内层循环计数器,CX中为课程数;-----------------内层循环循环体开始----------------

L22:ADDAL,[BX]ADCAH,0;累加,考虑可能的进位

INCBX;修改地址指针

LOOPL22;内层循环控制;------内层循环循环体结束,AX中为某学生5门课总成绩-----

MOVDL,5DIVDL;求平均值,保存在AL中

MOV[SI],AL;保存平均值

INCSI;修改地址指针

DECDI;修改外层循环计数值DIJNZL11;外层循环控制;===================外层循环循环体结束=============;**************以下为求每门课的平均成绩**************

LEADI,GRADE;设置地址指针,DI指向成绩表GRADELEASI,COURSE;设置地址指针,SI指向课程平均分表COURSE;MOVDI,BXMOVCX,5;设置外层循环计数器,CX中为课程数;===================外层循环循环体开始=============

L01:PUSHCX;外层循环计数值CX入栈保护

MOVBX,DI;设置内层循环地址指针

MOVAX,0;累计器清0MOVCX,4;设置内曾循环计数器,CX中为学生数;-----------------内层循环循环体开始----------------

L02:ADDAL,[BX]ADCAH,0;累加,考虑可能的进位

ADDBX,5;修改地址指针,指向下一个学生本课程地址

LOOPL02;内层循环控制;----内层循环循环体结束,AX中为某门课4名学生的总成绩----MOVDL,4DIVDL;求课程平均成绩,在AL中

MOV[SI],AL;保存课程平均成绩

INCSI;修改外层循环COURSE表地址指针

INCDI;修改外层循环GRADE表地址指针

POPCX;恢复外层循环计数值

LOOPL01;外层循环控制;===================外层循环循环体结束=============

MOVAX,4C00HINT21HCODEENDSENDSTART3.4子程序设计

子程序名 PROC [NEAR/FAR]

PUSH …… ;保护现场(寄存器/存储器)

PUSH …… ;个数根据具体情况决定

…… ;子程序主体

……

POP …… ;恢复现场,注意出栈次序

POP …… ;先进栈的寄存器后出栈

RET ;返回

子程序名

ENDP子程序的基本格式设计一个子程序之前,首先应该明确:子程序的名字;子程序的功能;入口参数:主程序调用子程序时,提供给子程序的参数出口参数:子程序执行结束返回给主程序的参数影响寄存器:执行这个子程序会改变哪几个寄存器的值?其它需要说明的事项。上述内容连同子程序源代码等合称为“子程序文件”。常常把上述内容以“程序注释”的方式书写在一个子程序的首部。;名称:Square;功能:求16Bit无符号数的平方根;入口参数:16Bit无符号数在AX中;出口参数:8Bit平方根数在AL中;影响寄存器:AX(AL)例3-12,一个名为“SQUARE”的子程序,用来求一个数的平方根,源程序如下:SQUARE PROC NEAR PUSH CX ;保护现场

PUSH BX

MOV BX,AX ;要求平方根的数送BX MOV AL,0 ;AL中存放平方根,初值0 MOV CX,1 ;CX置入第一个奇数1

;利用公式:N2=1+3+……+(2N-1)求平方根NEXT: SUB BX,CX JB DONE ADD CX,2 ;形成下一个奇数

INC AL ;AL存放已减去奇数的个数

JMP NEXTDONE: POP BX ;恢复现场

POP CX RET ;返回SQUARE ENDP子程序应用每调用一次子程序,主程序需要做三件事:(1)为子程序准备入口参数(2)调用子程序(3)处理子程序的返回参数DATA SEGMENTX DW 59,3500,139,199,77;欲求平方根的数组ROOT DB 5DUP(?)

;存放平方根内存区DATA ENDSCODE SEGMENT ASSUME CS:CODE,DS:DATASTART:MOV AX,DATA MOV DS,AX[例3-12]

求5个无符号数的平方根,主程序如下:

LEA BX,X ;初始化指针

LEA SI,ROOT MOV CX,5 ;设置计数器初值ONE: MOV AX,[BX] ;设置入口参数

CALL SQUARE ;调用子程序

MOV [SI],AL ;保存返回参数(平方根)

ADD BX,2 ;修改指针

INC SI ;修改指针

LOOP ONE ;循环控制

MOV AX,4C00H ;返回DOS INT 21H

主程序部分;名称:Square;功能:求16Bit无符号数的平方根;入口参数:16Bit无符号数在AX中;出口参数:8Bit平方根数在AL中;影响寄存器:AX(AL)SQUARE PROC NEAR PUSH CX ;保护现场

PUSH BX

MOV BX,AX ;要求平方根的数送BX MOV AL,0 ;AL中存放平方根,初值0 MOV CX,1 ;CX置入第一个奇数1

;利用公式:N2=1+3+……+(2N-1)求平方根NEXT:

SUB BX,CX JB DONE ADD CX,2 ;形成下一个奇数 INC AL ;AL存放已减去奇数的个数 JMP NEXTDONE: POP BX ;恢复现场 POP CX RET ;返回SQUARE

ENDPCODE ENDS

END

START子程序安排在主程序执行终止返回DOS后的位置子程序编写注意事项⑴子程序要利用过程定义伪指令声明⑵子程序最后利用RET指令返回主程序,主程序执行CALL指令调用子程序⑶子程序中对堆栈的压入和弹出操作要成对使用,保持堆栈的平衡⑷子程序开始应该保护使用到的寄存器内容,子程序返回前相应进行恢复⑸子程序应安排在代码段的主程序之外,最好放在主程序执行终止后的位置(返回DOS后、汇编结束END伪指令前),也可以放在主程序开始执行之前的位置子程序编写注意事项⑹子程序可以与主程序共用一个数据段,也可以使用不同的数据段(注意修改DS),还可以在子程序最后设置数据区(利用CS寻址)⑺子程序允许嵌套和递归⑼处理好子程序与主程序间的参数传递问题⑽提供必要的子程序说明信息【例3-13】含数据区的子程序;子程序HTOASC:将AL低4位表示的十六进制数转换为ASCII码HTOASC proc pushbx movbx,offsetASCII andal,0fh xlatCS:ASCII

;换码:AL←CS:[BX+AL] popbx

ret;数据区ASCII db30h,31h,32h,33h,34h,35h,36h,37h,38h,39h db41h,42h,43h,44h,45h,46hHTOASC endp【例3-14】

子程序嵌套示例,本例中子程序嵌套调用了例3-13子程序HTOASC。;入口参数:AL中为要显示输出的二进制数ALDISPPROC

PUSHAX;保护入口参数PUSHCX

PUSHAX;暂存数据

MOVCL,4SHRAL,CL;转换AL的高4位

CALLHTOASC;子程序调用(嵌套)

POPAX;转换AL的低4位

CALLHTOASC;子程序调用(嵌套)POPCXPOPAXRET;子程序返回ALDISPENDP【例3-15】子程序递归调用示例。编程计算N!,N!=N×(N-1)×(N-2)×…×2×1(N≥0)DATASEGMENT

NDW3 RESULTDW? ;保存结果DATAENDSCODESEGMENT ASSUMECS:CODE,DS:DATASTART:MOVAX,DATA MOVDS,AX

PUSHN ;入口参数N入栈

CALLFACT ;子程序FACT调用,求N!

POPRESULT ;出口参数弹出至RESULT MOVAX,4C00H ;返回DOS INT21H主程序部分;入口参数:N压入堆栈(采用堆栈传递参数);出口参数:N!值在栈顶FACTPROC

PUSHAX PUSHBP PUSHDX

MOVBP,SP MOVAX,[BP+8] ;从堆栈中取入口参数

CMPAX,0 ;比较入口参数是否为0

JNEFACT1 ;不为0,则转递归调用控制

INCAX ;如果为0,设置出口参数为0!=1

JMPFACT2子程序部分FACT1:DECAX ;设置求(N-1)!的入口参数值

PUSHAX ;入口参数入栈

CALLFACT ;递归调用,求(N-1)!

POPAX ;出口参数弹出至AX

MULWORDPTR[BP+8] ;求(N)!=N×(N-1)!FACT2:MOV[BP+8],AX

;设置出口参数,假定N!不会超出AX的表示范围 POPDX POPBP POPAX

RETFACTENDPCODEENDS ENDSTART子程序部分多出口子程序;子程序HTOASC:将AL低4位表示的十六进制数转换为ASCII码HTOASC proc andal,0fh cmpal,9 jbehtoasc1 addal,37h ;是A~F,加37H ret ;子程序返回htoasc1: addal,30h ;是0~9,加30H

ret ;子程序返回HTOASC endp子程序的参数传递主程序与子程序间一个主要问题是参数传递入口参数(输入参数):主程序调用子程序时,提供给子程序的参数出口参数(输出参数):子程序执行结束返回给主程序的参数参数的具体内容传数值:传送数据本身传地址:传送数据的主存地址常用的参数传递方法寄存器共享变量堆栈1.用寄存器传递参数最简单和常用的参数传递方法是通过寄存器,只要把参数存于约定的寄存器中就可以了由于通用寄存器个数有限,这种方法对少量数据可以直接传递数值,而对大量数据只能传递地址采用寄存器传递参数,注意带有出口参数的寄存器不能保护和恢复,带有入口参数的寄存器可以保护、也可以不保护,但最好能够保持一致2.用共享变量传递参数子程序和主程序使用同一个变量名存取数据就是利用共享变量(全局变量)进行参数传递如果变量定义和使用不在同一个源程序中,需要利用PUBLIC、EXTRN声明如果主程序还要利用原来的变量值,则需要保护和恢复利用共享变量传递参数,子程序的通用性较差,但特别适合在多个程序段间、尤其在不同的程序模块间传递数据3.用堆栈传递参数参数传递还可以通过堆栈这个临时存储区。主程序将入口参数压入堆栈,子程序从堆栈中取出参数;子程序将出口参数存入堆栈,主程序弹出堆栈取得它们采用堆栈传递参数是程式化的,它是编译程序处理参数传递、以及汇编语言与高级语言混合编程时的常规方法【例3-16】编程采用子程序结构实现数组元素求和DATASEGMENT

ARY1DW1,2,3,4,5,6,7,8,9,10COUNT1DW($-ARY1)/2 ;ARY1元素个数

SUM1DW?DATAENDS入口参数: 数组的逻辑地址(传址) 元素个数(传值)出口参数: 求和结果(传值)

;设置入口参数(含有DS←数组的段地址)

MOVBX,OFFSETARY1 ;BX←数组的偏移地址

MOVCX,COUNT1 ;CX←数组的元素个数

CALLPROADD1 ;调用求和子程序

MOVSUM1,AX ;处理出口参数

主程序1、通过寄存器传递参数;子程序名:PROADD1;功能:求字数组各元素之和;入口参数:

DS:BX=数组的段地址:偏移地址

CX=元素个数,

;出口参数:

AX=数组元素和;影响寄存器:AX子程序PROADD1PROC

PUSHCX

PUSHBX

XORAX,AX ;累加器清0

SUMA:

ADDAX,[BX] ;求和

INCBX;修改地址指针,指向下一个数据

INCBX

LOOPSUMA

POPBX POPCX

RETPROADD1ENDPdatasegmentary1dw1,2,3,4,5,6,7,8,9,10count1dw($-ARY1)/2sum1dw?ary2dw10,20,30,40,50,60,70,80,90,100count2dw($-ARY2)/2sum2dw?dataends2.通过共享变量传递参数datasegmentary1dw1,2,3,4,5,6,7,8,9,10count1dw($-ARY1)/2sum1dw?

ary2dw10,20,30,40,50,60,70,80,90,100count2dw($-ARY2)/2sum2dw?

tabledw3dup(?);地址表dataends累加数组中的元素(地址表)codesegmentassumecs:code,ds:datastart:pushdssubax,axpushaxmovax,datamovds,ax

movtable,offsetary1movtable+2,offsetcoun

温馨提示

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

评论

0/150

提交评论