2.6.5 子程序设计
子程序在汇编语言中常称为过程,子程序结构是模块化程序设计的重要基础。在模块化程序设计中,通常要把一个较大程序分解为多个具有独立功能的程序模块,这些独立模块称为子程序或过程。在编程和调试阶段,一般以模块为单位进行设计和调试,最后组装联调构成完整程序。模块化程序设计有利于分解复杂问题,也便于大型程序调试和软件开发中的分工与协作。
子程序的调用和返回是通过指令实现的,本节先介绍子程序调用与返回指令。
1.调用与返回指令
(1)调用指令CALL
CALL指令用于实现调用子程序的功能,可分为以下4种调用方式:
① 段内直接调用
指令格式:CALL dst
执行操作:(SP) ← (SP)−2,((SP)+1,(SP)) ← (IP)(返回地址),(IP) ← (IP)+D(入口地址)
② 段内间接调用
指令格式:CALL dst
执行操作:(SP) ← (SP)−2,((SP)+1,(SP)) ← (IP),(IP) ← (OA)
③ 段间直接调用
指令格式:CALL dst
执行操作:(SP) ← (SP)−2,((SP)+1,(SP)) ← (CS),(SP)←(SP)−2
((SP)+1,(SP)) ← (IP),(IP) ← dst
④ 段间间接调用
指令格式:CALL dst
执行操作:(SP) ← (SP)−2,((SP)+1,(SP)) ← (CS),(SP) ← (SP)−2
(SP)+1,(SP)) ← (IP),(IP) ← (OA),(CS) ← (OA+2)
(2)返回指令 RET
子程序或过程执行的最后一条指令必须是RET指令,RET指令将使程序的执行控制从子程序返回到调用指令CALL后的指令处(即断点)继续执行。
2.子程序的编写方法
需要多次执行并具有独立功能的一段程序,可以编写成子程序。
(1)编写子程序的要求
① 保护寄存器与工作单元
如果子程序要用到某些寄存器或存储单元,而它们的内容在子程序返回后还需使用,为了不破坏原有信息,应将它们的内容压入堆栈保护,或者存入一些空闲存储器单元或寄存器,返回之前再恢复这些信息。
② 正确使用堆栈
调用程序转入子程序之前,在堆栈顶部保存了断点地址,当子程序执行RET指令时,则将从栈顶弹出断点地址,以便返回到调用程序。
③ 说明文档
在子程序中应有内部文档使子程序可读性好,可理解性好,便于使用。子程序中应给出必要说明和适当的语句注释,这些说明和注释称为内部文档。
④ 参数传递
通过调用程序传递给子程序的参数,可以使程序的每次调用完成不同要求的具体操作,增加子程序的灵活性。
参数传递方法一般分为三种:
· 用寄存器传递:将参数送入约定的寄存器中。这种方法受到CPU寄存器个数的限制,一般用于参数较少的情况。
· 用参数表传递:调用程序将参数组成一个参数表,存放在内存或外设端口中,然后用寄存器将表址传送给子程序。这种方法适用于大量参数的传送。
· 用堆栈传递:调用程序将参数压入堆栈,子程序从堆栈中取得参数。这种方法适用于参数多、子程序嵌套调用和递归调用的情况。编写子程序时,应注意选用适当的方法进行参数传递。
(2)调用程序与子程序之间的参数传递示例
例2-50 将用压缩的BCD码表示的十进制数转换为二进制数。
设BCD码为4位(d−3d−2d−1d−0),按下面的公式将十进制数转换为二进制数BIN:
BIN =((((0×10)+d−3)×10+d−2)×10+d−1)×10+d−0
上例中用dx寄存器传送入口参数(BCD码十进制数),用bx返回转换为二进制数。子程序中还使用了ax和cx寄存器,为了适应其他程序调用,dtob子程序保护了ax和cx寄存器原内容。dx用于传送入口参数,不必保护,bx用于返回参数,则不能保护,否则执行恢复操作时,pop bx指令将破坏出口参数。
在数据转换过程中,由于寄存器dx、cx既要参与乘法运算,同时dx还要继续保存入口参数,cx还要保存循环移位计数和循环次数,因此程序采用了将dx、cx入栈临时保护的方法,使dx、cx寄存器的原值在操作过程中得到保留。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。