大学生新闻网

汇编子程序的设计方法

4.4.1 程序设计概述

  与高级语言程序设计类似,用汇编语言进行程序设计时同样按以下步骤进行。

  分析问题,建立数学模型;

  确定算法;

  编制程序流程图;

  编写程序;

  上机调试。

   初学程序设计者往往不习惯编制程序流程图。实际上,在编写程序前先构思程序流程图,不仅能加速程序的编制,而且对程序在逻辑上的正确性也比较容易查找和 修改。有了程序流程图,即可根据流程图,逐条编写程序。在编写程序时要注意程序的基本格式,分清指令语句和伪指令的不同用途,正确使用各种寻址方式和指令 系统中的各种指令。

  有关源程序的基本结构做如下说明。

  (1)一个汇编语言源程序一般具有代码段、数据段、堆栈段 和附加段。8086/8088/80286允许同时使用4个段。80386/80486除以上4个段外,还增加了FS和GS两个附加数据段。在实际程序 中,只有代码段是必需的,其他段都为可选。在实地址方式下,每个段的大小为小于等于64KB;在保护方式下,每个段最大长度允许4GB。

  (2)ASSUME伪指令只说明各段寄存器和逻辑段的关系,并没有为段寄存器赋值。因此,在源程序中,除代码段CS和堆栈段SS(在组合类型中选择了STACK参数)外,其他定义的段寄存器由用户在代码段起始处用指令进行段基址的装入。

  (3)每个源程序在代码段中都必须含有返回DOS操作系统的指令语句,以保证程序执行结束后能自动返回DOS状态。终止当前程序,使其正确返回DOS状态有以下几种:

  ①采用DOS功能与程序中的4CH功能调用

  这种方法在代码段结束前加以下调用语句:

  MOV AH,4CH;功能号4CH→AH

  INT 21H;中断调用

  ②采用标准序法,适用于定义为FAR的过程中

  此方式仅用于.COM格式的可执行文件。

  源程序编写结束后,应当输入计算机中进行调试。上机调试大致有以下四步:

  (1)使用编辑程序,将编写好的程序送入计算机,在盘中建立一个扩展名为.ASM的文件;

  (2)使用宏汇编程序,将扩展名为.ASM的源程序汇编成目标程序,在盘上获得扩展名为.OBJ的文件;

  (3)使用连接程序(LINK),将目标程序连接装配成可执行文件,其扩展名为.EXE,并存于盘上;

  (4)程序可运行,如果运行中仍有问题,可使用调试程序(DEBUG)进行调试,直到问题全部解决、运行正确为止。

  只有在计算机上通过运行的程序,才能认为是正确的程序。

  4.4.2 分支程序设计

  计算机可根据不同条件进行逻辑判断,从而选择不同的程序流向。程序的流向是由CS和IP(EIP)决定的,当程序的转移仅在同一段内进行时,只需修改偏移地址IP(EIP)的值;如果程序的转移是在不同的段之间进行,则段基址CS和偏移地址IP(EIP)均需要修改。

  转移指令分为无条件转移指令和条件转移指令。在设计分支程序前,请复习第3章有关转移指令的内容,尤其是条件转移指令。能否正确使用这些转移指令,是能否编写好分支程序的关键。

  分支程序设计要领如下。

   (1)首先要根据处理的问题用比较、测试等方式,或者用算术运算、逻辑运算,使标志寄存器产生相应的标志位。例如,比较两个单元的地址的高低、两个数的 大小,测试某个数据是正还是负,测试数据的某位是0还是1等。将处理的结果反映在标志寄存器的CF, ZF, SF, DF和OF位上。

  (2)根据转移条件选择转移指令。通常一条条件转移指令只能产生两路分支,因此要产生n路分支需n-1条条件转移指令。

  (3)各分支之间不能产生干扰,如果产生干扰,可用无条件转移语句进行隔离。

  4.4.3 循环程序设计

  在程序中重复执行的程序段可用循环程序实现,80x86微机系统中有专门的循环控制指令来简化循环程序的设计。循环控制指令已在第3章进行了介绍,这里不再多叙。

  一个循环程序通常由四部分组成。

  1)初始化部分

  为循环操作做准备工作,建立循环的初始值,如初始化地址指针、计数器及给变量赋初值等。

  2)循环体

  循环体为循环的工作部分,用于完成各种具体操作,它可以是一个顺序结构、分支结构或又一个循环结构。若循环体内又包含有循环程序,则称为多重循环。

  3)修改部分

  为执行循环而修改某些参数,如地址指针、计数器或某些变量。

  4)控制部分

  判断循环是否结束,通常判断循环是否结束主要有两种方法:

  (1)计数器控制循环,这种方式一般用于循环次数已知的情况;

  (2)条件控制循环,用于循环次数未知,根据条件决定是否结束。

  【例4-2】计算Y∑20

  i1Ai

  设A1,A2……,A20是一组无符号16位二进制数,并设其和不大于2B。

  分析:定义数组名TABL存放A1,A2……,A20,和存放于单元YY中。中间结果存于寄存器AX中,BX寄存器为地址指针,CX寄存器作计数器。

  4.4.4 子程序设计

  程序设计过程中常常把多次引用的相同程序段编成一个独立的程序段,当需要执行这个程序段时,可以用调用指令调用它。具有这种独立功能的程序段称为过程或子程序。调用子程序的程序通常称为主程序,或调用程序。主程序向子程序的转移叫子程序调用,简称转子。

  1.子程序的设计方法

  适合编成子程序的程序有以下两大类:

  (1)程序需要反复使用,这类程序编写成子程序可避免重复编写程序,并节省大量存储空间。

  (2)程序具有通用性,这类程序大家都要用到,如键盘管理程序、磁盘读写程序、标准函数程序等。编成子程序后便于用户共享。

  为了使用户使用方便,子程序应当以文件形式编写。子程序文件由子程序说明和子程序本身两部分构成。

  1)子程序说明部分

  子程序说明部分应提供足够的信息,使不同的用户看了此部分后就知道该子程序的功能。子程序说明部分要求语言简洁、确切,一般由以下几部分组成:

  子程序的名称;

  子程序的功能;

  使用的寄存器和存储单元;

  子程序的入口、出口参数;

  本子程序是否又调用其他子程序。

  子程序从PROC语句开始,以ENDP语句结束,程序中至少应当包含一条RET语句用以返回主程序。在定义子程序时,应当注意其距离属性:当子程序和调用程序在同一代码段中时,用NEAR属性;当子程序及其调用程序不在同一个代码段中时,应当定义为FAR属性。

  当由DOS系统进入子程序时,子程序应当定义为FAR属性。为执行子程序后返回操作系统,在子程序的前几条指令中设置返回信息。

  2.子程序使用中的问题

  1)子程序的调用和返回

   主程序调用子程序是通过CALL指令来实现的。子程序执行后,通过RET指令,返回主程序调用指令CALL的下一条指令,继续执行主程序。一个子程序可 以由主程序在不同时刻多次调用。如果在子程序中又调用了其他的子程序,则称为子程序的嵌套。特别是当子程序又能调用子程序本身时,这种调用称为递归。有关 CALL指令和RET指令在第3章指令系统中已经详细介绍,这里不再重复。

  2)调用子程序时寄存器及所用存储单元内容的保护

  如果子程序中要用到某些寄存器或存储单元时,为了不破坏原有的信息,要将寄存器或存储单元的原有内容压栈保护,或存入子程序不用的寄存器或存储单元中。

  保护可以放在主程序中,也可以放在子程序中,但放在子程序中较好。例如:

  用于中断服务的子程序则一定要把保护指令安排在子程序中,这是因为中断是随机出现的,因此无法在主程序中安排保护指令。

  3.子程序调用时参数的传递方法

  调用程序在调用子程序时需要传送一些参数给子程序,这些参数是子程序运算中所需要的原始数据。子程序运行后要将处理结果返回调用程序。原始数据和处理结果的传递可以是数据,也可以是地址,统称为参数传递。

  参数传递必须事先约定,子程序根据约定从寄存器或存储单元取原始数据(称入口参数);进行处理后将处理结果(称出口参数)送到约定的寄存器或存储单元,返回到调用程序。参数传递一般有下面三种方法。

  (1)用寄存器传递:适用于参数传递较少、传递速度快的情况。

  (2)用堆栈传送:适用于参数传递较多、存在嵌套或递归的情况。

  (3)用存储单元传送:适用于参数传递较多时,但传递速度较慢。

推荐新闻