版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
2026/7/28ch61
在程序设计中,我们会发现一些多次无规律重复的程序段或语句序列。解决此类问题一个行之有效的方法就是将它们设计成可供反复调用的独立的子程序结构,以便在需要时调用。在汇编语言中,子程序又称过程。
调用子程序的程序称为主调程序或主程序。第6章子程序结构2026/7/28ch62子程序的基本结构包括以下几个部分:(1)子程序定义(2)保护现场和恢复现场(3)子程序体(4)子程序返回子程序的结构2026/7/28ch63
子程序的定义是由过程定义伪指令PROC和ENDP来完成的。其格式如下:过程名PROC[NEAR/FAR]┆过程名ENDP
其中PROC表示过程定义开始,ENDP表示过程定义结束。过程名是过程入口地址的符号表示。
一般过程名同标号一样,具有三种属性,即段属性、偏移地址属性以及类型属性(NEAR和FAR)。6.1.1子程序的定义6.1子程序的设计方法2026/7/28ch64如果调用程序和过程在同一代码段中,则使用NEAR属性;MAINPROCFAR
…
CALLSUBR1RETMAINENDP;SUBR1PROCNEAR
…RETSUBR1ENDPMAINPROCFAR
…
CALLSUBR1RETSUBR1PROCNEAR
…RETSUBR1ENDPMAINENDP6.1.2子程序的调用和返回2026/7/28ch65如果调用程序和过程不在同一代码段中,则使用FAR属性;SEGXSEGMENT
…SUBTPROCFAR…RETSUBTENDP…
CALLSUBT…SEGXENDS;SEGYSEGMENT…
CALLSUBT…SEGYENDS2026/7/28ch666.1.3保护现场和恢复现场例如:若子程序PROG中改变了寄存器AX,BX,CX,DX的值,则可采用如下方法保护和恢复现场。PROG PROC
PUSH AX PUSH BXPUSH CX ;保护现场
PUSH DX
┆
POP DX POP CX POP BX ;恢复现场
POP AX RET ;返回断点处PROC ENDP2026/7/28ch676.1.4主程序与子程序参数传递方式
1通过寄存器传送参数
这是最常用的一种方式,使用方便,但参数很多时不能使用这种方法。
例:十进制到十六进制转换的程序。程序要求从键盘取得一个十进制数,然后把该数以十六进制的形式在屏幕上显示出来。开始调用DECIBIN调用CRLF调用BINIHEX调用CRLF结束从键盘取得十进制数,保存到BX中显示回车和换行用十六进制形式显示BX中的数2026/7/28ch68Decihexsegmentassumecs:DecihexMainprocfarRepeat:pushdsxorax,axpushax
calldecibincallcrlfcallbinihexcallcrlfretMainendp
Decibinprocnearmovbx,0Newchar:movah,1int21hsubal,30hjlexitcmpal,9jgexitcbw
xchgax,bxmovcx,10mulcxxchgax,bx;每次乘的
addbx,ax;结果在BX中
jmpnewcharExit:retDecibinendp
2026/7/28ch69Binihexprocnear
movch,4Rotate:movcl,4rolbx,clmovdl,blanddl,0fhadddl,30hcmpdl,3ahjlprintadddl,7hPrint:movah,2int21hdecchjnzrotateretBinihexendpCrlfprocnear
movah,2movdl,odhint21hmovdl,oahint21hretCrlfendpDecihexendsendrepeat
2026/7/28ch610如果过程和调用过程在同一源文件(同一模块)中,则过程可直接访问模块中的变量。
例6.4主程序MAIN和过程PROADD在同一源文件中,要求用过程PROADD累加数组的所有元素,并把和(不考虑溢出的可能性)送到指定的存储单元中去2026/7/28ch611DATASEGMENT
ARYDW100DUP(?)
COUNTDW100
SUMDW?DATAENDSCODESEGMENT
MAINPROCFARASSUMECS:CODE,DS:DATASTART:PUSHDSSUBAX,AXPUSHAXMOVAX,DATA…
CALLNEARPTRPROADD…RETMAINENDPPROADDPROCNEAR
PUSHAXPUSHCXPUSHSIPUSHDI
LEASI,ARYMOVCX,COUNTXORAX,AXNEXT:ADDAX,[SI]ADDSI,2LOOPNEXTMOVSUM,AX
POPDIPOPSIPOPCXPOPAXRETPROADDENDPCODEENDSENDSTART2026/7/28ch612CODESEGMENTARYDW100DUP(?)COUNTDW100SUMDW?NUMDW100DUP(?)NDW100TOTALDW?;MOVTABLE,OFFSETARYMOVTABLE+2,OFFSETCOUNTMOVTABLE+4,OFFSETSUNMOVBX,OFFSETTABLECALLPROADD;计算SUMPROADDPROCNEARPUSHAXPUSHCXPUSHSI
MOVSI,MOVCX,MOVDI,XORAX,AXNEXT:ADDAX,[SI]ADDSI,2LOOPNEXTMOV,AXPOPSIPOPCXPOPAXRETPROADDENDPCODEENDS
ENDSTART[BX][BX+2][BX+4][DI]3通过地址表传递参数2026/7/28ch613例:把内存中字变量num的值,转换为4个用ASCⅡ码表示的16进制数码,串的起始地址为string
。DatasegmentNumdw25afhStringdb4dup(?),‘$’,0dh,0ahDataendsStacksegmentparastack‘stack’db100dup(?)StackendsCodesegmentassumecs:code,ds:data,ss:stackMainprocfarBegin:pushdsxorax,axpushaxmovax,datamovds,ax
leabx,string
pushbxpushnum
callbinhex
leadx,string
movah,9int21hretMainendp2000:00002000:0002·3000:00003000:00013000:00033000:00043000:00073000:00093000:000d3000:000e3000:00123000:00153000:00191500af250200spstring地址NumLeadx,string地址(IP)4通过堆栈传递地址或参数2026/7/28ch614Binhexprocnear
pushbpmovbp,sp
pushaxpushdipushbxpushcxpushfmovax,[bp+4];ax=25afhmovdi,[bp+6];di=0002movch,4movcl,4roat:rolax,clmovbl,alandbl,0fhaddbl,30hcmpbl,39hjlenextaddbl,7h001525af0002spstring地址NumLeadx,string地址(IP)flagcxbxdiaxbp(Sp→)bpbp+2bp+4bp+6Bp-6Bp-4Bp-22026/7/28ch615Next:mov[di],blincdidecchjnzrotapopf
popcxpopbxpopdipopaxpopbp
ret4BinhexendpCodeendsendbegin001525af0002spstring地址NumLeadx,string地址(IP)flagcxbxdiaxbpsp2026/7/28ch616
例3:求10个数的累加值.--------远调用DatasegmentArydb10dup(?)Countdb10Sumdb?DataendsStacksegmentparastack‘stack’db100dup(?)StackendsCode1segmentassumecs:code1,ds:data,ss;stackMainprocfarStart:pushdsxorax,axpushaxmovax,datamovds,ax2026/7/28ch617
Movbx,offsetaryPushbxMovbx,offsetcountPushbxMovbx,offsetsumPushbx
Callfarptrproadd
moval,summovdl,almovah,2int21hretMainendpCode1endsSum地址Count地址Ary地址MOVAL,SUM地址spIPCS2026/7/28ch618Sum地址Count地址Ary地址spMOVAL,SUM地址disicxaxbp(Sp→)bpIPCSCode2segmentassumecs:code2Proaddprocfar
pushbpmovbp,sppushaxpushcxpushsipushdimovsi,[bp+0ah]movdi,[bp+08h]movcl,[di]movdi,[bp+06h]xoral,alAgain:addal,[si]incsideccljnzagainmov[di],al
popdipopsipopcx
popaxpopbp
ret6ProaddendpCode2endsendstart[bp+0ah][bp+08h][bp+06h]2026/7/28ch619(1)PUBLIC伪指令格式:PUBLIC符号[,符号]
功能:说明其后的符号是全局符号。全局符号能被其他模块引用。(局部符号)(2)EXTRN伪指令格式:EXTRN符号:类型[,符号:类型]
功能:说明在本模块中需要引用的、由其他模块定义的符号,即外部符号。5多个模块之间的参数传送问题2026/7/28ch620sourcemodule1
extrna:word
Data1segmentbdw?Data1endscode1segmentassumecs:code1,ds:data1Mainprocfarstart:movax,data1movds,ax
…movah,4chint21hMainendpCode1endsEndstartsourcemodule2
publica
Data2segmentadw?Data2endscode2segmentassumecs:code2,ds:data2Mainprocfarstart:movax,data2movds,ax
…movah,4chint21hMainendpCode2endsEndstart注意:应先有public定义,然后才有extrn说明2026/7/28ch621NAME MOD1
EXTRN DISP:FAR
PUBLIC STR1,N,BUFDATA1 SEGMENT STR1 DB ‘HOWDOYOUDO?’ N = $-STR1BUF DB ‘THISISANEXAMPLEOFMODULESPROGRAM$′DATA ENDSSTACK SEGMENTSTACK DB200DUP(0)STACK ENDSCODE1 SEGMENT ASSUMECS:CODE1,DS:DATA1,SS:STACKSTART:
MOV AX,DATA MOV DS,AX
CALL DISP MOV AH,4CH INT 21HCODE1 ENDSEND START例:用模块化程序设计方法建立两个模块MOD1ASM和MOD2ASM的数据通讯。2026/7/28ch622NAME MOD2EXTRN STR1:BYTE,STR2:BYTE,N:ABSPUBCIC DISPDATA2 SEGMENTSTR2 DB81DUP(0)DATA2 ENDSCODE2 SEGMENT ASSUMECS:CODE2,ES:DATA2DISP PROC FAR MOV AX,DATA2 MOV ES,AXLEA BX,STR1 MOV CX,N LEA SI,STR2NEXT:
MOV AL,[BX] MOV ES:[SI],AL INC BX INC SI LOOP NEXT LEA DX,BUF MOV AH,9 INT 21H RETDISP ENDPCODE2 ENDS END2026/7/28ch6236.1.5增强功能的过程定义伪操作ProcnamePROC[attributesfield][USERregisterlist][,parameterfield]
…
ProcnameENDPAttributesfield(属性字段)包括:
Distance:near、farLanguagetype:说明是那种高级语言的子程序如pascal、c
等。
Visibility:说明程序的可见性是private
或是public。
Prologue:是一个宏的名字,允许用宏来控制过程的入口或出口有关的代码USER:该字段用来指定用户所需保存和恢复的寄存器表。Parameterfield:参数字段,允许用户指定该过程所用的参数。
标识符:类型[,标识符:类型]
2026/7/28ch624DatasegmentArydb10dup(?)Countdb10Sumdb?DataendsStacksegmentparastack‘stack’db100dup(?)StackendsCode1segmentassumecs:code1,ds:data,ss:stackMainprocfarStart:pushdsxorax,axpushax
movax,datamovds,ax
Movbx,offsetaryPushbxMovbx,offsetcountPushbxMovbx,offsetsumPushbx
Callfarptrproadd
moval,summovdl,almovah,2int21hretMainendpCode1ends例6.4用增强功能过程定义伪操作实现2026/7/28ch625Code2segmentassumecs:code2Proaddprocfar
pushbpmovbp,sppushaxpushcxpushsipushdimovsi,[bp+0ah]movdi,[bp+08h]movcl,[di]movdi,[bp+06h]xoral,alAgain:addal,[si]incsideccljnzagainmov[di],al
popdipopsipopcxpopaxpopbp
ret6ProaddendpCode2endsendstartCode2segmentassumecs:code2Proaddproc
pascal
user
axcxsidi,
para:word,parc:word,pars:wordmovsi,paramovdi,parcmovcl,[di]movdi,parsxoral,alAgain:addal,[si]incsideccljnzagainmov[di],alretProaddendpCode2endsendstartSum地址Count地址Ary地址(bp)IPCS
(
bp+2)(bp+4)(bp+6)(bp+8)(bp+a)原始bpmoval,sum
para
parsparc局部变量disicxax
(
bp-2)2026/7/28ch626
增强功能的过程定义伪操作除了以上功能外,还可以在过程中定义局部变量。局部变量是在过程内部使用的变量,他是在过程调用是在堆栈中建立的,在退出过程是被释放。可以用LOCAL定义
LOCAL变量:类型[,变量:类型]Sum地址Count地址Ary地址(bp)IPCS(
bp+2)(bp+4)(bp+6)(bp+8)(bp+a)原始bp(
bp-2)(
bp-4)局部变量2026/7/28ch6276.2子程序的嵌套
一个子程序可以作为调用程序去掉用另一个子程序,这种情况称为子程序的嵌套。嵌套深度不限。但应注意什么问题?
堆栈溢出:上溢、下溢递归子程序:如果一个子程序调用的是子程序的本身,就是递归子程序。2026/7/28ch628
例5:计算N!=N*(N-1)*(N-2)*……*1
--------递归子程序DatasegmentNumdb3Resultdw?DataendsStacksegmentparastack‘stack’db100dup(?)StackendsCodesegmentassumecs:code,ds:data,ss:stackMainprocfarBegin:pushdsxorax,axpushaxmovax,datamovds,ax2026/7/28ch629movah,0moval,num
callfactormovresult,axretMainendpFactorproc
pushaxsubax,1jnef_contpopaxjmpreturnf_cont:callfactorpopcxmulclreturn:retfactorendpCodeendsendbeginIP1Movresult,ax地址3IP2Popcx地址2IP3Popcx地址1ax=1IPPOPCX
地址cx=2ax*cx=1*2IPPOPCX
地址cx=3ax*cx=1*2*3IPMovresult,ax地址2026/7/28ch630
常用的DOS系统功能调用1.单字符输入(1号调用)2.单字符显示(2号调用)3.打印输出(5号调用)4.结束调用(4CH号调用)5.显示字符串(9号调用)6.字符串输入(10号调用)2026/7/28ch6311.单字符输入(1号调用)格式:MOV AH,1
INT 21H功能:从键盘输入字符的ASCII码送入寄存器AL中,并送显示器显示。
2.单字符显示(2号调用)格式:MOVDL,待显示字符的ASCII码
MOVAH,2
INT21H功能:将DL寄存器中的字符送显示器显示.2026/7/28ch6323.打印输出(5号调用)格式:MOV DL,待打印字符的ASCII码
MOV AH,5
INT 21H功能:将DL寄存器中的字符送打印机打印。4.结束调用(4CH号调用)格式:MOV AH,4CH
INT 21H功能:终止当前程序并返回调用程序。2026/7/28ch6335.显示字符串(9号调用)格式:LEA DX,待显示字符串首偏移地址
MOV AH,9
INT 21H功能:将当前数据区中以‘$’结尾的字符串送显示器显示。6.字符串输入(10号调用)格式:LEA DX,缓冲区首偏移地址
MOV AH,10INT 21H功能:从键盘上输入一字符串到用户定义的输入缓冲区中,并送显示器显示。
maxlendb32actlendb?stringdb32dup(?)
leadx,maxlenmovah,0ahint21h说明:缓冲区的第一个字节保存最大字符数,这个最大字符数由用户程序给出。如果键入的字符数比此数大,机器发出嘟嘟声。第二个字节存放实际输入的字节数,这个不是由用户填入的而由功能A填入的。在这两个字节之后,才是我们输入的字符串。2026/7/28ch6346.3子程序举例例1:HEXIDEX是一个十六进制数转换成十进制数的程序。要求把从键盘输入的0—FFFFH的十六进制正数转换为十进制数并在屏幕上显示出来。Displayequ2hKeyequ1hDoscallequ21hHexidecsegmentMainprocfarassumecs:hexidecStart:pushdssubax,axpushaxcallhexideccallcrlfcallbinideccallcrlfjmpmainretmainendpCrlfprocnearmovdl,0ahmovah,displayintboscallmovdl,0dhmovah,displayintdoscallretcrlfendpHexidecendsendstart2026/7/28ch635Hexidecprocnearmovbx,0Newchar:movkey_inintdoscallsubal,30hjlexitcmpal,10djladd_to
subal,27hcmpal,0ahjlexitcmpah,10hjgeexitAdd_to:movcl,4shlbx,clmovah,0addbx,axjmpExit:RetHexidecendpBinidecprocnearmovcx,10000dcalldec_divmovcx,1000dcalldec_divmovcx,100dcalldec_divmovcx,10dcalldec_divmovcx,1dcalldec_divretDec_divprocnearmovax,bxmovdx,0divcxmovbx,dxmovdl,aladddl,30hmovah,displayintdoscall
retdec_divendpBinidecendp2026/7/28ch636例2:一个简单的信息检索系统。在数据区里,有10个不同的信息,编号为0—9,每个信息包括30个字符。现在要编制一个程序:从键盘接收0—9之间的一个编号,然后在屏幕上显示相应编号的信息的内容。Datareasegmentthirtydb30msg0db‘0IlikemyIBM-PC--------------’msg1db‘1IlikemyIBM-PC--------------’msg2db‘2IlikemyIBM-PC--------------’msg3db‘3IlikemyIBM-PC--------------’msg4db‘4IlikemyIBM-PC--------------’msg5db‘5IlikemyIBM-PC--------------’msg6db‘6IlikemyIBM-PC--------------’msg7db‘7IlikemyIBM-PC--------------’msg8db‘8IlikemyIBM-PC--------------’msg9db‘9IlikemyIBM-PC--------------’errmsgdb‘error!!!Invalidpraameter’Datareaends2026/7/28ch637Stacksegmentdb256dup(0)toslablewordStackendsPrognamsegmentassumecs:prognam,ds:datarea,ss:stackStart:pushdsxorax,axpushaxmovax,stackmovss,axmovax,datareamovds,axmovsp,offsettosBegin:movah,1int21hsubal,’0’jcerrorcmpal,‘9’jaerrorMovbx,offsetmsg0MulthirtyAddbx,axCalldisplayJmpbeginError:movbx,offseterrmsgcalldisplayretDisplayprocnearmovcx,30movdl,[bx]calldispcharincbxloopdisp1movdl,0dhcalldispcharmovdl,0ahcalldispcharretDispcharendpDispcharprocnaermovah,2int21hretDispcharendpMainendpPrognamendsEndstart2026/7/28ch638例3:人名排序程序。先从终端键入最多30个人名,当所有人名都进入后,按字母上升的次序将人名排序,并在屏幕上显示已经排好的人名。2026/7/28ch639Datasegmentnameparlabelbytemaxnlendb21namelendb?nameflddb21dup(?)crlfdb13,10,’$’endaddrdw?messg1db‘name?’,’$”messg2db‘sortednames’,13,10,’$’namectrdb0nametabdb30dup(20dup(‘’))namesavdb20dup(?),13,10,’$’swappeddb0DataendsCodesegmentmainprocfarassumecs:code,ds:data,es:datastart:pushdsmovax,0pushaxmovax,datamovds,axmoves,axcldleadi,nametaba20loop:callb10readcmpnamelen,0
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 智慧城市物联网技术应用推广手册
- 影像科系统瘫痪应急预案
- 科技公司技术部软件开发工程师效率绩效评定表
- 学校高中校长室职能
- 财务出纳员资金安全绩效考核表
- 技术交流合作协议确认函8篇
- 重要任务完成度考核表
- 发送合同模板确认请求回复函(4篇)
- 售后服务支持服务级别协议通知函(7篇)范文
- 知识更新情况评估表
- 2025届高三数学一轮复习-分段函数专项训练【含答案】
- 中学生自我价值感分析
- XXXX商品质量管理及法规
- 安全生产工作总体目标和年度安全生产目标
- 热注锅炉水量自动控制
- 安徽兴欣新材料有限公司年产20000吨三丙酮胺、10000吨2,2,6,6-四甲基哌啶醇、6000吨哌啶胺、6000吨受阻胺光稳定剂及600Nm3h甲醇重整制氢项目环境影响报告书
- 保密措施安全保卫措施
- 2022小学英语新课标试题及答案(共二套)4994
- 食品工程原理绪论课件
- 老年人能力评估标准解读(讲义)
- GB 16548-1996畜禽病害肉尸及其产品无害化处理规程
评论
0/150
提交评论