子程序设计和系统功能调用例题

更新时间:2023-10-06 21:44:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

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

1)设计参数传递约定

题目已指明参数传递为寄存器传递方式,这里只需要具体约定寄存器与参数间的对应关系。在本例中,我们约定主程序通过SI、DI寄存器传递两个长补码的起始偏移量(认为两个长补码位于同一数据段,并且段基值保存到DS中),通过CX寄存器传递补码的长度,通过BX寄存器传递运算结果的起始偏移量(认为段基值已保存在DS中);并且,我们约定子程序通过DL寄存器传递溢出标志。

2)源程序设计

参数传递约定设计完成后,我们开始源程序设计,主程序与子程序的相应代码如下所示。 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

LEA DI, VAR2 MOV CX, LEN LEA BX, SUM CALL LONGADD MOV OVR, DL

MOV AH, 4CH INT 21H LONGADD PROC PUSHF

PUSH AX 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 AX

POPF RET

; 传递入口参数

; 调用子程序

; 保存出口参数

; FR、AX入栈,保护CPU现场 ; 清除CF标志,保证第一次执行ADC时等同于ADD

; 完成当前字的加法,引入了上次加法的进位 ; 保护OF标志

; 当前字的计算结果保存到指定位置 ; 修改SI、DI、BX,使它们指向下一个字

; 恢复OF标志

; 计数循环,完成所有字单元的加法后退出循环 ; 判断最后一次运算是否溢出

; 无溢出则将0送至DL保存,传递出口参数

; 有溢出则将0FFH送至DL保存,传递出口参数 ; 恢复CPU现场

; 返回主程序

LONGADD ENDP CODE ENDS END BEGIN

读者在上例中应注意,首先,主程序向子程序传递入口参数、取得出口参数都是按照约定来进行的;其次,读者应注意子程序中的现场保护与恢复,它们分别在子程序的首位部分用PUSH和POP指令来实现;第三,由于上例中采用寄存器来传递参数,当执行子程序时,各参数已在寄存器中就位,使我们在子程序中没有找到“取入口参数”的动作,但实际上入口参数在子程序中已经可以直接使用。

例8.2.2 试设计一程序,完成例8.2.1中指定的功能,但本例中参数传递方式采用堆栈传递方式。

1)设计参数传递约定

题目中已指定参数传递方式为堆栈传递方式,这里只需约定入口参数入栈的顺序与出口参数的出栈顺序。我们约定主程序按照被加数起始偏移量、加数起始偏移量、被加数与加数的长度、运算结果起始偏移量的顺序将入口参数入栈,子程序则按照相应顺序来获取入口参数;并且,我们约定子程序的出口参数覆盖最先入栈的入口参数,因为只有一个出口参数,返回主程序后,主程序只需将出口参数出栈即可。

2)源程序设计

参数传递约定设计完成后,我们开始源程序设计,主程序与子程序的相应代码如下所示。

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 LEA SI, VAR2 PUSH SI MOV SI, LEN PUSH SI LEA SI, SUM PUSH SI

CALL LONGADD POP DX

MOV OVR, DL

MOV AH, 4CH INT 21H LONGADD PROC PUSH BP

MOV BP, SP PUSHF

PUSH AX PUSH BX PUSH CX PUSH SI PUSH DI

; 通过堆栈传递入口参数

; 调用子程序 ; 出口参数出栈

; 保存出口参数

; BP作为现场加以保护 ; 获取当前栈顶位置 ; 保护CPU现场

MOV BX, [BP+4] MOV CX, [BP+6] MOV DI, [BP+8] MOV SI, [BP+10] CLC

; 取得保存运算结果的起始偏移量 ; 取得被加数、加数得长度 ; 取得加数的起始偏移量 ; 取得被加数的起始偏移量

; 清除CF标志,保证第一次执行ADC时等同于ADD

L1: MOV AX, [SI] ADC AX, [DI] PUSHF

; 完成当前字的加法,引入了上次加法的进位 ; 保护OF标志

; 当前字的计算结果保存到指定位置 ; 修改SI、DI、BX,使它们指向下一个字

MOV [BX], AX ADD SI, 2 ADD DI, 2 ADD BX, 2 POPF

; 恢复OF标志

; 计数循环,完成所有字单元的加法后退出循环 ; 判断最后一次运算是否溢出

; 无溢出则将0送至堆栈保存,传递出口参数

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

POPF POP BP RET 6

; 有溢出则将0FFH送至堆栈保存,传递出口参数 ; 恢复CPU现场

; 返回主程序,仅清除3个入口参数,因最先入栈的入口参数已被出口参数覆盖

LONGADD ENDP CODE ENDS END BEGIN

本文来源:https://www.bwwdw.com/article/dw7d.html

Top