《汇编语言程序设计》第十一章:过程.ppt

上传人:za****8 文档编号:3205593 上传时间:2019-12-08 格式:PPT 页数:41 大小:1.74MB
返回 下载 相关 举报
《汇编语言程序设计》第十一章:过程.ppt_第1页
第1页 / 共41页
《汇编语言程序设计》第十一章:过程.ppt_第2页
第2页 / 共41页
《汇编语言程序设计》第十一章:过程.ppt_第3页
第3页 / 共41页
点击查看更多>>
资源描述
汇编语言程序设计-朱耀庭,南开大学朱耀庭,第11章过程,在编写程序时,常常发现在若干不同的点上都需要一个特定的指令序列,如果把这个指令序列插到程序中的每一个需要点上,必然会使程序的规模大大增加。程序员可以利用过程编程方法解决这个问题。将某个反复在程序中出现的程序片段设计成过程,缩短程序长度,节约存储空间。将某个具有通用性的程序片段设计成过程,实现许多程序共享,可以大大减少程序设计的工作量。另外,当某个程序片段的功能相对独立时,也可以把它设计成过程,这样便于模块化、调试和修改。本章详细论述过程的定义,过程的调用方法,并通过大量的实例进行说明。,南开大学朱耀庭,第11章过程,11.1过程的定义与说明,11.2过程调用,11.3过程的返回,11.4模块间的调用和转移,11.5寄存器的保护和恢复,11.6调用程序与被调用过程之间的数据传送,11.7递归,11.8C语言调用汇编过程,南开大学朱耀庭,11.1过程的定义与说明,南开大学朱耀庭,1.过程的定义,过程也称作子程序。将这一特定的指令序列编成一个过程的方法,称作“过程定义”。用一对伪指令PROC/ENDP定义一个过程,其格式如下:PROCNAMEPROCNEAR/FAR;过程体RETPROCNAMEENDP其中:PROCNAME是PROC和ENDP伪指令前面必须有的同一个过程的名称。在一个过程定义中,ENDP前面的过程名一定要和PROC前面的过程名一致,并且必须是合法的标识符。,南开大学朱耀庭,1.过程的定义,伪指令PROC和ENDP必须成对出现,表示过程的开始和结束。过程可以被指定为NEAR或FAR类型。如果没有指定,就认为是NEAR类型。如果一个过程要被别的程序跨段调用,就应将该过程说明为FAR类型。如果一个过程定义时被指明为NEAR类型或使用缺省类型说明,那么该过程仅能被本过程所在段的程序所调用。在一个过程中至少有一个RET返回指令。RET指令为过程的出口点,过程由该点结束本次过程调用,返回到调用者调用该过程的下一条指令继续程序的执行。,南开大学朱耀庭,2.过程的说明,编写过程的重要一环就是书写过程的说明信息,这样可以让不熟悉该过程的用户仍能正确快速地使用。过程的说明信息一般包括过程名称、功能、入口出口参数等。更详细的说明还包括存储单元、所用寄存器、作者、编写时间等内容,南开大学朱耀庭,2.过程的说明,例11-1过程说明实例。题目:主程序从键盘读入一个字符,如果是小写字母转化为大写字母输出,不是小写字母则直接输出。然后再继续下一个读入和转换,直到遇到输入为回车符结束。用户在程序运行时可以输入不同字符验证其正确性。设计思路:主程序用过程形式开始,以RET返回。主程序输入的非回车符调用过程UPPERCASE转换为大写字母后送入AL中返回并输出,如果输入回车符则结束。,例11-1过程说明实例,程序说明:主程序也可以不定义为过程,这时必须以INT21H的4CH号功能调用结束,南开大学朱耀庭,11.2过程调用,过程一经定义,在程序中每一个需要这一指令序列的位置都可以使用这个过程,对一个过程的使用称作“过程调用”。过程调用需要使用CALL指令。CALL指令的用法如下:CALLPARA其中PARA可以是一个过程名、间接寻址的寄存器或者是内存地址。过程调用分为两种类型:近过程调用(NEAR)和远过程(FAR)调用。汇编程序产生哪一种类型的CALL指令,取决于程序员所定义的过程名是NEAR类型还是FAR类型。近过程调用是指过程调用代码段和过程定义代码段位于同一代码段。当CALL指令产生一个近过程调用时,它把该指令之后的下一条指令地址压栈,即把返回地址的偏移量(16位)压栈,以供过程定义中的RET(返回指令)能将控制转回到CALL的下一条指令。,南开大学朱耀庭,11.2过程调用,类似地,当过程调用代码段和过程定义代码段不在同一代码段时,则CALL指令会产生一个远过程调用。不同的是,当CALL指令产生远过程调用时,不仅要把该指令之后的地址压栈,即把返回地址的偏移量压栈,而且也要把其段寄存器CS的值压栈。不同形式的CALL指令允许从指令中获得目标过程的入口地址(直接CALL),或从指令指定的存储单元或寄存器中获得目标过程的入口地址(间接CALL)。在保存断点进栈操作以前,处理器自动地修改IP或CS与IP以使它指向要执行的下一条指令。具体格式与JMP指令相似,也有4种格式:段内直接调用、段内间接调用、段间直接调用、段间间接调用,南开大学朱耀庭,11.2过程调用,1段内直接调用格式:CALLPROCNAME功能:其中PROCNAME是已经定义的近过程名。执行CALL指令调用时,首先保护返回地址,即将返回地址压栈,返回地址就是CALL指令所在位置的下一条指令的地址;保护好返回地址后将控制转移给过程。保护返回地址的具体操作是:SP(堆栈栈顶指针)减2,并将IP(指令指针)的内容压入堆栈;将控制转移给过程的具体操作是:将目标过程入口相对于CALL指令的相对位移量(-32K32K)加到指令指针IP中去。例11-1就是如此。请同学们解释其调用和返回过程,南开大学朱耀庭,11.2过程调用,2段内间接调用格式:CALLOPRD功能:其中OPRD是16位通用寄存器或字存储器操作数。执行该指令调用时,首先保护返回地址,将返回地址的偏移部分压入堆栈;然后将控制转移给过程。保护返回地址的具体操作是:SP减2,并将IP的内容压入堆栈。将控制转移的具体操作是:从CALL指令中指定的16位通用寄存器或字存储器中获得目标过程的入口地址(位移量),并用此地址替换IP的内容。例如:CALLWORDPTRBXCALLWORD_VARLABEL_NAMECALLWORDPTRBX+SI+2CALLWORDPTRDICALLWORD_VARLABEL_NAMEBPSICALLBX,南开大学朱耀庭,2.过程的说明,例11-2段内间接调用实例一题目:输入1、2、3分别对应输出R、G、B,输入其他符号则结束设计思路:设计3个过程pr、pg、pb分别输出R、G、B字符。主程序根据输入1、2、3分别用BX指向对应过程入口,通过段内间接调用实现过程调用,例11-2段内间接调用实例一,程序说明:过程pr、pg、pb均为近过程,因此调用时仅需修改IP实现调用。需要注意的是过程的调用方法。上述代码注释部分分别将几个过程入口地址的IP值送入寄存器BX中,通过语句callbx调用对应过程,属于段内间接调用。,南开大学朱耀庭,2.过程的说明,例11-3段内间接调用实例二题目:同例11-2设计思路:与例11-2不同的是定义表table,其中3个字分别存放过程pr、pg和pb的位移。主程序通过输入的数字n,计算(n-1)*2,从table中得到该位移,然后调用对应的过程,例11-3段内间接调用实例二,程序说明:与例11-2不同的是通过内存间接寻址调用过程,南开大学朱耀庭,11.2过程调用,3段间直接调用格式:CALLPROCNAME功能:其中PROCNAME是已经定义的远过程名。执行CALL指令调用时,CALL指令的功能是首先保护返回地址,然后将控制转移给远过程。保护返回地址的具体操作是:SP减2,将CS的内容压入堆栈;然后SP减2,将IP的内容压入堆栈。目标过程为FAR类型的过程,段间直接调用属于远调用,因此,将控制转移给远过程的具体操作是:将被调用过程所在段的段基址送入CS中,将被调用过程相对于其所在段的位移量送入IP中,以实现控制转移。,南开大学朱耀庭,2.过程的说明,例11-4段间直接调用实例题目:主程序从键盘读入一个字符,如果是小写字母转化为大写字母输出,不是小写字母直接输出。然后再输入下一字符继续上述工作,直到输入回车结束设计思路:与例11-1不同的是主程序和它所调用的过程分别放在不同的代码段,而不是在同一个代码段,例11-4段间直接调用实例,程序说明:本例中UPPERCASE过程与调用它的主过程不在同一个代码段中,分别处于CODE1和CODE2段。所以UPPERCASE过程使用了FAR关键字定义为远过程,这样在不同的代码段就可以直接调用该过程,南开大学朱耀庭,11.2过程调用,4段间间接调用格式:CALLOPRD功能:其中OPRD是双字存储器操作数。执行该指令调用时,首先保护返回地址,即把返回地址的段基址和偏移地址分别压入堆栈保存,然后将控制转移给远过程。保护返回地址的具体操作是:SP减2,将CS的内容压入堆栈,然后SP减2,将IP的内容压入堆栈。将控制转移的具体操作是:把双字存储器操作数的低字送入IP中,把双字存储器操作数的高字送入CS中,从而实现远转移。段间间接调用只能通过双字存储器进行,而不能通过寄存器进行。例如:CALLDWORDPTRBXCALLDWORD_VARLABEL_NAMESICALLDWORD_VARLABEL_NAME,南开大学朱耀庭,2.过程的说明,例11-5段间间接调用实例。题目:同例11-2和例11-3。设计思路:与例11-3不同的仅仅是主程序与它所调用的过程不在同一个代码段,例11-5段间间接调用实例,程序说明:本例与例11-3的功能类似,主要区别在于子过程与主过程不在同一代码段,所以过程定义需要使用FAR关键字,属于段间间接调用,南开大学朱耀庭,11.3过程的返回,过程调用时调用者将控制转移给过程,当过程执行完后,过程又会将控制返回给调用者,从调用过程的那个位置的下一条指令继续执行,实现“过程返回”。在一个过程中至少有一个RET(返回)指令被执行到。RET指令为过程的出口点,从此处返回调用过程的位置。格式:RET或RETn其中n是在弹出返回地址后,从堆栈中删除字节的个数。功能:过程的返回和调用在功能上是互逆的。所以过程的返回也分为远返回和近返回。返回指令在堆栈操作方面是调用指令的逆过程。,南开大学朱耀庭,11.3过程的返回,具体操作如下:(1)近返回:RET指令将SP所指向的栈顶字(断点的位移量)弹出送至指令指示器IP中,并将SP加2(2)远返回:RET指令先弹出栈顶之值送到IP中,再弹出栈顶之值送到CS中,并再将SP加4,南开大学朱耀庭,11.3过程的返回,如果选用RETn的格式,RET指令在完成RET的以上功能外,将n加到SP上去,即SP内容加n送入SP中,以废除调用过程时调用程序装入栈中的参数,使之恢复调用之前的栈顶。例如,指令:RET4,除了返回到调用程序的断点处,并恢复到调用过程指令CALL之前的栈顶外,还要将4加到SP上去,以废除两个参数所占用的堆栈空间(这两个参数是为所调用的过程提供的)。因为堆栈是以字为单位的,而RET中的弹出值是字节数,因此,若废除n个参数,则弹出值应为2n(即为偶数)。RETn格式往往用于带参数的过程的参数传递,特别是其他语言调用汇编语言过程时的参数传递。RETn返回的实例请参考例11-8,南开大学朱耀庭,11.4模块间的调用和转移,在实际编程过程中,特别是开发大型软件或多人共同开发一个软件时,往往会遇到调用者和被调用的过程不在同一个源程序文件中的情况,即调用者和被调用的过程不是在同一个模块中。在这种情况下,就需要对构成一个执行程序的多个源程序分别汇编生成对应的多个OBJ文件。然后应用连接程序将这多个OBJ文件最终连接生成一个可执行文件,即EXE文件。然而问题还不这么简单,在分别汇编时如果一个源程序文件中出现了一个不属于本文件的过程名,汇编时就会出现错误,解决的办法是在这一源程序文件中将该过程说明成外部过程;又被调用到过程所在的源程序文件中,还需要将该过程说明为公用的;这样在连接时,只要提供了调用者和被调用者所在的OBJ文件就可以生成一个真正的执行文件。这正是本节所要解决的问题。,南开大学朱耀庭,11.4模块间的调用和转移,南开大学朱耀庭,1.模块间的调用和转移的程序结构,(1)公用说明伪指令PUBLIC格式:PUBLIC符号,说明:符号是本汇编模块中所定义的一个数值、变量、标号或过程名功能:PUBLIC伪指令指明在连接时,本模块能提供给其他模块使用的符号。PUBLIC伪指令前不能带标号,可以在一个汇编模块中的任何一行出现。在PUBLIC伪指令中被说明的符号必须有定义。例如,publicstdcin,stdcout,dec8bin,hex8out。如果出现在某个源程序中,说明本程序中的stdcin,stdcout,dec8bin,hex8out可以被外部模块应用,供连接程序在连接过程中识别。,南开大学朱耀庭,1.模块间的调用和转移的程序结构,(2)外部说明伪指令EXTRN格式:EXTRN名称:类型,说明:名称是别的模块所定义的符号,而类型必须与说明它为PUBLIC的模块给它的类型说明一致功能:EXTRN伪指令把某些符号的段和类型的属性告诉汇编程序。这些符号是本模块所要使用的,但是它们是在其他模块中定义的。在那些模块中必须用PUBLIC伪指令来说明这些符号,而且那些模块应与本模块连接在一起。,南开大学朱耀庭,1.模块间的调用和转移的程序结构,例11-6模块间相互调用实例题目:编写由EX11-6-1.asm和EX11-6-2.asm生成的可执行程序。要求前者含有被后者调用的过程,共同完成输入一个十进制数,输出其对应的十六进制数,输入0结束。设计思路:主程序main和输出回车换行过程在EX11-6-2.asm中。主程序调用EX11-6-1.asm中的过程dec8bin将输入的十进制数转化为二进制数存入BL中,然后调用crlf输出回车换行后调用hex8out以十六进制输出,例11-6模块间相互调用实例,程序说明:EX11-6-1使用到了public关键字来声明过程,使这些过程可以被外部模块调用。EX11-6-2中使用了extrn、far等关键字,表明待调用的过程为外部远过程。该程序输入数范围应为0255,否则结果不正确。具体程序解释请参考注释,南开大学朱耀庭,2连接程序的伪指令及其参数,1)连接程序所用到的伪指令连接程序用到的伪指令,除上节提到的公用说明伪指令PUBLIC和外部说明伪指令EXTRN外,本节还将涉及源程序结束伪指令END和模块名伪指令NAME。END伪指令指出源程序的结束使汇编程序停止汇编操作。NAME伪指令用于给汇编程序产生的目标模块指定名称。2)连接程序的步骤调试例11-6-1,生成执行文件EX11-6-1.exe的步骤如下:(1)编译:利用masm命令分别编译EX11-6-1.asm和EX11-6-2.asm(2)链接:使用link命令,如linkEX11-6-1+EX11-6-2,生成EX11-6-1.exe(3)执行:调用EX11-6-1.exe,南开大学朱耀庭,11.5寄存器的保护和恢复,程序设计者必须明白,寄存器与存储器一样对于所有的程序都是公用的。因此当调用者调用一个过程时,如果该过程将某个寄存器的值改变了,而返回后,调用者仍然需要使用该寄存器的原有值。在这种情况下,该过程在使用该寄存器前必须保留该寄存器的副本,通常的方法是,将其压入堆栈,返回前再由堆栈弹出恢复原有值。下面将举例说明:,南开大学朱耀庭,11.5寄存器的保护和恢复,例11-7过程中寄存器的保护实例题目:主程序调用NCOUT输出5行由*组成的三角形。第1行5个*,第2行4个*,.第5行1个*设计思路:过程NCOUT入口参数n在CX中,输出符号在DL中。功能是输出由n行DL中符号组成的三角形。主程序将5送入CX中,将*送入DL中,输出5行由*组成的三角形。,例11-7过程中寄存器的保护实例,本程序执行结果如下:*,南开大学朱耀庭,11.5寄存器的保护和恢复,例11-7过程中寄存器的保护实例程序说明:由于过程CRLF完成输出回车换行的任务,需要修改DX寄存器,所以在该过程开始时将DX寄存器压入堆栈,而在该过程返回时弹出。经过这样的操作,DX寄存器中的内容在CRLF过程调用前后保持一致。同样的,过程NCOUT输出一行*,而*的个数由当时的CX寄存器决定。由于主过程对CX寄存器中内容递减,并调用NCOUT输出倒三角,而NCOUT中也使用了CX寄存器作为循环使用,所以在NCOUT中要对CX进行保护。通过大量的例子可以看到,大多数过程都需要修改寄存器的内容,当返回到调用它的程序时,这些寄存器的内容也就不会是调用过程前的内容。出现这种情况会导致程序出错,并且很难查找到错误来源。为此,需要对相关的寄存器进行保护,当过程返回时进行寄存器的恢复。,南开大学朱耀庭,11.5寄存器的保护和恢复,一般的寄存器保护和恢复的方法是在过程开始时将可能使用到的寄存器依次入栈,在过程返回前再将寄存器出栈。形式如下:TESTPROCPUSHAXPUSHBXPUSHCX.POPCXPOPBXPOPAXRETTESTENDP注意:(1)寄存器入栈和出栈的顺序相反。(2)如果需要的话,使用PUSHF和POPF保护和恢复标志寄存器。,南开大学朱耀庭,11.6调用程序与被调用过程之间的数据传送,南开大学朱耀庭,1.利用寄存器传送数据,由于寄存器在任何程序中都是可见的,对某寄存器赋值后,其他程序中就能直接访问,因此,使用寄存器来传递参数会非常直接、简便。但是寄存器的个数和容量都是有限的,而且寄存器中经常还要保存其他数据,所以,此方法适用于传递较少的参数信息,南开大学朱耀庭,2.利用存储器传送数据,当需要向子程序传递大量数据时,一般使用存储器传输参数。利用存储器传送数据通用性比较差,通常是把一个参数表(数据表)放在某一数据区,然后把这个数据区的首地址传送给过程,而过程把计算结果送至某一个变量,南开大学朱耀庭,3.利用堆栈传送数据,利用堆栈是最常用的过程之间传递数据的方法例11-8利用堆栈传送数据程序实例题目:主程序压入堆栈3个数201、301、101和数的个数3。调用过程访问堆栈,求3个数的平均值送入AX中,然后调用另一过程将其以十进制形式输出设计思路:AVERAGE_N通过堆栈获取数的个数和每个数,然后将平均值送入AX中,过程OUTPUT_PROC将AX中二进制数转化为十进制数输出,例11-8利用堆栈传送数据程序实例,南开大学朱耀庭,3.利用堆栈传送数据,例11-8利用堆栈传送数据程序实例程序说明:在此例中可以看出访问堆栈的另一方法:即将某一时刻的栈顶指针SP的值送给BP,使BP指向堆栈中某一位置,然后用地址表达式BPdisp间接访问堆栈的非栈顶字(或字节)。其中disp是此字(或字节)距离BP指向的位置的相对位移量(字节数)。高级语言主程序调用汇编过程进行参数传递就是用这一方法。,南开大学朱耀庭,11.7递归,例11-9递归程序实例一题目:用递归方法编写程序,在一行输出n个*设计思路:过程nSTAR从CX中得到n,如果n为0则返回,否则输出一个*后,n-1送入cx中再递归调用nSTAR,实现一行输出n个*,例11-9递归程序实例一,程序说明:本例中的nSTAR过程使用了递归的方法,即调用自身。当CX寄存器不为0时就将CX减1并调用自身,直至CX为0返回输出*,南开大学朱耀庭,11.7递归,例11-10递归程序实例二题目:用递归计算1+2+3+11,然后将其和作为ASCII码输出设计思路:过程MYSUM从CX中获得n,递归计算1+2+n,例11-10递归程序实例二,程序说明:本例中的MYSUM过程使用了递归的方法。当CX寄存器不为0时就将CX压栈后CX减1再调用自身,接着堆栈弹出一个字与DX相加,直至CX为0返回。返回后,所求和1+2+3+n在DL中,南开大学朱耀庭,11.8C语言调用汇编过程,例11-11C语言调用汇编过程实例题目:写TurboC2.0的主函数main()调用由汇编写的子函数(即过程)_SORT对数组排序设计思路:TurboC调用子函数sort(i,a)时将i,a压栈后将返回地址压栈。汇编过程sort利用BP访问堆栈对数据排序,例11-11C语言调用汇编过程实例,程序说明:一般情况下,如果汇编程序中定义的过程或者变量准备供TurboC调用,应以下划线开头,也可以在PUBLIC后加C标明调用的语言类型,南开大学朱耀庭,11.8C语言调用汇编过程,首先对汇编过程进行编译,生成OBJ文件,并把该OBJ文件复制到C源程序同级目录下。然后,打开TurboC2.0,创建PRJ文件,并写入如下代码:EX11-11-2.cEX11-11-1.obj最后,使用Compile选项下的BuildAll即可生成对应的可执行文件。由于TurboC对字母的大小写敏感,而MASM汇编生成的OBJ文件均为大写字母,所以要对TurboC2.0做以下设置:进入OPTION下的LINKER选项,将CASE-SENSITIVELINK选项设置为OFF状态,保存修改设置。这里需要注意的是栈内的情况:SP:偏移量SP+2:段地址SP+4:参数1SP+6:参数2,南开大学朱耀庭,ThankYou!,
展开阅读全文
相关资源
相关搜索

当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!