![汇编语言第七章_第1页](http://file4.renrendoc.com/view/1feff81efd52f473fad43ceaeee9ab93/1feff81efd52f473fad43ceaeee9ab931.gif)
![汇编语言第七章_第2页](http://file4.renrendoc.com/view/1feff81efd52f473fad43ceaeee9ab93/1feff81efd52f473fad43ceaeee9ab932.gif)
![汇编语言第七章_第3页](http://file4.renrendoc.com/view/1feff81efd52f473fad43ceaeee9ab93/1feff81efd52f473fad43ceaeee9ab933.gif)
![汇编语言第七章_第4页](http://file4.renrendoc.com/view/1feff81efd52f473fad43ceaeee9ab93/1feff81efd52f473fad43ceaeee9ab934.gif)
![汇编语言第七章_第5页](http://file4.renrendoc.com/view/1feff81efd52f473fad43ceaeee9ab93/1feff81efd52f473fad43ceaeee9ab935.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
xdw110,120,130,140,150,160,170,180,190,200ydw?………..
…………..MOVAX,XMOVBX,OFFSETXMOVCX,9L1:INCBXINCBXCMPAX,[BX]JAEL2XCHGAX,[BX]L2:LOOPL1MOVY,AX此程序段完成什么功能复习16.4.2多重循环程序设计【例6.5】在以BUF为首址的字存储区中存放N个有符号数,现需将它们按大到小的顺序排列在BUF存储区中,试编写其程序。
采用冒泡排序算法从第一个数开始依次对相邻两个数进行比较,如次序对,则不交换两数位置;如次序不对则使这两个数交换位置,则第一遍比较后最小值排到最后.2冒泡法的排序过程序号数比较遍数1234132285316415583216158851615832851581632858151632853程序如下:DATA SEGMENTBUF DW32,85,16,15,8DATA ENDSCODE SEGMENTASSUMECS:CODE,DS:DATA4START: MOV AX,DATA MOV DS,AX MOV CX,5;元素个数 DEC CX
;比较遍数LOOP1: MOVDX,CX;保存外循环的循环次数也可以做内循环计数(比较次数)
MOV BX,0LOOP2:
MOVAX,BUF[BX];相邻两数比较CMPAX,BUF[BX+2]JGE LXCHGAX,BUF[BX+2];大数放AXMOVBUF[BX],AX;并将大数送相应单元5L:ADD BX,2;进下一个单元,准备取下一个数Looploop2
MOV CX,DX;恢复外循环次数
LOOP LOOP1MOV AH,4CHINT 21HCODE ENDS END START思考:外循环次数还可用什么指令处理?6上机:编写打印如下图形程序(yhsj)01021032104321054321065432107654321087654321098765432107第7章子程序设计 为了程序共享或模块化设计的需要,可以把一段公共语句序列设计成子程序(也叫过程)或宏指令的形式。8(一)子程序结构子程序结构 在汇编语言中用过程定义伪指令定义子程序。过程定义伪指令格式: 过程名 PROC属型 ┇过程名 ENDP9 其中过程名就是子程序名,它也表示子程序入口的符号地址。属型可以是NEAR型(缺省值)或FAR型。NEAR型子程序只可以被段内调用,FAR型子程序可以被段间或段内调用。10(1).调用指令:格式:CALLPROC_NAME功能:把断点地址(主程序中下一条指令地址)压入堆栈进行保护,无条件转到目标地址执行子程序。(2).返回指令:格式:RET[N]功能:从栈顶弹出返回地址送IP,并返回到主程序中去继续执行。dos演示call演示ret演示111.调用程序和子程序在同一个代码段的程序结构
CODE SEGMENT …
CALL SUB1 …
SUB1
PROC [near] … RET
SUB1
ENDP
CODE ENDS122.调用程序和子程序在不同段的程序结构(SUB2被段间调用,必须是FAR属性。CALL要显式说明是FAR属性)CODE1 SEGMENT
…CALL FARPTRSUB2CODE1 ENDS
CODE2 SEGMENTSUB1 PROC
CALLSUB2
…SUB1 ENDPSUB2PROC FAR … RETSUB2 ENDPCODE2 ENDS13寄存器的保存与恢复
应在子程序开头保存它要用到的寄存器内容,返回前再恢复它们。
通常用PUSH指令保存,用POP恢复。(二)、设计子程序时应注意的问题14SUB1PROC;****
PUSH CX
PUSH SI PUSHF …… …… …… POPF
POP SI
POP CX RETSUB1ENDP15密切注意堆栈状态
注意一切与堆栈有关的操作。例如:CALL调用类型和子程序定义类型的一致性。PUSH和POP指令的匹配。通过堆栈传递参数时子程序返回使用RETn指令等。确保堆栈平衡,否则后果不可预料。16datasegmentstring1db"howdowyoudo!",0dh,0ah,"$"dataendscodesegmentassumestart:movax,datamovds,ax
lop1:movdx,offsetstring1movah,4chint21hdspprocnear
dspendpCodeendsendstart填空177.5子程序的参数传递1.寄存器传递参数。
最常用,用寄存器作为入口参数或出口参数。
适用传递少量参数.(howdoyou.asm)2.通过地址表(存储器)传递参数地址。
安排数据区时,必须留出传递参数的位置。
适用传递大量参数.3.堆栈传递参数或参数地址。
将参数入栈,子程序从堆栈中取数据.
适用参数多,子程序嵌套及递归.18(四)举例说明子程序参数传递191.通过寄存器传递
这种传递方式使用方便,适用于参数较少的情况。
例7.9.把BX中的16位二进制数转换成十进制并显示在屏幕上。 分析:本例采用从高到低逐个除以十进制位权的方法。20STASG SEGMENT DW32DUP(?)STASG ENDSCODE SEGMENT ASSUMECS:CODE,ss:stasgMAIN PROCFAR MOVBX,162EH
CALLTERN MOVAX,4C00H INT21HMAIN ENDP程序21TERN PROC ;二→十并显示。 MOVCX,10000
CALLDEC_DIV
;转换万位数 MOVCX,1000
CALLDEC_DIV
;转换千位数 MOVCX,100
CALLDEC_DIV
;转换百位数 MOVCX,10
CALLDEC_DIV
;转换十位数 MOVCX,1
CALLDEC_DIV
;转换个位数 RETTERN ENDP22DEC_DIV PROC ;CX中为十进制的位权 MOVAX,BX MOVDX,0 DIVCX ;商为转换后的一位十进制数
MOVBX,DX;余数 MOVDL,AL;商 ADDDL,30H ;转换成ASCII码 MOVAH,2 ;显示 INT21H RETDEC_DIV ENDPCODE ENDS ENDMAIN23movbx,0newchar:movah,1int21hsubal,30hjlexitcmpal,9jgexitcbw
xchgax,bxmovcx,10mulcxxchgax,bxaddbx,axjmpnewchar复习:此程序段完成的功能是什么?24
BX1234把BX中数以十六进制数形式显示(如007DH)0000000001111101000001111101000025movch,4rotate:movcl,4rolbx,clmoval,blandal,0fh;’0’~’9’ASCII30H~39Hcmpal,3ah;是否大于9jlprintit;’A’~’F’ASCII41H~46Hprintit:
addal,30haddal,7hmovdl,almovah,2int21hdecchjnzrotate把BX中数以十六进制数形式显示,程序段填空26例7.3把从键盘接收的十进制数以十六进行形式输出到屏幕上。开始调用DECIBIN调用CRLF调用BINIHEX调用CRLF结束从键盘取得十进制数,保存在BX中用十六进制形式显示BX中的数27CODESEGMENTASSUMECS:CODESTART:CALLDECIBIN
CALLCRLFCALLBINIHEX
CALLCRLFJMPSTARTMOVAH,4CHINT21H28DECIBINPROCNEARmovbx,0newchar:movah,1;键盘输入int21hsubal,30hjlexit;<0退出cmpal,9jgexit;>9退出cbw
xchgax,bxmovcx,10mulcxxchgax,bxaddbx,axjmpnewcharexit:RETDECIBINENDP125313235((0×10)+1)×10+2)×10+529
BX1234把BX中数以十六进制数形式显示(如007DH)0000000001111101000001111101000030BINIHEXPROCNEARmovch,4rotate:movcl,4rolbx,clmoval,blandal,0fh;’0’~’9’ASCII30H~39Hcmpal,3ah;是否大于9jlprintit;’A’~’F’ASCII41H~46Hprintit:
RETBINIHEXENDPaddal,30haddal,7hmovdl,almovah,2int21hdecchjnzrotate31CRLFPROCNEAR
MOVDL,0DHMOVAH,2INT21HMOVDL,0AHMOVAH,2INT21HRETCRLFENDPCODEENDS
ENDSTART32xdw110,120,130,140,150,160,170,180,190,200ydw?………..
…………..MOVAX,XMOVBX,OFFSETXMOVCX,9L1:INCBXINCBXCMPAX,[BX]JAEL2XCHGAX,[BX]L2:LOOPL1MOVY,AX此程序段完成什么功能?思考33TESTVAR,55HJZZERO…..ZERO:……上述程序段中,当VAR的内容为何值时,执行JZZERO条件转移指令后,可满足条件转到ZERO处()?。A)(VAR)=0FFHB)(VAR)=55HVAR中第0,2,4,6位为0VAR中第1,3,5,7位为0342.若调用程序和子程序在同模块中,子程序可以直接访问模块中的变量 例2.实现数组求和功能。要求数组求和(不考虑溢出情况)由子程序实现,其数组元素及结果均为字型数据。见程序。35 DATA SEGMENT
ARY DW1,2,3,4,5,6,7,8,9,10
COUNT DW10 ;数组元素个数
SUM DW? ;和的地址 DATA ENDS程序7.436CODE SEGMENT ASSUMECS:CODE,DS:DATAStart: MOVAX,DATA MOVDS,AX CALLARY_SUMMOVAH,4CHINT21H37ARY_SUM PROC ;数组求和子程序
PUSHAX ;保存寄存器 PUSHCX PUSHSI LEASI,ARY ;取数组起始地址 MOVCX,COUNT ;取元素个数 XORAX,AX ;清0累加器38NEXT: MOVSUM,AX ;存和
RETARY_SUM ENDPCODE ENDS ENDSTARTADDAX,[SI] ;累加和ADDSI,TYPEARY ;修改地址指针LOOPNEXTPOPSI ;恢复寄存器POPCXPOPAX393.通过地址表传递参数地址
适用于参数较多的情况。
具体方法是先建立一个地址表,该表由参数地址构成。然后把表的首地址通过寄存器或堆栈传递给子程序。
40例7-5.编写一个数组求和的子程序,其数组元素及结果均为字型数据。另定义两个数组,并编写一个主程序,通过调用数组求和子程序分别求出两个数组的和。41
分析:虽然主、子程序在同模块中,但由于在一个程序中要分别求出两个数组的和,因此子程序不能直接引用数组变量名。本例用数组首地址、元素个数的地址、和的地址构成地址表,通过地址表传送这些参数的地址,以便子程序能够访问到所需参数。见程序7.5。42程序7.5STACKSG SEGMENT DW32DUP(?)STACKSG ENDSDATA SEGMENTARY1
DW1,2,3,4,5,6,7,8,9,10
;数组1CT1 DW($-ARY1)/2 ;数组1的元素个数SUM1 DW? ;数组1的和地址ARY2
DW10,20,30,40,50
;数组2CT2 DW($-ARY2)/2 ;数组2的元素个数sum2 DW? ;数组2的和地址TABLE DW3DUP(?) ;地址表DATA ENDS43 CODE1 SEGMENT ASSUMECS:CODE1,DS:DATA,SS:STACKSGSTART: MOVAX,DATA MOVDS,AX;构造数组1的地址表 MOVTABLE,OFFSETARY1 MOVTABLE+2,OFFSETCT1 MOVTABLE+4,OFFSETSUM1
LEABX,TABLE
;传递地址表首地址
CALLFARPTRARY_SUM
;段间调用调用数组求和子程序44
;构造数组2的地址表 MOVTABLE,OFFSETARY21 MOVTABLE+2,OFFSETCT2 MOVTABLE+4,OFFSETSUM2
LEABX,TABLE
;传递地址表的首地址
CALLFARPTRARY_SUM MOVAH,4CH INT21HCODE1 ENDS45CODE2 SEGMENT ASSUMECS:CODE2ARY_SUM
PROCFAR
;数组求和子程序 PUSHAX ;保存寄存器 PUSHCX PUSHSI PUSHDI MOVSI,[BX]
;取数组起始地址 MOVCX,[BX+2]
;取元素个数地址 MOVDI,[BX+4]
;取结果地址 XORAX,AX ;清0累加器
movbx,cxmovcx,[bx]46NEXT: ADDAX,[SI] ;累加和 ADDSI,TYPEARY ;修改地址指针 LOOPNEXT MOV[DI],AX ;存和 POPDI ;恢复寄存器 POPSI POPCX POPAX RETARY_SUM ENDPCODE2 ENDS ENDSTART474.通过堆栈传递参数或参数地址 这种方式适用于参数较多,或子程序有多层嵌套、递归调用的情况。 步骤:主程序把参数或参数地址压入堆栈;子程序使用堆栈中的参数或通过栈中参数地址取到参数;子程序返回时,使用RETn指令调整SP指针,以便删除堆栈中已用过的参数,保持堆栈平衡,保证程序的正确返回。48例6.完成数组求和功能,求和由子程序实现,要求通过堆栈传递参数地址。 STACK SEGMENT DW16DUP(?)TOSLABLEWORD STACK ENDS DATA SEGMENT ARY DW1,2,3,4,5,6,7,8,9,10 COUNT DW($-ARY)/2 SUM DW? DATA ENDS49CODE1 SEGMENTMAIN PROCFARASSUMECS:CODE1,DS:DATA,SS:STACK
MOVAX,STACK
MOVSS,AXMOVSP,OFFSETTOS PUSHDS ;⑴ XORAX,AX PUSHAX ;⑵
MOVAX,DATA MOVDS,AX50 LEABX,ARY PUSHBX ;⑶压入数组起始地址 LEABX,COUNT PUSHBX ;⑷压入元素个数地址 LEABX,SUM PUSHBX ;⑸压入和地址
CALLFARPTRARY_SUM ;⑹调用求和子程序(压入cs和IP) RET ;⒅MAIN ENDPCODE1 ENDS51CODE2 SEGMENT ASSUMECS:CODE2ARY_SUM PROCFAR
;数组求和子程序
PUSHBP ;⑺保存BP值 MOVBP,SP
;BP是堆栈数据的地址指针 PUSHAX ;⑻保存寄存器内容 PUSHCX ;⑼ PUSHSI ;⑽ PUSHDI ;⑾ MOVSI,[BP+10] ;得到数组起始地址 MOVDI,[BP+8] ;得到元素个数地址 MOVCX,[DI]
;得到元素个数 MOVDI,[BP+6] ;得到和地址 XORAX,AX52NEXT: ADDAX,[SI] ;累加 ADDSI,TYPEARY ;修改地址指针 LOOPNEXT MOV[DI],AX ;存和 POPDI ;⑿恢复寄存器内容 POPSI ;⒀ POPCX ;⒁ POPAX ;⒂ POPBP ;⒃
RET6
;⒄返回并调整SP指针ARY_SUM ENDPCODE2 ENDS ENDMAIN53
本例通过BP访问堆栈中的参数。 程序的堆栈变化情况参见图7-1,指示了程序中所有入栈操作对堆栈的影响随入栈数据的增加,SP的值不断减小,堆栈可用空间也随之减少。图7-2为已从子程序返回、而主程序RET指令执行前的堆栈状态,其中的灰色部分表示执行语句⑿~⒄时已弹出的数据。54 子程序中语句⒄——RET6指令,在从堆栈弹出返回地址后还要使SP值加6,这样就跳过了通过堆栈传递的三个参数,或者说删除了它们。因此,当主程序的语句⒅——RET指令被执行时,程序控制从栈顶弹出数字0给IP,弹出PSP的段基址给CS,于是执行PSP:0处的INT20H指令,正确返回操作系统。55返回语句⑾执行后堆栈状态语句⑽执行后堆栈状态语句⑼执行后堆栈状态语句⑻执行后堆栈状态语句⑺执行后堆栈状态语句⑹执行后堆栈状态
语句⑸执行后堆栈状态语句⑷执行后堆栈状态语句⑶执行后堆栈状态语句⑵执行后堆栈状态语句⑴执行后堆栈状态图7-1程序7.6中所有入栈操作对堆栈的影响SSSPBPDI值SI值CX值AX值BP值IP值CS值SUM的地址COUNT地址ARY首地址0PSP段基址56返回SP语句⒄执行后堆栈状态图7-2程序7.6中主程序的RET执行前堆栈状态SSDI值SI值CX值AX值BP值IP值CS值SUM的地址COUNT地址ARY首地址0PSP段基址57
**从以上分析可以看出:通过堆栈传递参数时子程序的返回指令必须是RETN形式,当堆栈操作是16位时N值应该是压入堆栈的参数个数的2倍,只有这样保证程序的正常运行。
58
例5.完成数组求和功能,其中求和由子程序实现,要求使用结构访问堆栈中的参数。(此例仅供参考)
图7-3给出了堆栈及结构数据定义。注意这些结构字段的顺序为其值压入的逆序。实际上,它只是给图7-1中由主程序压入的数据、返回地址及子程序压入的BP值起了个名字而已,而字段值的预置是通过PUSH和CALL指令实现的。当子程序用到堆栈中的参数时,只需使用BP作为基地址、通过结构字段名访问就可以了。编码见程序7.7。59返回SSSPBPDI值堆栈数据SI值结构字段名CX值AX值BP值SAVE_BPIP值SAVE_CS_IPCS值
SUM的地址SUM_ADDRCOUNT地址COUNT_ADDRARY首地址ARY_ADDR0PSP段基址图7-3程序7.7的堆栈及结构数据示意图结构60程序7.7STACKSG SEGMENTSTACK'STK' DW16DUP('S')STACKSG ENDSDATA SEGMENTARY DW1,2,3,4,5,6,7,8,9,10COUNT DW($-ARY)/2SUM DW?DATA ENDS61CODE1 SEGMENTMAIN PROCFAR ASSUMECS:CODE1,DS:DATA PUSHDS XORAX,AX PUSHAX MOVAX,DATA MOVDS,AX62 LEABX,ARY PUSHBX ;压入数组起始地址 LEABX,COUNT PUSHBX ;压入元素个数地址 LEABX,SUM PUSHBX ;压入和地址 CALLFARPTRARY_SUM RETMAIN ENDPCODE1 ENDS63CODE2 SEGMENT ASSUMECS:CODE2STACK_STRC STRUC ;定义结构SAVE_BP DW?SAVE_CS_IP DW2DUP(?)SUM_ADDR DW?COUNT_ADDR DW?ARY_ADDR DW?STACK_STRC ENDS64ARY_SUM PROCFAR ;数组求和子程序 PUSHBP ;保存BP值 MOVBP,SP PUSHAX PUSHCX PUSHSI PUSHDI MOVSI,[BP].ARY_ADDR;数组始地址 MOVDI,[BP].COUNT_ADDR MOVCX,[DI] MOVDI,[BP].SUM_ADDR;得到和地址 XORAX,AX65NEXT: ADDAX,[SI] ;累加 ADDSI,TYPEARY ;修改地址指针 LOOPNEXT MOV[DI],AX ;存和 POPDI POPSI POPCX POPAX POPBP RET6 ;返回并调整SP指针ARY_SUM ENDPCODE2 ENDS ENDMAIN66例6.编写两个四位无符号十进制数乘法程序。要求:乘数从键盘输入;二进制乘;用十进制数形式显示乘积。
1.分析:由于题目要求从外设输入输出数据,而在内存中用二进制数形式实现乘法,所以涉及到代码转换问题。步骤如下:从键盘输入两个十进制乘数(ASCII码)→分别转换成二进制形式→二进制数乘→把二进制乘积转换成十进制数的ASCII码形式→输出到屏幕。67
2.设计:本例中的输入、输出、十进制到二进制的转换、二进制到十进制的转换均采用子程序形式实现。*十→二转换算法:
Y=Y*10+Xi (Y的初始值为0,i=n,n-1,…0) ASC_BIN是实现四位十进制数转换成二进制数的子程序。程序中Y值在AX中,i值由CL控制。68*二→十转换算法:
除10取余法。即用32位的二进制乘积(高16位在RSLTHI中、低16位在RSLTLO中)作为被除数,10作为除数,每次除后所得到的余数就是本位的十进制数,并把它转换成ASCII码存放在输出缓冲区的相应位置,直到整个转换结束,最后输出。69
BIN_ASC是实现32位二进制数转换成十进制数的子程序。考虑到32位的被除数除以10很容易产生超过16位的商,从而产生除法错中断无法得到正确结果,因此需要采用一种避免产生除法错中断的技术。本例采用的方法是把32位被除数扩展成48位,其中最高16位为0,然后进行除法运算。示意图如下:全0703.编码(程序7.8)
CR EQU0DH LF EQU0AH STACKSG SEGMENTSTACK'S' DW64DUP('ST') STACKSG ENDS71DATA SEGMENTPROMPT1 DB CR,LF,'INPUT NUM1:$'PROMPT2 DB CR,LF,'INPUT NUM2:$'ASCIN1 DB 5,?,5 DUP(?)ASCIN2 DB 5,?,5 DUP(?)BIN1 DW ? ;乘数1二进制值BIN2 DW ? ;乘数2二进制值RSLTHI DW 0 ;32位二进制乘积的高16位RSLTLO DW 0 ;32位二进制乘积的低16位ASCOUT0 DB CR,LF,'RESULT:'ASC_OUT DB 10 DUP(0),'$'DATA ENDS72CODE SEGMENT ASSUMECS:CODE,DS:DATA,SS:STACKSGMAIN PROCFAR MOVAX,DATA
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年智能化高架活动地板项目可行性研究报告
- 2025年排水阀门项目可行性研究报告
- 2025年大红描金粉蜡笺项目可行性研究报告
- 2025年压片机项目可行性研究报告
- 2025年全粒面填充项目可行性研究报告
- 2025年PVC可调电容项目可行性研究报告
- 2025至2030年中国陶瓷纤维浇注料数据监测研究报告
- 2025至2030年中国转动计数器数据监测研究报告
- 2025至2030年中国落地通风柜数据监测研究报告
- 2025至2030年桦木皮项目投资价值分析报告
- 2025年度消防工程安全防护措施设计固定总价合同范本3篇
- 2025年事业单位财务工作计划(三篇)
- Unit 2 Know your body(说课稿)-2024-2025学年外研版(三起)(2024)英语三年级下册
- 名师工作室建设课件
- 《电子技术应用》课程标准(含课程思政)
- 纸尿裤使用管理制度内容
- 电力储能用集装箱技术规范
- 体检中心员工礼仪培训
- 《工程质量验评培训》课件
- 《课标教材分析》课件
- 筑牢安全防线 创建平安校园
评论
0/150
提交评论