汇编中的子程序设计(8086/8088)

385 阅读4分钟

(一)、子程序框架

PROC_NAME PROC [NEAR/FAR]  //如果不加以指定类型,汇编程序默认解释为NEAR类型
....
RET                        //最后一条被执行的必然是RET指令,RET具体格式由子程序的类型确定
...
PROC_NAME ENDP

(二)、传参方式:

1.种类:
寄存器传递方式
堆栈传递方式
数据去传递方式
高级语言程序多使用堆栈传递方式与数据区传递方式。
2.传参时程序员在主函数与子函数之间需要约定的:
参数类型
参数传递方式
参数顺序

(三)、子程序进行主程序的现场保护:

CPU现场(执行现场):当主程序调用子程序时,有关寄存器、标志位当时的状态。
习惯用 PUSH指令保护现场,用POP指令恢复现场。

二、设计示例

题目:试设计一程序,完成两个长补码的加法,其中两个长补码的长度是相同的,并且采用低地址存放低位,
高地址存放高位的方式存储。对于加法功能,使用子程序实现,两个长补码的起始地址、长补码的长度(以字为单位)、
运算结果的起始地址均有由主程序以入口参数的形式传给子程序;运算是否溢出使用一个字节标志来表示,
00H表示运算无溢出,0FFH表示运算溢出,子程序将此溢出标志以出口参数的形式传递给主程序。

(一)寄存器传递方式
约定:(具体约定寄存器与参数间的对应关系)本例中约定,SI、DI寄存器传递两个长补码的起始偏移量(认为两个
长补码位于同一数据段,且段基值保存到DS中),CX寄存器传递补码长度,BX寄存器传递运算结果的起始偏移量
(认为段基值已保存在DS中),约定使用DL寄存器传递溢出标志。
DATA SEGMENT
VAR1 DW 5482H,669EH,02C7H,14B2H,0C254H
VAR2 DW 8C2BH,0C24CH,0AB12H,357AH,41A5H
LEN EQU $-VAR2
SUM DW LEN DUP(0)   ;用于保存运算结果
OVR DB ?            ;用于保存溢出标志
DATA ENDS
STACK1 SEGMENT STACK  ;子程序设计必须使用堆栈
        DW 40H DUP(0)
STACK1 ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK1
BEGIN:MOV AX,DATA
      MOV DS,AX
      MOV SI,VAR1    ;传递入口参数
      MOV DI,VAR2
      MOV CX,LEN
      MOV BX,SUM
      CALL LONGADD
      MOV OVR,DL     ;保存出口参数(这行我出错)
      MOV AH,4CH
      INT 21H
LONGADD PROC
      PUSH AX
      PUSHF
      CLC
L1:   MOV AX,[SI]
      ADC AX,[DI]
      MOV [BX],AX
      PUSHF
      ADD SI,2
      ADD DI,2
      ADD BX,2
      POPF
      LOOP L1
      JO L2
      MOV DL,0
      JMP L3
L2:   MOV DL,0FFH
L3:   POPF
      POP AX
      RNT
LONGADD ENDP
CODE ENDS
END BEGIN
(二)堆栈传递方式
约定:(只需要约定入口参数的入栈顺序与出口参数的出栈顺序)约定主程序按照被加数起始偏移量、
加数起始偏移量、被加数与加数的长度、运算结果起始偏移量的顺序将入口参数入栈。
约定子程序的出口参数覆盖最先入栈的入口参数(因为只有一个出口参数)
DATA SEGMENT
VAR1 DW 5482H,669EH,02C7H,14B2H,0C254H
VAR2 DW 8C2BH,0C24CH,0AB12H,357AH,41A5H
LEN EQU $-VAR2
SUM DW LEN DUP(0)   ;用于保存运算结果
OVR DB ?            ;用于保存溢出标志
DATA ENDS
STACK1 SEGMENT STACK  ;子程序设计必须使用堆栈
        DW 40H DUP(0)
STACK1 ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK1
BEGIN:MOV AX,DATA
      MOV DS,AX
      LEA SI,VAR1
      PUSH SI         ;-2
      LEA SI,VAR2
      PUSH SI         ;-2
      LEA SI,LEN  
      PUSH SI         ;-2
      LEA SI,SUM
      PUSH SI         ;-2
      CALL LONGADD
      POP DX
      MOV OVR,DL
      MOV AH,4CH
      INT 21H
LONGADD PROC
      PUSH BP         ;-2  
      MOV BP,SP
      PUSHF
      PUSH AX
      PUSH BX
      PUSH CX
      PUSH SI
      PUSH DI
      MOV BX,[BP+4]   ;加4的原因请看下面图解
      MOV CX,[BP+6]
      MOV DI,[BP+8]
      MOV SI,[BP+10]
      CLC
L1:   MOV AX,[SI]
      ADC AX,[DI]
      MOV [BX],AX
      PUSHF
      ADD SI,2
      ADD DI,2
      ADD BX,2
      POPF
      LOOP L1
      JO L2
      MOV [BP+10],0
      JMP L3
L2:   MOV [BP+10],0FFH
L3:   POP DI
      POP SI
      POP CX
      POP BX
      POP AX
      PUSHF
      POP BP
      RET 6    ;返回参数覆盖了最高地址的入口参数,使用堆栈传参时务必使用RET N 清楚堆栈内的参数
 LONGADD ENDP
 CODE ENDS
 END BEGIN
图解+4原因:
(三)数据区传递方式
约定:(需指明各参数在数据区的顺序、占据的空间)约定按照变量定义的顺序,子程序也按照这个顺序获得入口参数。
各参数均占一个字的空间。
DATA SEGMENT
VAR1 DW 5482H,669EH,02C7H,14B2H,0C254H
VAR2 DW 8C2BH,0C24CH,0AB12H,357AH,41A5H
LEN EQU $-VAR2
SUM DW LEN DUP(0)   ;用于保存运算结果
OVR DB ?            ;用于保存溢出标志
IPAR DW 4 DUP(0)    ;入口参数数据区
OPRA DW 1           ;出口参数数据区
DATA ENDS
STACK1 SEGMENT STACK  ;子程序设计必须使用堆栈
        DW 40H DUP(0)
STACK1 ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK1
BEGIN:MOV AX,DATA
      MOV DS,AX
      LEA SI,IPAR
      LEA DI,OPRA
      MOV WORD PTR [SI],OFFSET VAR1
      MOV WORD PTR 02H[SI],OFFSET VAR2
      MOV WORD PTR 04H[SI],OFFSET LEN
      MOV WORD PTR 06H[SI],OFFSET SUM
      CALL LONGADD
      MOV DL,BYTE PTR [DI]
      MOV OVR,DL
      MOV AH,4CH
      INT 21H
LONGADD PROC
      PUSHF
      PUSH AX
      PUSH BX
      PUSH CX
      PUSH DX
      PUSH SI
      PUSH DI
      MOV DI,02H[SI]
      MOV CX,04H[SI]
      MOV BX,06H[SI]
      MOV SI,[SI]
      CLC
L1:   MOV AX,[SI]
      ADC AX,[DI]
      PUSHF
      MOV [BX],AX
      ADD SI,2
      ADD DI,2
      ADD BX,2
      POPF
      LOOP L1
      JO L2
      MOV DL,0
      JMP L3
L2:   MOV DL,0FFH
L3:   POP DI
      MOV [DI],DX
      POP SI
      POP DX
      POP CX
      POP BX
      POP AX
      POPF
      RET
LONGADD ENDP
CODE ENDS
END BEGIN