大连理工汇编语言程序设计子程序结构(第3-4节)
发布时间:2024-02-16 15:02:18浏览次数:36汇编语言程序设计辅导资料十二主 题: 第六章 子程序结构(第 3-4 节)内 容:第六章第 3-4 节 概述 这周我们学习继续第六章,课件后两节:多模块间参数传递,实例讲解,学习子程序递归调用。第 3 节 多模块间参数传递上小节中已经介绍过多模块间参数的传递,利用外部符号和相关的伪操作就可以实现参数传递,下面再具体说明一下。1)局部符号:本模块(源程序)中定义,在本模块中使用的符号2)外部符号:某一模块中定义,在另一模块中引用的符号3)外部符号相关的两个伪操作: PUBLIC 符号 EXTRN 符号经过 PUBLIC 伪操作定义的符号说明此符号可以供其他模块引用,而 EXTRN 定义的符号说明在其他模块中定义而要在本模块中使用的情况,这两个伪操作必须匹配成对才能完成参数传递,下面是两个具体的源文件: ;******************* ;*******************;SOURCE MODULE1 ; SOURCE MODULE2EXTRN PROADD :FAR PUBLIC PROADD ;******************** ;******************…. …. …. …. CODE1 SEGMENT CODE2 SEGMENT START: PROADD PROC FAR … …. CALL FAR PTR PROADD RET …. PROADD ENDP CODE1 ENDS CODE2 ENDS END START END 可以看出代码段 1 中定义了一个 EXTRN 符号 :PROADD,而代码段 2 中定义了一个 PUBLIC 符号:
PROADD。这样,代码段 2 中的符号 PROADD 就可以供代码段 1 引用,PUBLIC 与 EXTRN 伪操作必须配对使用,这样代码段 1 中引用外部符号 PROADD 的时候就需要加入伪操作 EXTRN。 4)多模块间参数传递方法:可以使用上面已经说过两种伪操作及上周学习的参数传递方法来解决问题 (1)当主程序和子程序不在同一模块中时变量传递方法之一:使用公共数据段;************************** SOURCE MMODULE1 EXTRN PROADD :FAR;**************************** ………..;**************************** END START;******************************; SOURCE MODULE2 PUBLIC PROADD;****************************** DATA SEGMENT COMMON ………….. DATA ENDS;***************************** CODE2 SEGMENT PROADD PROC FAR …………… PROADD ENDP;****************************** END 本例子中,源程序 2 中数据段用 COMMON 合并为一个覆盖段,作为公共的数据段使用,需要引用参数的时候只引用本模块中的变量即可。整个程序的外部符号只有 PROADD,配合两个伪操作就可以完成不同模块间的参数传递了。 注意子程序调用于定义都应该是 FAR 类型,因为主调程序与子程序不在同一个源程序文件中了。 (2)当主程序和子程序不在同一模块中时变量传递方法之二:动态修改外部符号(变量)的段地址内容。 参见如下由 3 个源程序模块组成的程序:模块 1 的局部变量在数据段中,外部变量在附加段中,动态修改附加段值就可以正确访问各外部变量。这有些类似于汇编程序设计中的各段寄存器的指定
过程。 ;SOURCE MODULE 1 模块 1 ;************************************** EXTRN VAR1; WORD,OUTPUT;FAR ;EXTRN 类型的变量 VAR1 和 OUTPUTEXTRN VAR2;WORD ;EXTRN VAR2 PUBLIC EXIT ;PUBLIC 类型的变量 EXIT;**********************************LOCAL_DATA SEGMENT ;数据段 VAR DW .5 ;定义变量内部变量 VAR . .LOCAL_DATA ENDS;*************************************CODE SEGMENT ;代码段 ASSUME CS:CODE,DS:LOCAL_DATA;**************************************** MAIN PROC FAR START: MOV AX.LOCAL_DATA ;数据段地址载入 DS 寄存器 MOV DS,AX . . MOV BX,VAR MOV AX,SEG VAR1 ;VAR1 段偏移置于附加段 MOV ES,AX 从模块 2 引入 VAR1 变量 ADD BX,ES:VAR1 . . MOV AX,SEG VAR2 ;VAR2 段偏移置于附加段 MOV ES,AX 从模块 3 引入 VAR2 变量 SUB ES:VAR2,50 . . JUMP OUTPUT ;从模块 3 引入 OUTPUT 变量 . .
EXIT …… …….MAIN ENDP;************************************** CODE ENDS ;代码段结束;*************************************** END START SOURCE MODULE2 ;模块 2;**************************************** PUBLIC VAR1 ;外部变量 VAR1;**************************************** EXTDATA1 SEGMENT ;数据段 VAR1 DW 10 ;从模块 2 引入 VAR1 变量 ……. EXDATA1 ENDS;***************************************** …………;****************************************** END SOURCE MODULE3 ;模块 3;*******************************************PUBLIC VAR2 ;外部变量 VAR2EXTRN EXIT:FAR 及 EXIT;*******************************************EXTDATA2 SEGMENT ;数据段 VAR2 DW 3 ;内部变量 VAR2 ……….EXTDATA2 ENDS;*******************************************PUBLIC OUTPUT ;外部变量 OUTPUTPROGRAM SEGMENT ;代码段 ASSUME CS:PROGRAM,DS:EXTDATA2 ………..OUTPUT: JMP EXIT ………PROGRAME ENDS
;************************************* END在利用外部变量及两种伪操作的基础上,从模块 2 和模块 3 对附加段的操作中可以看出动态的修改段地址可以达到传递模块间参数的目的,还可以进一步优化上例的程序,避免动态修改段地址产生的错误。 (3)当主程序和子程序不在同一模块中时变量传递方法之三:将不同模块的变量指向同一个附加段 具体实例程序不在列举,可以在课件和参考书中找到,这种方法与方法一类似,其实也是建立了一个公共数据段,让不同模块的变量可以在外部符号伪操作及段前缀伪操作的帮助下,达到参数传递的目的。第 4 节 子程序的递归调用字符串反序输出实例: 主程序: ;************************************STR DB ‘HAPPY!’,’$’ MOV BX,OFFSET STR PUSH BX CALL REVERS ;调用子程序 POP BX MOV DL,[BX] MOV AH,2 INT 21H 子程序: ;***************************************REVERS PROC NEAR ;寄存器保存 PUSH AX PUSH BX PUSH DX PUSH BP ;原始 BP 入栈 MOV BP,SP ;新 BP 值为栈指针 MOV BX,[BP+10] ;栈顶 BP 移动到栈底,BX 获取字符串首地址
MOV AL,[BX] ;AL 获得串首地址内容 CMP AL,’$’ ;是否是字符‘$’ JNE RE_CALL ;否,则转入符号地址 RE_CALL JMP RETURN ;相等,跳转到 RETURN RE_CALL: INC BX ;BX 自增 1,以备字符串下一字符的操作 PUSH BX ;BX 入栈 CALL REVERS ;重复调用子程序 REVERS POP BX ;恢复 BX 内容 MOV DL,[BX] ;DOS 功能调用 MOV AH,2 INT 21H RETURN: POP BP ;恢复寄存器 POP DX POP BX POP AX RET REVERS ENDP 具体程序可以参见课件。本实例程序通过反复调用子程序可以达到反序输出字符串的目的,而这种反复调用同一程序的过程称为递归调用。上节中已经说明,递归调用可以解决一类很典型的问题,对于某些需要反复执行相似操作的问题很容易通过递归调用的方法得到解决。本周要求掌握的内容如下:基本概念:多模块参数传递、内部变量与外部变量、外部变量调用的伪操作匹配、递归调用、参数传递的几种方式基本理论:了解模块间参数传递的意义,理解外部符号伪操作在参数传递中的作用,理解几种模块间参数传递的方法,理解子程序递归调用的作用习题:1、为了实现两个模块间的参数传递需要的操作包括:
(A)外部符号伪操作 (B)SEGMENT 伪操作 C)模块内参数传递方法 ABC2、下列关于变量描述正确的是: (A)局部变量是在子程序内部使用的变量 (B)外部变量是在子程序外部使用的变量(C)局部变量只能在本模块内部使用 (D)外部变量可以在其他模块中使用 ACD