




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第六章子程序结构
过程定义伪操作
子程序的调用与返回保存与恢复寄存器子程序的参数传送
子程序的嵌套与递归一、调用程序与子程序
子程序:在许多应用程序中,常常需要多次使用某功能的指令序列。这时,为了减少重复编写程序,节省内存空间,把这一功能的指令序列组成一个相对独立的程序段。在程序运行时,如果需要使用这个给定的功能,就转移到这个独立的程序段,待这个独立的程序段指令序列执行完后,又返回到原来位置继续运行程序。我们把这个相对独立的程序段就叫子程序或过程。调用程序:编制程序时,按需要转向子程序,称为子程序调用,或称为过程调用。调用子程序的程序称为调用程序或主程序。主、子程序是相对而言的。但子程序一定是受调用程序或主程序调用的。子程序定义的位置可以放在主程序的前面或后面。二.过程定义伪操作过程名PROCNEAR
(FAR)
过程名ENDP(1)NEAR属性:调用程序和子程序在同一代码段中,可省略。(段内调用)(2)FAR属性:调用程序和子程序不在同一代码段中。(段间调用)...code1segmentmainprocfar……
callfarptr
subp……retmainendpcode1endscode2segmentsubpprocfar……
retsubp
endpcode2ends
段间调用和返回codesegmentmainprocnear……call
subp……retmainendpsubpprocnear……
retsubp
endpcodeends
段内调用和返回segxsegmentsubtprocfar……
retsubt
endp……
call
subt……segxendssegysegment……
callfarptr
subt……segyends同一个子程序可以被段内调用,也可以段间调用
(1)CALL子程序调用指令:隐含使用堆栈保存返回地址
指令格式:
CALLDST;其中DST为过程的目标地址(即过程名)。指令功能:把CALL指令的下一条指令地址(称为返回点或断点)推入堆栈保存,然后转到目标地址(DST)。
CALL指令可以在段内、段间调用,寻址方式分为直接和间接两种。三.子程序的调用与返回指令
段内直接近调用:CALLDST执行操作:
(SP)←(SP)-2((SP)+1,(SP))←(IP)(IP)←DST(实际操作是把从指令中得到的距目标过程相对偏移量(最大为32K字节)加到指令指针IP上(得到子程序的入口地址),实现过程调用。)段内间接近调用:CALLDST执行操作:
PUSHIP(IP)←(EA)DST给出子程序的入口地址(子程序为near属性)比如:CALLsubpDST给出寄存器或存储单元的内容(转向地址)比如:CALLwordptr[bx](SP)→(IP)段间直接远调用:CALLFARPTRDST执行操作:PUSHCSPUSHIP(IP)←DST偏移地址
(CS)←DST段地址段间间接远调用:CALLFARPTRDST
执行操作:PUSHCSPUSHIP(IP)←(EA)(CS)←(EA+2)(IP)(CS)(SP)→DST给出子程序的入口地址(子程序为far属性)比如:CALLfarptr
subp(2)RET返回主程序指令:属于无条件转移指令。可以在段内或段间返回。段内近返回:RET
执行操作:POPIP段内带立即数近返回:RETEXP
执行操作:POPIP(SP)(SP)+EXP段间远返回:RET(F)
执行操作:POPIPPOPCS段间带立即数远返回:RETEXP表达式(SP)→(IP)(SP)→
。。。(SP)→(SP)+EXP例:带立即数返回(SP)
堆栈段codesegmentmainprocfarStart:pushds Subax,ax pushax……pushaxpushbxpushcxcallsub……retmainendpsubprocnear……ret6subendpcodeendsendstart(IP)(cx)(bx)(ax)(SP)
(SP)
主程序模块子程序模块(SP)
程序返回【例】已知三个八位无符号数X、Y、Z,分别存放于BUF、BUF+1和BUF+2存储单元,计算2X+5Y+8Z,结果送RES和RES+1单元。
DATASEGMENTBUFDB71H,0A4H,9BHRESDB2DUP(?)DATAENDSSTACKSEGMENTDW50DUP(?)TOPLABELWORDSTACKENDSCODESEGMENTASSUMECS:CODE,DS:DATA,SS:STACKMAINPROCFARSTART:…MAINENDP…CODEENDSENDSTART将主程序补充完整START:PUSH DSSUB AX,AXPUSHAX;保存程序前缀PSP地址
MOVAX,DATAMOVDS,AXMOVAX,STACKMOVSS,AXMOVSP,OFFSETTOPMOVAX,0;AX清0MOVWORDPTRRES,AX;RES字单元清0LEABX,BUF;置地址指针
MOVAL,2
CALLMULL;过程调用计算RES+2XMOVAL,5
CALLMULL;过程调用计算RES+5YMOVAL,8
CALLMULL;过程调用计算RES+8ZRET;程序返回子程序编写MULLPROCNEAR;乘法子程序
MULBYTEPTR[BX];做乘法结果在AXADDWORDPTRRES,AX;做加法
MOVAX,0;AX清0INCBX;地址加1RET
;返回主程序MULLENDP四.现场保护与恢复subtprocnear
pushaxpushbxpushcxpushdx…………popdxpopcxpopbxpopaxretsubt
endp要保护的寄存器:应该是在子程序中将被使用,返回调用程序后仍然需要使用其原有内容的那些寄存器。即保护调用程序和子程序两者在使用上发生冲突的那些寄存器。但在编程时,一时很难弄清哪些是有冲突的寄存器,一种较为简单的方法是把所有的寄存器均加以保护。一般在子程序中进行寄存器保护较好。即在子程序的开始部分,先进行相关寄存器(主要是在子程序中使用的各寄存器)的保护。然后再进行子程序的处理操作。在执行完子程序后,返回前,先恢复各寄存器内容后,再返回调用程序。(1)通过寄存器传送参数(2)通过存储器传送参数(3)通过地址表传送参数地址(4)通过堆栈传送参数或参数地址五.子程序的参数传送实现的方法是把子程序所需要的入口参数,由调用程序予先放入指定的寄存器中。在进入子程序后,子程序就可直接对这些寄存器内容进行操作了。同样子程序的运行结果,也可置入寄存器中,把它们作为子程序的出口参数寄存器使用。请大家注意:参数的传递方法并不是固定不变的,即它们是可以综合使用的。依实现的需要和情况的不同,可以灵活使用其中一种方式,也可以同时使用几种方式的混合。有的时候还可能并不需要参数传递。例1:十六进制到十进制的转换(通过寄存器传送参数)hexidecsegment;1610assumecs:hexidec
mainprocfarstart:pushdssubax,axpushaxcallhexibin
;162callcrlfcallbinidec
;210callcrlf
retmainendp………………hexidecendsendstartCrlfprocnear
movdl,0dh
movah,2
int21h
movdl,0ah
movah,2
int21hretCrlf
endphexibinprocnear
mov
bx,0newchar:
movah,1
int21hsubal,30h
jlexit
cmpal,10
jladd_tosubal,27h
cmpal,0ah
jlexit
cmpal,10h
jgeexitadd_to:
mov
cl,4
shl
bx,cl
movah,0addbx,ax
jmp
newcharexit:rethexibin
endpbinidecprocnear
mov
cx,10000d
calldec_div
mov
cx,1000d
calldec_div
mov
cx,100d
calldec_div
mov
cx,10d
calldec_div
mov
cx,1d
calldec_div
retbinidec
endpdec_divprocnear
movax,bx
mov
dx,0divcx
mov
bx,dx
movdl,aladddl,30h
movah,2
int21hretdec_div
endp1ab5
31616235例2:累加数组中的元素(通过存储器传送参数)datasegment
ary
dw1,2,3,4,5,6,7,8,9,10countdw10sumdw?dataendscodesegmentassumecs:code,ds:datastart:
movax,data
mov
ds,ax
callproadd
mov ax,4c00h
int21hmainendpcodeendsendstartproaddprocnearpushaxpushcxpushsileasi,ary
mov
cx,count
xorax,axnext:addax,[si]addsi,2loopnext
mov
sum,axpopsipopcxpopaxretproadd
endp如果数据段定义如下:datasegment
ary
dw1,2,3,4,5,6,7,8,9,10
countdw10
sumdw?
ary1dw10,20,30,40,50,60,70,80,90,100
count1dw10
sum1dw?dataends如果直接访问内存变量,那么累加数组ary和数组ary1中的元素不能用同一个子程序
proadd。那如何能实现调用同一个子程序proadd来累加另一个数组元素?例3:累加数组中的元素(通过地址表传送参数地址)datasegment
ary
dw10,20,30,40,50,60,70,80,90,100countdw10sumdw?
tabledw3dup(?)
;地址表dataendscodesegmentmainprocfarassumecs:code,ds:datapushdssubax,axpushax
movax,data
mov
ds,ax
movtable,offsetary
;把要传送给子程序
movtable+2,offsetcount;的参数都存放在地址
movtable+4,offsetsum
;表中,然后把地址表
mov
bx,offsettable;的首地址通过寄存器
callproadd
;BX传送到子程序中去。
retmainendp
proaddprocnearpushaxpushcxpushsipushdi
mov
si,[bx]
mov
di,[bx+2]
mov
cx,[di]
mov
di,[bx+4]
xorax,axnext:addax,[si]addsi,2loopnext
mov[di],axpopdipopsipopcxpopaxretproadd
endpcodeendsendmain30d40d50d60d70d80d90d100d10d
ary
20d10dcountsumtable0000001400160018000000140016
(bx)(si)(di)550d存储单元的内容例4:累加数组中的元素(通过堆栈传送参数地址)
在主程序里把参数地址保存到堆栈中,在子程序里从堆栈中取出参数以达到传送参数的目的。datasegment
ary
dw10,20,30,40,50,60,70,80,90,100countdw10sumdw?dataendsstacksegment
dw100dup(?);堆栈全是字操作,必须用DW
toslabelword;栈顶指针也必须是字类型stackends
codesegmentmainprocfarassumecs:code,ds:data,ss:stackstart:
movax,stack
mov
ss,ax
movsp,offsettos
;堆栈段及SP设置方法
movax,data
mov
ds,ax
mov
bx,offsetarypushbx
mov
bx,offsetcountpushbx
mov
bx,offsetsumpushbx
;把参数地址保存到堆栈
callproadd……
movax,4c00h
int21hmainendpcodeendsendstartproaddprocnear
pushbp
mov
bp,sppushaxpushcxpushsipushdi
movsi,[bp+8]
movdi,[bp+6]
mov
cx,[di]
movdi,[bp+4]
xorax,axnext:addax,[si]addsi,2loopnext
mov[di],axpopdipopsipopcxpopaxpopbp
ret6proadd
endp(ip)sumcountarray
(di)(si)(cx)(ax)(sp)
(bp)
(bp)
(bp)+8
(bp)+6
(bp)+4
tosCALL指令堆栈最满的状态子程序的嵌套:一个子程序也可以作为调用程序去调用另一个子程序。主程序
子程序A
子程序B六.子程序的嵌套与递归调用……callproc_A……proc_A
……callproc_B……Callproc_Aretproc_B……ret子程序的递归调用是指一个子程序直接或间接地调用自己。递归调用要注意必须有结束递归调用的判断语句。编写子程序计算(bx)!=axFactprocnearand bx,bx
jz fact1;等于0跳转
push bx
dec
bxcall fact;递归调用L:pop bx
mul
bx
;结果在ax中
retFact1:mov ax,1retFactendp编写程序计算4!+7!
….….;主程序开始部分
mov
bx,4;入口参数
call fact;调用子程序M:pushax;保存4!的结果
mov
bx,7
callfact;(ax)=7!popbx;(bx)=4!addax,bx….….递归子程序:n!=n(n-1)(n-2)…13!=3×2×1=6
0!=1n!=n(n-1)!子程序如果段间调用时,必须定义为FAR类型。段间调用通常用于不同模块之间的调用。编写不同模块的段间调用程序,应该注意以下几个个问题:(1)主程序模块和子程序模块分别汇编,然后用连接程序将它们连接在一起。(2)在主程序模块中,主程序所调用的外部过程名必须用EXTRN伪指令说明。(3)在过程模块中,提供给外段调用的过程名必须用PUBLIC伪指令说明。(4)模块间其它公用符号名及外部符号名的定义不可缺少。七.多模块程序设计(段间调用)局部符号:在本模块中定义,在本模块中引用的符号。不同模块中的局部符号允许重名。外部符号:在某一模块中定义,在另一模块中引用的符号。要连接的模块中的外部符号不允许重名。
PUBLIC符号EXTRN符号:类型
extrn
proadd:far……;在本模块中引用其他模块
……;中定义的外部符号proaddcode1segmentstart:……callfarptr
proadd
……code1endsendstart;proadd1.asmpublicproadd……;在本模块中定义可供
……;其他模块引用的符号code2segmentproaddprocfar……retproadd
endpcode2endsend;proadd2.asm将【例6.1】中的段内调用改为段间调用
已知三个八位无符号数X、Y、Z,分别存放于BUF、BUF+1和BUF+2存储单元,计算2X+5Y+8Z,结果送RES和RES+1单元。NAMEEXAM6_2EXTRNMULL:FAR;外部引用说明PUBLICRES;定义公用名DATASEGMENTBUFDB71H,0A4H,9BHRESDB2DUP(?)DATAENDSSTACKSEGMENTDW50DUP(?)TOPLABELWORDSTACKENDSCODE1SEGMENTASSUMECS:CODE1,DS:DATA,SS:STACKMAINPROCFARSTART:…MAINENDPCODE1ENDSENDSTART
NAMEL6_2AEXTRNRES:BYTE;外部引用说明
PUBLICMULL;定义公用名CODE2SEGMENTASSUMECS:CODE2MULLPROCFAR;乘法子程序
MULBYTEPTR[BX];做乘法结果在AXADDWORDPTRRES,AX;做加法
MOVAX,0;AX清0INCBX;地址加1RET;返回主程序MULLENDPCODE2ENDSEND例5:用两个模块累加数组元素。;proadd1.asmextrn
proadd:fardatasegmentcommon;允许同名段重叠
ary
dw1,2,3,4,5,6,7,8,9,10countdw10sumdw?dataendscode1segmentmainprocfarassumecs:code1,ds:datastart:
movax,data
mov
ds,ax
callfarptr
proadd
movah,4ch
int21hmainendpcode1endsendstart;proadd2.asmpublicproadddatasegmentcommon
ary
dw1,2,3,4,5,6,7,8,9,10countdw10sumdw?dataends
code2segmentproaddprocfarassumecs:code2,ds:data
movax,data
mov
ds,ax
pushaxpushcxpushsileasi,ary
mov
cx,count
xorax,axnext:addax,[si]addsi,2loopnext
movsum,ax
popsipopcxpopax
retproadd
endpcode2endsend补充:模块化程序设计思想在设计大型程序时,常常要将整个问题分解为若干个小问题,必要时还要将小问题再次分解为更小的若干问题,每个小问题编写成独立的源文件,最后将所有的源文件连接起来组合成一个大程序。也就是说,一个程序往往由多个源文件组成,那么构成一个程序的各个相对独立的源文件通常称为模块。这样把一个程序分成多个功能相对独立的程序模块分别编制、调试后,再用连接程序把它们连接在一起生成一个完整的程序的设计方法称为模块化程序设计。模块化程序设计的优点1.开发速度快2.可维护性与可读性强3.可移埴性强模块划分的原则和方法模块划分是一个自上而下的过程。主模块是一个总控模块,首先确定主要的模块,也就是说,要把总任务划分成几个主要的子任务。一般来说,可以分成输入任务、输出任务和一个
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 基因治疗药物临床研发现状报告:2025年市场前景分析
- 2025年食品工业节能减排技术改造项目质量管理体系报告
- 2025年下沉市场消费金融与金融机构合作模式创新与风险控制研究报告
- 2025年机械制造企业服务化转型中的服务创新与产业协同报告
- 快递市场2025年价格战背后的政府政策与行业规范研究报告
- 2023年知识竞赛策划方案大全
- 2023年银行招聘之银行招聘综合知识真题附答案
- 2023年系统集成项目管理工程师考试大纲复习知识
- 2023年继续教育信息化能力建设题库与答案
- 2023年造价工程师工程造价计价与控制试题及答案
- 2025工会知识测试题及答案
- 2025年塔城地区直遴选面试真题附详解含答案
- 2025机动车检测站授权签字人考试试题(附含答案)
- 内部竞聘选拔的方案
- 2025年法律专业基础知识考试试卷及答案
- DGTJ08-2232-2017 城市轨道交通工程技术规范
- 四川省成都市2023级高中毕业班摸底测试(成都零诊)化学试题及答案
- 2024华南理工大学辅导员招聘笔试真题
- 消化道异物护理常规
- 2025年光电耦合器行业现状分析:全球光电耦合器总产量将达到692.22亿颗
- 甘肃浙能武威能源有限公司招聘笔试题库2025
评论
0/150
提交评论