《电子技术应用》
您所在的位置:首页 > 嵌入式技术 > 解决方案 > 汇编基础:子程序设计

汇编基础:子程序设计

2017-06-10
关键词: 汇编

在一个程序中的不同地方,常常需要多次非循环的使用完成特定功能的程序段,这些程序段除了某些变量的赋值不同外,具有相同的指令序列,这时,我们为了减少重复编写程序,缩短目标代码,节省内存空间,把视线这一功能的指令序列组成一个相对独立的程序段。这也就是我们这片文章中所要讨论的子程序。

子程序相当于高级语言(比如C语言)中的过程和函数,在汇编语言中子程序也称为过程。使用子程序的好处:

a、有利于程序模块化、结构化和自顶向下的程序设计方法,简化了程序设计过程。

b、增加了源程序的可读性,便于调试维护

c、减少了目标代码锁占用的空间

d、子程序一旦编制成功,在开发研制各种软件时都可使用,缩短了软件的开发周期。

一、子程序的调用与返回

1、子程序的定义

子程序必须定义在一个逻辑段内,子程序的定义由过程定义伪指令PROC/ENDP来实现,它们分别用在程序的子程序的前后,一般格式如下:

PROC_NAME   PROC    [NEAR/FAR]    
......    
PROC_NAME   ENDP

其中PROC_NAME为子程序名,也极为CALL的操作数,自程序具有3个属性:段属性、偏移量属性和类型属性,段属性表示该子程序所在段的段基值。偏移量属性表示该子程序在段中的偏移量。类型属性也称为距离属性,可以是NEAR或FAR,属性为NEAR的子程序只能在本段内调用,属性为FAR的子程序则可以在本段以内以及其他段中调用。

2、调用指令

当主程序属性是NEAR的子程序时,CPU把当前指令指针IP的内容压入堆栈,作为返回地址保存起来,然后将子程序的偏移量送入IP,当从子程序返回时,将从堆栈弹出2个字节的返回地址送入IP,当调用属性是FAR的过程时,CPU把当前的段寄存器CS与指令指针IP的内容都压入堆栈,作为返回地址保存起来,然后将子程序的段基值与偏移量送入CS与IP,当子程序返回时,将从堆栈弹出4个字节的返回地址分别送入IP与CS。

我们容易知道,当主程序和子程序处于同一逻辑段时,可以把类型属性定义为NEAR,也可以把类型属性定义为FAR,然后进行调用。而当主程序与子程序不在同一逻辑段是,只可把过程的类型定义为FAR,然后调用。

二、返回指令

返回指令RET是子程序逻辑上的最后一条指令,也就是最后一条被执行的指令,它使子程序在完成功能后返回到调用它的CALL指令的后续指令处,即返回地址处继续执行。

三、子程序设计的基本要求

1、子程序必须有一定的通用性

2、注意寄存器的保存和恢复

3、正确使用堆栈

4、选用适当的方法在主程序与子程序间进行参数传递

5、编制子程序说明信息文件

四、子程序与主程序间的参数传递

在汇编语言中最常用的参数传递方式有3种,分别是:用寄存器传递参数、用堆栈传递参数和用地址表达式传递参数。

1、用寄存器传递参数

这种方式是通过通用寄存器来传递的参数,即在主程序调用子程序前,将入口参数送到约定的通用寄存器中,子程序可以直接从这些寄存器中取出参数进行加工处理,并将结果放在约定的通用寄存器中,返回主程序,主程序再从约定的寄存器中取出结果,我们一例子来说明问题:

例:将两个给定的二进制数(8位和16位)转换为ASCII码字符串。

分析:主程序提供呗转换的数据和转化后的ASCII码字符串的存储区的首地址。子程序完成二进制的转换。为了提高子程序的代码转换通用性,它可以完成8位或16位数的转换。设调用子程序时,入口参数为:被转换的数在DX中,若位数小于16,则从高到低存放,转换后的ASCII码的存放首地址在DI中。下面给出一种实现方法:

DATA    SEGMENT    
   BIN1    DB  35H    
   BIN2    DW  0AB48H    
   ASCBUF  DB  20H DUP  (?)    
DATA    ENDS    
STACK1  SEGMENT PARA    STACK    
   DW  20H DUP  (0)    
