汇编语言程序设计第9章子程序设计.ppt
2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,1,8086/8088和ARM核汇编语言程序设计,第9章 子程序设计,教学重点:子程序设计方法,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,2,9.2 子程序的参数传递,9.3 子程序嵌套与递归,第9章 子程序设计,9.1 子程序设计方法,9.4 子程序库,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,3,子程序又称为过程,是能完成特定功能有一定通用性的程序段,在需要时能被其它程序调用。调用子程序的程序常称为主程序。一般把源程序中反复出现的程序段或常用的功能独立的程序段设计成子程序供用户使用。这样可以简化源程序结构、节省目标程序的存储空间,提高程序设计的效率。子程序结构也是模块化程序设计的基础。本章主要介绍子程序的定义、子程序调用和返回、子程序的参数传递以及子程序库等知识。,9.1 子程序设计方法,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,4,9.1 子程序设计方法,9.1.1 子程序的定义,子程序的定义是由过程定义伪指令PROC和ENDP实现,格式如下:过程名 PROCNEAR|FAR;过程体过程名 ENDP,NEAR 属性的过程只能被相同代码段的其他程序调用,FAR 属性的过程可以被不同代码段的程序调用。,(1)子程序和主程序在同一个代码段中,则子程序定义为NEAR属性。(2)子程序和主程序不在同一个代码段中,则子程序定义为FAR属性。(3)主程序通常定义为FAR属性,这是因为主程序被看作DOS调用的一个子程序,以便执行完返回DOS。,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,5,9.1 子程序设计方法,9.1.1 子程序的定义,子程序可以放在代码段主程序开始执行之前的位置,也可放在代码段的末尾主程序执行终止后的位置。,为了便于其他程序员能正确使用子程序,在编写子程序时,还要养成书写子程序说明信息的良好习惯。子程序说明信息一般包括以下内容:(1)子程序名(2)功能描述(3)入口和出口参数(4)调用注意事项和说明等,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,6,9.1 子程序设计方法,9.1.1 子程序的定义,例9.1 编写一个子程序,从键盘输入一位十进制数。;子程序名:stdin;功能:完成从键盘输入一位十进制数;入口参数:等待键盘输入;出口参数:al中存放输入的数值stdinproc movah,1 int21h cmpal,30h jl next cmp al,39h jg next and al,0fh next:retstdin endp,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,7,9.1 子程序设计方法,9.1.2 子程序调用与返回,子程序调用与返回由CALL和RET指令实现。,子程序调用指令首先把子程序的返回地址(即CALL指令的下一条指令的地址)压入堆栈,然后转移到子程序的入口地址执行子程序。根据子程序和主程序是否在同一代码段,分为段内调用和段间调用。子程序和主程序在同一个代码段中称为段内调用;子程序和主程序不在同一个代码段中,称为段间调用。子程序返回指令负责把压入栈区的返回地址弹出送IP或CSIP,实现返回主程序继续往下执行。与子程序的段内调用和段间调用相对应,子程序的返回也分为段内返回和段间返回。,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,8,9.1 子程序设计方法,9.1.2 子程序调用与返回,当子程序和主程序在同一个代码段中,子程序的定义和调用如下图:,code segmentmain proc far call suba retmain endpsuba proc near retsuba endpcode ends,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,9,9.1 子程序设计方法,9.1.2 子程序调用与返回,当子程序和主程序不在同一个代码段中,子程序的定义和调用如下图:,code1 segmentmain proc far call far ptr suba retmain endpcode1 endscode2 segmentsuba proc far retsuba endpcode2 ends,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,10,9.1 子程序设计方法,寄存器内容的保护与恢复,通常主程序和子程序是分别编制的,所以它们可能会使用同一个寄存器。如果主程序中某个寄存器的内容在调用子程序后还要用,而子程序又恰好使用了同一个寄存器,当子程序修改了寄存器的内容后,返回到主程序时,该寄存器的内容也就不会是调用子程序前的内容,这样,常常会导致调用程序的出错。为此,编写子程序时,在一进入子程序后,就把它所用到的寄存器内容压进栈,在返回前,再把它们弹出栈。,为什么寄存器的保护与恢复?,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,11,9.1 子程序设计方法,寄存器内容的保护与恢复,例如:若子程序PROG中改变了寄存器AX,BX,CX,DX的值,则 可采用如下方法保护和恢复现场。PROGPROCPUSHAXPUSH BX PUSHCX;保护现场PUSHDX POPDXPOPCXPOPBX;恢复现场POPAXRET;返回断点处PROCENDP,注意:堆栈“先进后出”的操作特点,恢复寄存器的顺序不能搞错。,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,12,9.2 子程序的参数传递,用寄存器传递参数,优点:直接、简便,只要把参数存放在约定的寄存器中就行了。缺点:适用于传递参数较少的情况。,例9.3 从键盘输入一组字符,直到“0”为止。编一子程序,完成当输入是小写字母时,则修改为大写字母。输入的字符存放在string为首址的存储单元中。,参数可以增加子程序的灵活性和通用性。调用程序传送给子程序的参数称为入口参数,子程序返回给调用程序的结果称为出口参数。,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,13,9.2 子程序的参数传递,用寄存器传递参数,;主程序Data segment string db 100 dup(?)data endscode segment assume cs:code,ds:data start:mov ax,data mov ds,axmov di,offset stringagain:mov ah,1int 21hcmp al,,0je exitcall stobmov di,alinc dijmp againexit:mov ah,4chint 21h,;子程序名:stob;功能:将小写字母修改为大写字母;入口参数:al存放输入的字符;出口参数:al存放修改后的字符stob proc nearcmp al,61hjb nextcmp al,7ahja nextsub al,20h next:retstob endpcode endsend start,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,14,9.2 子程序的参数传递,9.2.2 用存储单元传递参数,这种方法是使用存储单元传递参数的,即主程序在存储单元建立一个参数表,存放子程序所要的参数,在主程序中将该参数表首地址传送给子程序,子程序通过参数表取得所需参数,并把结果也存放到指定存储单元中。优点:适合于传递参数较多的情况。,第十六讲,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,15,9.2 子程序的参数传递,9.2.2 用存储单元传递参数,例9.4使用存储单元传递参数的方法来实现例9.3。,;主程序datasegment stringdb100 dup(?)Lentdw?dataendscodesegmentassumecs:code,ds:datamain proc far start::push dsmov ax,,0push axmovax,datamovds,axmovcx,0movdi,offset string again:movah,1int21hcmpal,0jenext,movdi,alincdiinccxjmpagain next:mov lent,cxleabx,stringcallstob1ret,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,16,9.2 子程序的参数传递,9.2.2 用存储单元传递参数,;子程序名:stob1;功能:将小写字母修改为大写字母;入口参数:bx存放数据存储单元首址;出口参数:修改后的字符存回原存储单元中stob1procmovcx,lent again1:moval,bxcmpal,61hjbnext1cmpal,7ahjanext1subal,20hmovbx,al next1:incbxdeccxjnzagain1retstob1endpmainendpcodeends end start,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,17,9.2 子程序的参数传递,9.2.3 用堆栈传递参数,用堆栈传递入口参数时,要在调用子程序前把有关参数依次压栈,子程序从堆栈中取得入口参数;用堆栈传递出口参数时,要在子程序返回前,把有关参数依次压栈,主程序就可以从堆栈中取到出口参数。优点:适合于传递参数较多的情况。注意:避免因堆栈操作而造成子程序不能正确返回的错误。,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,18,9.2 子程序的参数传递,9.2.3 用堆栈传递参数,例9.5编一子程序:求有符号字数组array中元素的最小值。数组元素的个数存放在cont字单元中。Datasegmentarray dw 100,66,-1,88,20cont dw5min dw?data endsstack segmentdw 128 dup(?)stackendscode segmentassume cs:code,ds:data,ss:stackstart:movax,datamov ds,axmov ax,offset array push ax;数组偏移地址进栈movax,contpush ax;元素个数进栈callfindminmovmin,ax;保存出口参数movah,4chint21h,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,19,9.2 子程序的参数传递,9.2.3 用堆栈传递参数,;子程序名:findmin;功能:求有符号字数组中元素的最小值;入口参数:数组首地址和元素个数在堆栈中;出口参数:ax中存放最小值findminprocpushbpmovbp,sp;为取参数作准备pushbxpushcxmovbx,bp+6;从堆栈中取数组首地址送bxmovcx,bp+4;从堆栈中取元素个数送cxdeccxmovax,bx;取出第一个元素给AXagain:addbx,2cmpbx,ax;与下一个数据比较jgnextmovax,bxnext:loopagainpopcxpopbxpopbpret,fminendpcodeendsendstart,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,20,9.3 子程序嵌套与递归,一个子程序也可以作为调用程序去调用另一个子程序,称为子程序嵌套。,递归子程序:如果一个子程序调用的是子程序的本身,就是递归子程序。,例9.6编程计算n!(设0n6)分析:求n!的递归定义为:,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,21,9.3 子程序嵌套与递归,Data segmentNum db 3Result dw?Data endsStack segment para stack stack db 100 dup(?)Stack endsCode segment assume cs:code,ds:data,ss:stackMain proc farBegin:push ds xor ax,ax push ax mov ax,data mov ds,ax,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,22,9.3 子程序嵌套与递归,mov ah,0 mov al,num call factor mov result,ax retMain endp,Factor proc push ax sub ax,1 jne f_cont pop ax jmp returnf_cont:call factor pop cx mul clreturn:retfactor endpCode ends end begin,IP1,Mov result,ax 地址,3,IP2,Pop cx 地址,2,IP3,Pop cx 地址,1,ax=1,IP POP CX 地址,cx=2,ax*cx=1*2,IP POP CX 地址,cx=3,ax*cx=1*2*3,IP Mov result,ax 地址,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,23,9.4 子程序库,开发大型应用程序时,通常把复杂的程序分成很多功能独立的模块,分别编写成子程序,对各个子程序模块单独进行汇编产生相应的目标模块(OBJ文件),最后再用连接程序把它们连接起来,形成一个完整的可执行程序。采用这种模块化程序设计方法,程序不但结构清晰,也便于调试。采用模块化程序设计,各模块之间会存在着相互调用,即一个模块会引用在另一个模块中定义的标识符(包括变量、标号、过程名等)。标识符有两种:1)在本模块中定义,供本模块使用的标识符称为局部标识符;2)在一个模块中定义,而又在另一个模块中引用的标识符称为外部标识符。,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,24,9.4 子程序库,为了解决各模块间标识符的交叉访问,汇编语言提供了二条伪指令PUBLIC和EXTRN。,(1)伪指令PUBLIC说明:当前模块中哪些标识符是能被其它模块引用的外部标识符。其格式如下:PUBLIC 标识符,标识符,;定义标识符的模块使用,(2)伪指令EXTRN说明:在当前模块所使用的标识符中,哪些标识符是已在其它模块中被定义为指定类型的标识符。格式如下:EXTRN 标识符:类型,标识符:类型,;调用标识符的模块使用,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,25,9.4 子程序库,例9.7 从键盘输入一个数n((0n6),求n!,并输出结果。把例9.1、例9.2例和9.6的子程序编写成子程序模块,供主程序调用。,;子程序stdin.asmpublicstdincodesegmentstdinprocfar;例9.1中的输入子程序stdinstdinendpcodeendsend;子程序dispax.asmpublicdispaxdatasegmentdb4dup(?),0ah,0dh,$dataendscodesegmentdispaxprocfar;例9.2中的输出子程序dispaxdispaxendpcodeendsend,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,26,9.4 子程序库,;子程序fact.asmpublicfactcodesegmentfactprocfar;例9.6中求n!子程序factfactendpcodeendsend;主程序main.asmextrnstdin:far,fact:far,dispax:farStacksegmentDw128dup(0)StackendsCodesegmentAssumecs:code,ss:stackStart:callstdin,mov ah,0call factcall dispaxmov ah,4chInt 21hcode endsend start,2023/9/12,第1章 汇编语言基础知识 9章 子程序的设计,27,9.4 子程序库,用汇编程序把它们分别汇编成目标文件stdin.obj、dispax.obj和fact.obj。当子程序模块很多时,可以把它们统一管理起来,存入一个或多个子程序库中。库文件可以把它看成是子程序的集合。MASM系统提供了库管理程序LIB.EXE,可以建立、组织和维护子程序库。,教学要求,掌握子程序设计方法熟悉常见程序设计问题:子程序要利用过程定义伪指令声明子程序最后利用RET指令返回主程序,主程序执行CALL指令调用子程序(3)子程序开始应该保护使用到的寄存器内容,子程序返回前相应进行恢复(4)处理好子程序与主程序间的参数传递问题作业:P147:2、4、8,