好文档就是一把金锄头!
欢迎来到金锄头文库![会员中心]
电子文档交易市场
安卓APP | ios版本
电子文档交易市场
安卓APP | ios版本

pc汇编语言程序设计课件_第8章_子程序设计.ppt

112页
  • 卖家[上传人]:bin****86
  • 文档编号:57189595
  • 上传时间:2018-10-19
  • 文档格式:PPT
  • 文档大小:493KB
  • / 112 举报 版权申诉 马上下载
  • 文本预览
  • 下载提示
  • 常见问题
    • 第八章 子 程 序 设 计,8.1 子程序的定义、 调用和基本要求 8.2 调用程序和子程序之间的参数传递方式 8.3 子程序设计举例 8.4 子程序的嵌套和递归 习题八,8.1 子程序的定义、调用和基本要求,8.1.1 过程(子程序)的定义过程的定义由过程定义伪指令完成 过程定义伪指令的格式如下:,过程名(子程序名)不能省略,其定义方法与标号和变量名类似一个过程一经定义就有了FAR或NEAR的属性通常如果调用程序与过程在同一个代码段内, 则过程的属性定义为NEAR; 如果调用程序和过程不在同一个代码段内, 则必须将过程定义为FAR属性8.1.2 过程调用与返回指令对过程的正确调用和返回是保证有子程序的程序能正确运行的基础 通常调用子程序用CALL指令, 由子程序返回用RET指令 CALL指令与RET指令配对出现 1. 过程调用指令 CALL由于子程序与调用程序可以在一个段中,也可以不在同一段中,因此与JMP指令类似, 这两条指令也有四种不同的寻址方式1) 段内直接调用指令 汇编格式: CALL NEAR PTR DST 执行的操作: (SP)←(SP)-2 (SP内容减2,指向新的栈顶)((SP)+1和(SP))←(IP) (将IP内容存入栈顶字单元)  (IP)←(IP)+disp (实现段内转移),这条指令先把子程序的返回地址(即CALL指令的下一条指令地址)存入堆栈中,以便由子程序返回主程序。

      然后将子程序第一条指令的地址装入IP指令中DST为转向地址,汇编后在机器指令中是以偏移量的形式给出的,偏移量等于转向地址和返回地址之间的差值 这种调用方式直接在CALL指令后书写过程名, 例如:  CALL PROC-A ; PROC-A为当前代码段中的过程(子程序)名,CPU执行; 此指令时, 将段内偏移地址加在IP上, 找到PROC-A,(2) 段内间接调用指令  汇编格式: CALL WORD PTR DST 执行的操作 (SP)←(SP)-2((SP)+1和(SP))←(IP)(IP)←(EA) 其中, EA是由DST的寻址方式所确定的有效地址这种调用方式的子程序(过程)的入口地址(段内偏移地址)在一个通用寄存器或一个字存储单元中,例如:  CALL BX ;(IP)←(BX);BX寄存器的内容是当前代码段中子程序的入口地址 CALL MEM_W ; (IP)←(MEM-W), MEM-W为数据段中的 一个字单元地址, ; 其内容是当前代码段中子程序的入口地址,(3) 段间直接调用指令 汇编格式: CALL FAR PTR DST 执行的操作: (SP)←(SP)-2 (SP内容减2,指向新的栈顶)((SP)+1和(SP))←(CS) (将CS内容存入栈顶字单元)  (SP)←(SP)-2 (SP内容减2,指向新的栈顶)((SP)+1和(SP))←(IP) (将IP内容存入栈顶字单元)(IP)←转向偏移地址(指令的第2、 3个字节)(CS)←转向段基址(指令的第4、 5个字节),即先保留返回地址,然后转移到由DST指定的子程序入口。

      由于调用程序和子程序不在同一个段内,因此,返回地址的保存以及转向地址的设置都必须涉及段基址的保护和设置 这种调用方式直接在CALL指令后书写属性为FAR的过程(子程序)名, 或用属性修改运算符PTR将过程的属性说明为“FAR” 例如:  CALL PROC_B ; (CS)←SEG PROC_B,(IP)←OFFSET PROC_B; PROC_B 为其它代码段中的过程名,具有FAR属性 CALL PTR FAR PROC_C ; (CS)←SEG PROC_C, (IP)←OFFSET PROC_C; PROC_C 为其它代码段中的过程名,具有FAR属性,(4) 段间间接调用指令汇编格式: CALL DWORD PTR DST执行的操作: (SP)←(SP)-2((SP)+1和(SP))←(CS)(SP)←(SP)-2((SP)+1和(SP))←(IP)(IP)←(EA)(CS)←(EA+2) 其中, EA是由DST的寻址方式确定的有效地址这种调用方式,在CALL指令中给出的是由四个字节组成的地址指针的首地址,而子程序的入口地址在该地址指针中:低字存放子程序入口地址的段内偏移地址,高字存放段基址。

      例如:,CALL DWORD PTR MEM-D ; (CS)←(MEM_D+2,MEM-D+3),(IP)←(MEM_D,MEM_D+1) ; MEM_D为数据段中的一个双字单元地址,其低字存放有子程序入 ; 口地址的段内偏移地址, 高字存放有子程序的段基址 CALL DWORD PTR [BX] ; (CS)←((BX)+2,(BX)+3), (IP)←((BX),(BX)+1)) ; BX的内容指出数据段中连续四个字节的内容, 分别为子程序入 ; 口地址的段内偏移地址和段基址,2. 由过程(子程序)返回指令 RET指令格式: RET [n]RET指令必须是子程序中最后执行的一条指令, 其作用是返回调用程序继续执行,由于返回地址是由CALL指令放在堆栈中的,因此, RET指令的操作是将返回地址出栈送入IP寄存器 如果是段间调用,还需将CS寄存器恢复如果过程(子程序)被定义为NEAR属性, 则汇编程序在翻译位于该过程中的RET指令时,将其汇编成段内返回指令编码,CPU在执行RET指令时, 将当前栈顶的内容送入IP如果过程(子程序)被定义为FAR属性,则汇编程序在翻译位于该过程中的RET指令时,将其汇编成段间返回指令编码, CPU在执行RET指令时,将当前栈顶的连续四个字节的内容分别送入IP和CS。

      (1) 段内返回指令 汇编格式: RET执行的操作: (IP)←((SP)+1和(SP)) (将栈顶字单元内容弹出,装入IP)(SP)←(SP)+2 (SP内容加2,指向新的栈顶),(2) 段内带立即数返回指令汇编格式: RET n执行的操作: (IP)←((SP)+1和(SP))(SP)←(SP)+2(SP)←(SP)+ n (SP内容加n,指向入口参数入栈前的栈顶)指令中n为立即数,是一个正的偶数该立即数待返回地址出栈后用以修改堆栈的指针SP调用程序若采用堆栈传送入口参数,供子程序使用,从子程序返回后,这些参数已不再有用,就可以用该立即数修改堆栈指针使其指向入口参数入栈以前的位置3) 段间返回指令 汇编格式: RET执行的操作: (IP)←((SP)+1和(SP)) (将栈顶字单元内容弹出,装入IP)  (SP)←(SP)+2 (SP内容加2, 指向新的栈顶)(CS)←((SP)+1和(SP)) (将栈顶字单元内容弹出, 装入CS)(SP)←(SP)+2 (SP内容加2, 指向新的栈顶),(4) 段间带立即数返回指令汇编格式: RET n执行的操作: (IP)←((SP)+1和(SP))(SP)←(SP)+2(CS)←((SP)+1和(SP))(SP)←(SP)+2(SP)←(SP)+ n (SP内容加n, 指向入口参数入栈前的栈顶),这里n的含义及使用情况与段内带立即数返回指令相同。

      要注意的是,一个过程执行的最后一条指令必定是返回指令(RET),用来返回调用程序的断点处, 即CALL指令的下一条指令因此,在一个过程(子程序)中至少要包含一条RET指令,如果程序有多个出口,则可以有多个RET指令 CALL指令和RET指令都不影响标志位8.1.3 子程序设计的基本要求设计子程序时,应尽量考虑使子程序具有通用性且使用方便为此,在设计子程序时应考虑如下几个问题1. 寄存器的保护 由于子程序是功能相对独立的一个程序,因此子程序不可避免地要用到一些寄存器,而这些寄存器调用程序在调用子程序前后可能也要使用如果调用程序在调用子程序前后需要这些寄存器的内容保持一致,则对这些寄存器的内容必须加以保护 对这些寄存器信息的保存可以有以下方法1) 在调用程序中保护具体要保存哪些寄存器的信息可根据调用程序使用的寄存器来确定例如,调用程序正在使用AX、 BX、 SI寄存器, 则在调用子程序之前,先保护AX、 BX、 SI的内容, 从子程序返回后立即恢复,其形式如下:,(2) 在子程序中保护对子程序要用到的寄存器内容的保护也可以在子程序中进行 例如,子程序需要使用AX、CX、SI寄存器,则在子程序开始先保护AX、 CX、 SI的内容,子程序返回之前(RET指令前),再恢复这些寄存器的内容,这样子程序的形式如下:,2. 堆栈的正确使用CPU在执行调用指令(CALL)时,自动地在堆栈中保存子程序的返回地址; 而当其执行RET指令时,从栈顶弹出子程序的返回地址。

      如果在子程序的执行过程中也使用了堆栈(如在子程序中用堆栈保存寄存器的内容),则为保证子程序正确返回,必须保证堆栈指针正确 这一点在编程时应该特别小心, 以免出错3. 子程序与调用程序之间参数的传递方法一般来讲,子程序都要对某些数据进行加工运算, 而这些数据往往要由调用程序提供,另一方面,子程序对数据的运算结果又需要提供给调用程序 二者之间这种信息交换称为调用程序和子程序之间的参数传递 参数传递的方法有多种, 但无论采用哪种方法,在设计调用程序和子程序前,必须先约定好要使用的方法,在设计调用程序和子程序时, 要遵守约定4. 子程序说明文档的编写由于子程序是功能相对独立的程序段,为便于程序阅读以及其它人使用,应当提供有关子程序的详细说明文档 子程序的说明文档应该包括:  (1) 子程序名 (2) 子程序功能的详细描述 (3) 子程序的入口参数和出口参数 (4) 子程序使用了哪些寄存器, 调用之前是否需要保护 (5) 子程序占用堆栈情况, 是否嵌套调用了其他子程序 (6) 子程序占内存多少、 执行时间长短、 影响哪些标志、 出错如何处理等其他情况 (7) 给出子程序的调用形式及调用示例。

      8.2 调用程序和子程序之间的参数传递方式,8.2.1 寄存器传递方式寄存器传递方式是最常用的一种参数传递方式使用这种方式传递参数简单方便,但寄存器数量有限,当要求传递的参数较多时不宜采用寄存器传递方式需预先约定用来传递参数的通用寄存器调用程序将要传送的参数送到约定的寄存器中, 子程序从约定的寄存器中取得参数;并在返回调用程序前,将运算结果存放到约定的寄存器,返回后,由调用程序到约定存放结果的寄存器中取结果例 8.1 编程将若干个给定的 16 位二进制数转换为对应十六进制数的ASCII码 二进制数与十六进制数之间的转换,只需将二进制数每 4 位组合在一起就构成了十六进制数十六进制数 0~F所对应的ASCII码可分两段来求取:0~9 与A~F 若是 0~9,只需加上30H就可得到 0~9 的ASCII码;若是A~F, 则需加上 37H 程序采用主程序和子程序的结构形式主程序提供待转换的 16 位二进制数和转换后ASCII码的存储区首址,子程序实现具体的转换, 图 8.1 为程序流程图, 程序清单如下:,图 8.1 16 位二进制数转换为对应十六进制数的ASCII码,主程序 MYDATA SEGMENT BIN1 DW 5679HASCD1 DB 4 DUP(0) MYDATA ENDS STACK1 SEGMENT PARA STACKDW 40H DUP(0) STACK1 ENDS MYCODE SEGMENTASSUME CS:MYCODE,DS:MYDATA,SS:STACK1 MYSTART: MOV AX, MYDATA MOV DS, AX,。

      点击阅读更多内容
      关于金锄头网 - 版权申诉 - 免责声明 - 诚邀英才 - 联系我们
      手机版 | 川公网安备 51140202000112号 | 经营许可证(蜀ICP备13022795号)
      ©2008-2016 by Sichuan Goldhoe Inc. All Rights Reserved.