STACK1  ENDS    
CODE    SEGMENT    
ASSUME  CS:CODE, DS:DATA, SS:STACK1    
BEGIN:  MOV AX, DATA    
   MOV DS, AX    
   XOR DX, DX    
   LEA DI, ASCBUF      ;存放ASCII码的单元首地址送DI    
   MOV DH, BIN1            ;待转换的第一个数据送DH    
   MOV AX, 8           ;待转换的二进制数的位数送AX    
   CALL    BINASC      
   MOV DX, BIN2    
   MOV AX, 16    
   LEA DI, ASCBUF    
   ADD DI, 8           ;设置下一个数的存放首地址    
   CALL    BINASC    
   MOV AH, 4CH    
   INT     21H    
BINASC  PROC    
   MOV CX, AX    
LOP:    ROL DX, 1           ;最高位移入最低位    
   MOV AL, DL    
   AND AL, 1           ;保留最低位,屏蔽其他位    
   ADD AL, 30H    
   MOV [DI], AL            ;存结果    
   INC DI          ;修改地址指针    
   LOOP    LOP    
   RET    
BINASC  ENDP    
CODE    ENDS    
   END BEGIN


2、用堆栈传递参数

这种方法是主程序先将入口参数压入堆栈,子程序从堆栈中把参数读出,进行加工处理。这里要注意从堆栈中读取数据与从堆栈中弹出数据是有区别的,从堆栈中读取数据并不改变堆栈的栈顶指针SP,而从堆栈中弹出的数据,则需修改SP,在使用堆栈传递参数时,要保证堆栈状态的正确。

我们还以上面的例子来说明下问题,这次采用堆栈传递参数

分析:如果使用堆栈,一般用包括:

a、在主程序中,将待转换的数据、存放ASCII码的首地址和转换的位数压入栈中

b、在子程序中保存信息

下面我们依然用程序说明问题,在程序的必要处我已经做了注释

DATA    SEGMENT    
   BIN1    DB  35H    
   BIN2    DW  0AB48H    
   ASCBUF  DB  20H DUP  (?)    
DATA    ENDS    
STACK1  SEGMENT PARA    STACK    
   DW  20H DUP  (0)    
STACK1  ENDS    
CODE    SEGMENT    
ASSUME  CS:CODE, DS:DATA, SS:STACK1    
BEGIN:  MOV AX, DATA    
   MOV DS, AX    
   MOV AH, BIN1    
   PUSH    AX              ;待转换数据压栈    
   MOV AX, 8    
   PUSH    AX              ;待转换位数压栈    
   LEA DI, ASCBUF    
   PUSH    DI          ;存放ASCII码的首地址压栈    
   CALL    BINASC              ;调用转换子程序    
   MOV AX, BIN2    
   PUSH    AX    
   MOV AX, 10H    
   PUSH    AX    
   ADD DI, 8    
   PUSH    DI    
   CALL    BINASC    
   MOV AH, 4CH    
   INT     21H    
BINASC  PROC    
   PUSH    AX    
   PUSH    CX    
   PUSH    DX    
   PUSH    DI      
   MOV BP, SP    
   MOV DI, [BP+10]         ;从堆栈取出入口参数    
   MOV CX, [BP+12]    
   MOV DX, [BP+14]    
LOP:    ROL DX, 1    
   MOV AL, DL    
   AND AL, 1    
   ADD AL, 30H    
   MOV [DI], AL    
   INC DI    
   LOOP    LOP    
   POP DI    
   POP DX    
   POP CX      
   POP AX    
   RET 6           ;返回并从堆栈中弹出6个字节    
BINASC  ENDP    
CODE    ENDS    
   END BEGIN

3、用地址表传递参数

当要传送的参数较多时,可在主程序中建立一个地址表,在调用子程序前,把所有参数的地址依次存放在该地址表中,然后把地址表的首地址通过寄存器传送到子程序中去,而在子程序中,按照地址表中给出的地址逐个取出参数,用地址表传递参数的方法,在入口参数比较多时很方便,当返回参数较多时,可用同样的方法传递参数,供主程序使用。


本站内容除特别声明的原创文章之外,转载内容只为传递更多信息,并不代表本网站赞同其观点。转载的所有的文章、图片、音/视频文件等资料的版权归版权所有权人所有。本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如涉及作品内容、版权和其它问题,请及时通过电子邮件或电话通知我们,以便迅速采取适当措施,避免给双方造成不必要的经济损失。联系电话:010-82306118;邮箱:aet@chinaaet.com。