[计算机硬件及网络]微机原理与接口技术汇编语言程序设计.ppt_第1页
[计算机硬件及网络]微机原理与接口技术汇编语言程序设计.ppt_第2页
[计算机硬件及网络]微机原理与接口技术汇编语言程序设计.ppt_第3页
[计算机硬件及网络]微机原理与接口技术汇编语言程序设计.ppt_第4页
[计算机硬件及网络]微机原理与接口技术汇编语言程序设计.ppt_第5页
已阅读5页,还剩60页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第4章 汇编语言程序设计,本章重点,掌握汇编语言程序的规范格式 掌握汇编语言程序设计的基本方法 顺序程序设计 循环程序设计 选择程序设计 子程序设计 了解汇编语言与高级语言的接口,汇编语言的特点 8086系统常用的汇编语言称为ASM86,汇编语言的有如下的特点: 1)汇编语言可以让我们从根本上了解计算机的工作原理,清晰的跟踪计算机的工作过程。 2)计算机系统中,某些功能程序仍然用汇编语言来实现,比如机器自检、输入输出驱动程序。 3)汇编语言书写的程序目标代码占用的内存空间少、执行速度快、效率高、实时性强。 4)汇编语言可以直接调用系统中断,方便用户使用资源。,4.1 汇编语言设计概述,汇编语言的编译过程 1)用文本编辑器编写符合汇编格式的程序,并将文件的扩展名命名为.ASM,该文件称为汇编源程序。 2)利用汇编程序(MASM.EXE)将汇编源程序翻译成计算机可以识别和运行的扩展名为.OBJ二进制目标程序。 3)利用链接程序(LINK.EXE)将目标文件进行地址重定位、目标程序组合等过程,产生用户可以执行的扩展名为.EXE的可运行程序。,汇编语言语句类型 指令性语句 一条指令性语句就是一条8086的指令,例如 ADD AL,BL和 MOV CX,1000;每一条指令性语句都会在汇编过程中产生相应的目标代码。 指示性语句 指示性语句又称为伪指令,例如 SEGMENT和ABC DB 50H。伪指令用来为汇编程序提供某些信息,让汇编程序在汇编的过程中执行特定功能的信息,比如规定一个数据段从哪里开始到哪里结束等。每一条伪指令在汇编的过程中都不会产生相应的目标代码。,指令性语句的格式如下: 指令助记符 目标操作数 START: MOV AX,1090H ;将16进制数1090H送入AX INC BX,指示性语句的格式如下: 伪指令助记符 CR DB ODH ;在字节单元CR处存放数据0DH ORG 200H ;目标程序的偏移量 DATA SEGMENT ;数据段开始,指令性语句和指示性语句的最大区别就是指示性语句在标识符和伪指令助记符没有冒号,汇编语句语句格式,段定义伪指令SEGMENT、ENDS、ASSUME 伪指令SEGMENT和ENDS总是成对出现。SEGMENT用来定义段开始,ENDS是来定义段结束。这一段伪指令可以将源程序分为几个段,通常为数据段,堆栈段和代码段。 格式为: 段名 SEGMENT 段内容 段名 ENDS 伪指令ASSUME告诉汇编程序,哪一个段是数据段,哪一个段是堆栈段,哪一个段是代码段。 格式为: ASSUME 段寄存器:段名 源程序结束伪指令 END,4.2 汇编语言程序结构,一个标准汇编语言源程序结构如下:,数据段名 SEGMENT 数据段内容 数据段名 ENDS 堆栈段名 SEGMENT 堆栈段内容 堆栈段名 ENDS 代码段名 SEGMENT ASSUME CS:代码段名, DS:数据段名, SS:堆栈段名 代码段内容 代码段名 ENDS END,注意:各个段的名称可以任意起,一般把数据段的段名记做DATA,堆栈段的段名记做STACK,代码段的段名记做CODE。,规范程序示例:,CODE SEGMENT ;定义段 ASSUME CS:CODE ;把上面定义段的段基址放入 CS MOV CX,100H ;装入循环次数 MOV DL,0 ;装入第一个ASCII码 NEXT: MOV AH,02 INT 21H INC DL ;每次将数据寄存器DL内的数值加1 LOOP NEXT ;执行一次,CX减1,直到CX为0. MOV AH,4CH ;终止当前程序并返回调用程序 INT 21H ;返回DOS CODE ENDS ;段结束 END ;汇编程序结束,编译工具MASM的使用,MASM是专门为汇编语言设计的一种集编译、链接为一体的工具,它是利用文本编辑器(EDIT等)将汇编指令按照规范格式建成一个独立且扩展名为.ASM的汇编程序,称源程序。编译程序MASM将输入的ASM文件,编译成.OBJ文件,称为目标程序。OBJ文件仅包含有关程序各部分要载入何处及如何与其他程序合并的信息,无法直接载入内存执行。链接程序LINK则可将OBJ文件转换成可载入内存执行的EXE文件。,利用MASM编译、链接汇编程序的步骤如下: (1) 用EDIT编辑一个扩张名为ASM的源程序文件。例如:smile.asm (2) DOS窗口的命令提示符下输入:MASM SMILE 不用打入附加名.ASM。 50162 + 403867 Bytes symbol space free 0 Warning Errors 警告错误,表示编译器对某些语句不理解,通常 是输入错误。 0 Severe Errors 严重错误,会造成程序无法执行,通常是语法结 构错误。 如果没有一个错误存在,即可生成OBJ文件。 (3) DOS窗口的命令提示符下输入: LINK SMILE 不用附加名OBJ LINK : warning L4021: no stack segment 由于COM文件不使用堆栈 段,所以错误信息并不 “no stack segment” 影响程序正常执行。,DEBUG和MASM的区别 DEBUG是调试器,它的主要用途在于除错,能够观察每条汇编语句运行后的结果,方便的修正汇编程序中的错误。DEBUG中必须使用16进制的数。 MASM是一种编译器,它能将汇编源程序进行编译、链接形成可执行文件,但汇编程序必须使用规范书写方式,源程序中除了指令性语句,还必须加入许多与指令语句无关的指示性语句,以供编译器识别。 MASM中的数据默认为10进制。 除了MASM外,还有TASM等工具软件也能对规范格式的汇编语言进行编译,段定义伪指令SEGMENT、ENDS、ASSUME和ORG (1) 伪指令SEGMENT和ENDS总是成对出现。SEGMENT用来定义段开始,ENDS是来定义段结束,段名是合法的标识符。伪指令SEGMENT的参数有定位类型,组合类型和类别。 格式为: 段名 SEGMENT 定位类型 组合类型 类别 段名 ENDS 定位类型:指定逻辑段在主存储器中的边界 BYTE 段基址为为任何地址,段间无空隙(xxxx xxxxB) WORD 段基址为下一个可用的偶数地址(xxxx xxx0B) PARA 段基址为下一个可用的节地址(xxxx 0000B) PAGE 段基址为下一个可用的页地址(0000 0000B) 默认的定位类型是PARA,组合类型:指定多个逻辑段之间的关系 NONE 本段与其他段没有逻辑关系,不与其他段合并,每段都有自己的段地址。 PUBLIC 连接程序把本段与所有同名同类型的其他段相邻地连接在一起,然后为所有这些段指定一个共同的段地址,也就是合成一个物理段。 STACK 仅用于堆栈段,连接程序将所有STACK段进行合并连接成一个物理段,系统初始化SS和SP。 COMMON 连接程序把本段与所有同名同类型的其他段指定相同的段基址,即共享存储空间。 MEMORY 连接程序把本段定位在所有同名同类型的其他段后面,即最高的地址空间。 默认的组合类型是NONE,(2) 伪指令ASSUME告诉汇编程序,哪一个段是数据段,哪一个段是堆栈段,哪一个段是代码段。 格式为: ASSUME 段寄存器:段名 除CS的值可以自动装入外,其他各段的实际值还要用MOV指令来赋值。 MOV AX,DATA MOV DS,AX ;将数据段DATA的段基址送DS MOV AX,STACK MOV SS,AX ;将堆栈段STACK的段基址送SS MOV SP,TOP ;堆栈指针指向栈顶,类别:类别必须用单引号括起来,连接程序所有程序中类别相同的段放在一个连续的存储空间里组合成一个物理段。,STACK SEGMENT PARA STACK STACK 段名 定位 组合类型 类别,DATA SEGMENT 数据段内容 DATA ENDS STACK SEGMENT 堆栈段内容 STACK ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA, SS:STACK START:MOV AX,DATA MOV DS,AX ;初始化DS MOV AX,STCAK MOV SS,AX ;初始化SS MOV SP,TOP ;初始化SP MOV AH,4CH INT 21H ;程序正常结束 CODE ENDS END START,过程定义伪指令PROC、ENDP 过程就是完成某个特定功能的子程序,应用伪指令PROC和ENDP定义过程的格式如下:,过程名 PROC NEAR|FAR 过程名 ENDP,(1)过程名:(子程序名)为符合语法的标识符 (2)属性:NEAR属性(段内近调用)的过程只能被相同代码段的其他程序调用、FAR属性(段间远调用)的过程可以被相同或不同代码段的程序调用;NEAR属性是默认值。 (3)调用过程:CALL 过程名 (4)过程返回:RET,程序结束伪指令END 格式是: END 标识符 标识符是可选项,它是程序起始地址的标识符。,CODE SEGMENT ;定义段 ASSUME CS:CODE ;把CODE段的段基址放入CS START:MOV DL,1 MOV AH,02 INT 21H MOV AH,4CH ;终止当前程序并返回调用程序 INT 21H ;返回DOS CODE ENDS ;段结束 END START,DATA SEGMENT ;数据段开始 ARRAY DB 3,12,45,21,97,56,8 ;存放7各数字 MAXNUM DB ? ;MAXNUM单元存放最大数 DATA ENDS ;数据段结束 CODE SEGMENT ;代码段开始 ASSUME CS:CODE,DS:DATA START:MOV AX,DATA MOV DS,AX ;数据段寄存器赋值 MOV BX,OFFSET ARRAY ;取数组的偏移量送BX MOV CX,6 ;比较的次数送CX MOV AL,BX ;取第一个数 LABLE:INC BX ;偏移量加1,指向下一个数 CMP AL,BX ;比较AL和第N+1个数 JNB NEXT ;不低于则转入NEXT MOV AL,BX ;否则将大数送AL NEXT:LOOP LABLE ;继续下一次比较,直到CX为0 MOV MAXNUM,AL ;最大数送MAXNUM单元 MOV DL,AL MOV AH,02 INT 21H ;显示输出最大数97 MOV AH,4CH INT 21H ;程序正常结束 CODE ENDS ;代码段结束 END START ;汇编程序结束,常量 常量就是指令中出现的固定值,比如 MOV AX,90。 1)数字常量 如果一个常数后面加字母B来表示二进制数。 如果一个常数后面加字母D(可不加)表示十进制数。 如果一个常数后面加字母H来表示十六进制数,一个16进制数以字母AF开头,前面必须加一个0,如0A59H 2)字符常量 单引号引出的字符表示字符常量,如c表示字符c。 单引号引出的多个字符序列称为字符串常量,如ABC 注意:一个用引号引出的字符串也代表常数,如带引号的字符串ABC,等效于它们对应的ASCII的常数64、65、66。,4.3 汇编语言的语法,变量 变量是存放数据的存储器单元的符号地址,在程序运行过程中其值可以变化。 伪指令DB,DW,DD用来定义变量 变量的属性 1)段基址(SEG):变量所在段的起始地址 2)偏移量(OFFSET):变量所在地址与段基址的相对距离 3)类型(TYPE):变量指示的存储区中每个数据所占的内存单元的字节数,可以是字节(1字节)、字(2字节)、双字(4字节) 注意: 1)变量定义后可以使用,在指令中必须与操作数类型一致 2)变量的偏移地址仅仅对应其所代表的数据区的首地址,如果这个数据区有多个数据项,对后面的数据项操作时必须改变地址值。,定义变量伪指令DB、DW、DD 该组伪指令用来给出程序中所用到的数据、字符串以及存储单元。DB用来定义字节、DW用来定义字、DD用来定义双字。 变量定义的格式为: 变量 伪指令 参数1、参数2 例如: CR DB 10H LF DB 0BH,64H RP DW FBFFH,3CH,1)操作数?用来保留存储空间,但不存入数据。 ABC DB 0BH,06H,?,?,? LPI DW ?,54H,?,ABC,LPI,2)操作数还可以用复制操作符DUP来缩写 BUFFER DB 9 DUP (?) ABC DB 0,1,3 DUP(?),3)操作数可以是字符串 STRING DB HELLO,STRING,汇编的表达式和运算符,表达式是常数、寄存器、标识符与一些运算符组合的序列,分数字表达式和地址表达式两种。汇编时按一定的优先规则对表达式进行计算后可得到一个数值或一个地址。,算术运算符 逻辑运算符 关系运算符 分析运算符 综合运算符,算术运算符,有+、-、*、/、MOD。 算术运算符可以用于数字表达式, 例如: MOV AL,2*7 汇编后为 MOV AL,0E 算术运算符也可以用于地址表达式,对地址运算的结果应有明确的物理意义,例两个地址的乘或除无意义,而加或减则可以, 例如: BUF DW 1,2,3,4,5,6,7,8 MAX DW ? MOV CX,(BUF-MAX)/2 汇编后为 MOV CX,8,逻辑运算符,逻辑运算符有AND、OR、XOR和NOT,它们只能用于数字表达式中。 例如:MOV CL,36H AND 0FH 经汇编后:MOV CL,06H,这些逻辑运算符也是8086/8088的指令助记符,会不会造成混乱呢? 不会的,前者在汇编时进行,而后者在指令执行时进行的。 例如: AND DX,36H AND 0FH 后一个逻辑运算符AND在汇编时进行, 汇编后得到表达式的值为06H,运行时执行前一个指令助记符AND,将(DX)与06H相与,结果在DX中。,关系运算符,共有6个,它们为: EQ(相等),NE(不等),LT(小于),GT(大于), LE(小于或等于),GE(大于或等于) 关系运算符的两个操作数必须都是数字或者是同一段内的两个存储器地址。 关系为真,结果为0FFFFH;关系为假,结果为0 例如: MOV BX,PORT GE 5 若PORT的值大于等于5,则汇编后为: MOV BX,0FFFFH 若PORT的值小于5, 则汇编后为: MOV BX,0,分析运算符,分析运算符的OFFSET,SEG可以把一个存储单元的地址分解为段基址和偏移量。 1)运算符OFFSET用来取地址的偏移量; 2)运算符SEG取存储单元的段地址。,例如在规范程序中有定义:ABC DB 11H,则执行: MOV DX,OFFSET ABC 此语句将ABC处的偏移量0150H送DX,则执行: MOV DX,SEG ABC 此语句将ABC处的段地址1EFFH送DX,3)分析运算符的TYPE,SIZE及LENGTH可以把存储器一些特征作为数值送回。,TYPE运算符用来取存储器的单元类型,各单元类型对应值如下: 存储器单元类型 对应值 DB(字节) 1 DW(字) 2 DD(双字) 4,LENGTH运算符用来计算一个存储区的单元的数目。 SIZE运算符用来计算一个存储区的字节总数。,若BUFFER存储区是用如下伪指令定义的: BUFFER DW 100 DUP (?) 则TYPE BUFFER等于2, LENGTH BUFFER等于100,SIZE BUFFER等于200,合成运算符PTR,用来对存储单元规定类型,通常和BYTE, WORD和DWORD等连起来使用。 考虑下面的语句: MOV 1000,0 ;类型不定,MOV BYTE PTR1000,0 ;1000字节单元清零 MOV WORD PTR1000,0 ;1000开始的字单元清零,1000字节单元清零?1000开始的字单元清零?,INC WORD PTRSI ;SI所指内存1个字自增1 JMP DWORD PTR SI ;段地址CS在SI、SI+1中 ;偏移量IP在SI+2、SI+3中,标号赋值伪指令EQU 为了便于阅读和修改,汇编程序常常使用标识符代表数据或者寄存器,必须在源程序前用EQU伪指令对标识符赋值。 格式为: 标识符 EQU 操作数 例如: CONSTANT EQU 100 COUNT EQU CX 在一个程序中不能用EQU对一个标识符多次重复定义。 标号解除伪指令PURGE 此伪指令用来解除用EQU对某一个标识符的赋值 例如: PURGE CONSTANT 等号伪指令 = 与EQU功能一样,但那是可以多次重复定义同一标识符,汇编的常用的伪指令,定位伪指令ORG 指定数据段或者代码段的偏移地址。 DATA SEGMENT ORG 0200H BUF DB 10 DUP (?) ;变量BUF的在数据段的偏移地址 DATA ENDS ;是0200H,省略为0000H CODE SEGMENT ASSUME CS:DCODE,DS,DATA ORG 1000H ;首条指令在代码段的偏移地址 MOV AX,DATA ;是1000H,省略为0100H MOV DS,AX CODE ENDS END,地址计数器 $ 汇编语言中,每一个段都有一个地址计数器$,指示当前指令或者数据的在段内的偏移量。,某数据段定义如下: DATA SEGMENT ORG 1000H BUF DW 1,2,$+3,$-2,1234H COUNT EQU ($-BUF)/2 NUM DW 5ABBH,$-BUF DATA ENDS 汇编后内存的分配如右所示:,概述: 1) SEGMENT和ENDS前面的标识符为各个段的名称,可以任意起名,一般把数据段的段名记做DATA,堆栈段的段名记做STACK,代码段的段名记做CODE。 2) ASSUME告诉汇编程序,哪一个段是数据段,哪一个段是堆栈段,哪一个段是代码段。除CS的值可以自动装入外,其他各段的实际值还要用MOV指令来赋值。 3) 指令性语句的标识符后面要有冒号,如标识符NEXT;指示性语句的标识符后面没有冒号,如标识符DATA、CODE。 4) 每一个汇编程序都要调用21H中断的4C功能子程序让程序正常结束,否则运行出错。,4.4 汇编程序设计概述,例:要求完成两个32位的数据相加运算 DATA SEGMENT X DD 10008423H Y DD 20007F00H Z DD ? DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START:MOV AX,DATA MOV DS,AX ;初始化DS,顺序程序设计,顺序程序完全按指令书写的前后顺序执行每一条指令,是最基本、最常见的程序结构,MOV SI,OFFSET X MOV AX,SI ;取第1个数的低16位送AX MOV DI,OFFSET Y ADD AX,DI ;低16位相加 MOV BX, OFFSET Z MOV BX,AX ;送低16位和 MOV AX,SI+2 ;取第1个数的高16位送AX ADC AX,DI+2 ;高16位连同进位标志相加 MOV BX+2,AX ;送高16位和 MOV AH,4CH INT 21H ;程序结束 CODE ENDS END START,例: 编写程序,判别键盘上输入的字符;若是09字符,则显示之;若为a-z字符,均显示“c”;若是回车字符(0DH),则结束程序;若为其它字符则不显示。,分支程序设计,CODE SEGMENT ASSUME CS:CODE START: MOV AH,1 INT 21H CMP AL,0DH JZ DONE CMP AL,0 JB START CMP AL,9 JA CHRDN MOV DL,AL MOV AH,2 INT 21H JMP START,CHRDN: CMP AL,a JB START CMP AL,z JA START MOV DL,C MOV AH,2 INT 21H JMP START DONE: MOV AH,4CH INT 21H CODE ENDS END,循环程序设计,循环结束的控制可以用循环次数,还可以用特定条件等: 1)计数控制循环:LOOP、LOOPZ、LOOPNZ 2)条件控制循环:JCC,例:计算SUMi,i1,100,COUNT EQU CX DATA SEGMENT ;数据段开始 SUM DW ? DATA ENDS ;数据段结束 CODE SEGMENT ;代码段开始 ASSUME CS:CODE,DS:DATA ORG 200H ;代码段偏移量为0200H处存放代码 MOV AX,DATA MOV DS,AX ;数据段寄存器赋值 XOR AX,AX ;累加器AX清零 MOV COUNT,100 ;置循环次数,CX=100 NEXT: ADD AX,CX ;求累加和 LOOP NEXT MOV SUM,AX ;将累加和送指定单元 MOV AH,4CH INT 21H ;4C号功能调用:终止当前程序并返回调用程序 CODE ENDS ;代码段结束 END ;汇编程序结束,例:以10进制向屏幕输出BX中的16位无符号数 分析:将BX的数据除以10,余数保存,商继续除以10,余数保存,直到商为0,余数的倒序即为待显示的数字;将待显示的数字加30H变成对应数字的ASCII码,调用21H中断的2号子程序向屏幕输出。,程序清单: STACK SEGMENT STAK DB 64 DUP(?) ;堆栈段大小是64个字节 TOP EQU LENGTH STAK ;标识符 STACK ENDS CODE SEGMENT ASSUME CS:CODE,SS:STACK ;绑定各个段与段寄存器 START:MOV AX,STACK MOV SS,AX ;初始化SS MOV SP,TOP ;初始化SP,MOV SI,10 ;SI中是除数 XOR CX,CX MOV BX,174 ;待输出的数据 MOV AX,BX NEXT: MOV DX,0 ;DX存放余数,清零 DIV SI ;AX中的数除以10 PUSH DX ;余数入栈 INC CX CMP AX,0 ;商为0则完成转换 JNZ NEXT OUTP: POP DX ;余数出栈 ADD DL,30H ;转化数字为对应的ASCII MOV AH,2 INT 21H LOOP OUTP MOV AH,4Ch INT 21H ;结束程序 CODE ENDS END START,注意:堆栈段定义建议如下,则SS和SP的初始化由系统完成: STACK SEGMENT STACK STACK,子程序,也称为过程,是功能相对独立的一段代码。每一个子程序都有唯一的合法标识符作为子程序名,它也是子程序入口地址的符号表示。 1)子程序调用: CALL 子程序名/寄存器/内存单元 主程序可以采用子程序名调用对应的子程序,目标地址就在CALL指令中,称为直接调用;目标地址也可以在寄存器或者存储单元中,称为间接调用。 子程序如果在当前代码段中,称为段内调用,子程序也可以不在当前代码段中,称为段间调用。 2)子程序返回:RET 子程序的出口地址是返回指令RET,可以带1个立即数作为参数,必须是子程序的最后一条指令,有段内返回和段间返回两种。,子程序设计,3)保护断点:为了保证子程序结束后,被中断的主程序返回断点处继续执行,必须在执行CALL指令时对返回地址推入堆栈进行保存,段内调用保存IP,段间调用保存CS和IP。 段内调用:SPSP2,SS:SPIP 段间调用:SPSP2,SS:SPCS SPSP2,SS:SPIP 4)恢复断点:在执行RET指令时,将CALL指令推入堆栈的返回地址恢复,段内调用恢复IP,段间调用恢复CS和IP。 段内返回:IPSS:SP,SPSP2 段间返回:IPSS:SP,SPSP2 CSSS:SP,SPSP2 注意:保护断点的入栈过程和恢复断点的出栈过程是系统自动完成的,不需要程序员干预。,5)子程序格式:子程序以PROC开始,以ENDP结束;如果是段内调用,用默认值NEAR属性。段间调用,用FAR属性。,过程名 PROC NEAR|FAR 过程名 ENDP,6)保护现场:子程序运行过程时,会使用CPU中的某些通用寄存器,为了在子程序结束之后主程序恢复调用前的状态继续运行,必须在子程序执行之前,把子程序将要使用的寄存器的数据压入堆栈加以保护。,7)恢复现场:将原来推入堆栈的通用寄存器的数据弹出,恢复主程序调用之前程序的运行状态。,注意:保护现场和恢复现场是子程序完成的,根据子程序的需要将相应的寄存器加以保护。,子程序名 PROC NEAR ;该子程序用于段内调用 PUSH AX ;保护寄存器:顺序压入堆栈 PUSH BX PUSH CX ;过程体 POP CX ;恢复寄存器:逆序弹出堆栈 POP BX POP AX RET ;过程返回 子程序名 ENDP ;过程结束,8)子程序基本内容:子程序除了固定格式外,一般还包括保护现场的PUSH指令和恢复现场的POP指令。,子程序设计的一个关键问题就是堆栈内容和堆栈指针的变化情况。,子程序的参数传递 子程序设计的另一个关键问题是参数以及参数传递。 参数的类型有两种: -入口参数:主程序调用子程序时,提供给子程序运行的原始数据,可以是数据本身也可以是地址。 -出口参数:子程序执行结束时提供给主程序的结果。 子程序的参数传递主要有以下三种方式: -利用寄存器传递参数:将入口参数或出口参数放在规定的寄存器中,采用寄存器传递出口参数的寄存器不能保护。 -利用存储单元传递参数:将入口参数或者出口参数放在内存区域中,一般采用共享变量实现。 -利用堆栈传递参数:将入口参数或者出口参数推入堆栈,利用堆栈完成参数交换,必须注意堆栈内容和堆栈指针。,利用寄存器传递参数 由于CPU内部寄存器个数有限,该方式仅仅适用于传递参数不多的情况。 例:编写一个子程序,该子程序的功能是将16位无符号数转换成10进制数向屏幕显示。 子程序名:Display 入口参数:BX 出口参数:无 子程序程序清单: Display PROC NEAR PUSH AX ;保护寄存器 PUSH BX PUSH CX PUSH DX PUSH SI MOV SI,10 ;SI中是除数 XOR CX,CX MOV AX,BX ;入口参数在BX中,NEXT1: MOV DX,0 ;DX存放余数,清零 DIV SI ;AX中的数除以10 PUSH DX ;余数入栈 INC CX CMP AX,0 ;商为0则完成转换 JNZ NEXT1 OUTP: POP DX ;余数出栈 ADD DL,30H ;转化数字为对应的ASCII MOV AH,2 INT 21H LOOP OUTP POP SI ;恢复寄存器 POP DX POP CX POP BX POP AX RET ;子程序返回 Display ENDP,例:计算1+2+3+100,调用子程序Display显示结果。,STACK SEGMENT STACK STACK STAK DB 64 DUP(?) ;堆栈段大小是64个字节 STACK ENDS CODE SEGMENT ASSUME CS:CODE,SS:STACK MAIN PROC ;主过程开始 START:MOV CX,100 NEXT:ADD AX,CX LOOP NEXT MOV BX,AX ;置入口参数 CALL Display ;调用子程序 MOV AH,4CH INT 21H MAIN ENDP ;主过程结束 Display PROC ;子过程开始,属性为NEAR Display ENDP ;子过程结束 CODE ENDS END START,利用存储单元传递参数 子程序和主程序使用同一个变量名存取数据就是利用共享存储单元进行参数传递,类似于C的全局变量。 如果主程序还要利用原来的变量值,则需要保护和恢复 利用共享变量传递参数,子程序的通用性较差,但特别适合在多个程序段间、尤其在不同的程序模块间传递数据 例:利用子程序来实现数据块的移动。 子程序名:MOVEDAT 入口参数:字变量SCRADR存放源数据块首地址 字变量DESADR存放目标数据块首地址 字变量LEN存放数据块字节数 出口参数:无,数据块传送的三种情况: 1.对于数据块无重叠区的情况,可分别从首(末)地址开始传送,如(A) 2.对有数据块有重叠区的情况,应分别对待: 当源数据块首址小于目标块首址时,应从数据末址开始传数,如(B) 当源数据块首址大于目标块首址时,应从数据首址开始传数,如(C),DATA SEGMENT BUF1 DB 100 DUP (?) BUF2 DB 100 DUP (?) SRCADR DW ? DSTADR DW ? LEN DW ? DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA,ES:DATA MAIN PROC START: MOV AX, DATA MOV DS, AX MOV ES, AX LEA AX,BUF1 MOV SRCADR,AX ;入口参数赋值 LEA AX,BUF2 MOV DESADR,AX ;入口参数赋值 MOV LEN,100 ;入口参数赋值 CALL MOVEDAT ;调用子程序 MOV AH,4CH INT 21H MAIN ENDP,MOVEDAT PROC PUSH SI ;保护寄存器 PUSH DI PUSH CX MOV SI,SRCADR ;源数据块首地址送SI MOV DI,DESADR ;目标数据块首地址送DI MOV CX,LEN ;传送长度送CX CLD CMP SI,DI ;比较源块和目标块首地址 JA DONE ;小于则从首地址递增传送 STD ;大于则从末地址递减传送 ADD SI,CX DEC SI ;源串末地址 ADD DI,CX DEC DI ;目标串末地址 DONE:REP MOVSE POP SI ;恢复寄存器 POP DI POP CX RET MOVEDAT ENDP CODE ENDS END START,利用堆栈传递参数 参数传递还可以通过堆栈这个临时存储区。主程序将入口参数压入堆栈,子程序从堆栈中取出参数;子程序将出口参数压入堆栈,主程序弹出堆栈取得它们。 采用堆栈传递参数是程式化的,它是编译程序处理参数传递、以及汇编语言与高级语言混合编程时的常规方法。,例:编写子程序求2个16位数据的和。 子程序名:Addition 入口参数:堆栈 出口参数:AX STACK SEGMENT STACK STACK STAK DW 50 DUP(?) ;堆栈段大小是50个字 STACK ENDS DATA SEGMENT DAT1 DW 100 DAT2 DW 200 SUM DW ? DATA ENDS,CODE SEGMENT ASSUME CS:CODE,DS:DATA,SS:STACK MAIN PROC START: MOV AX, DATA MOV DS, AX MOV AX, DAT1 PUSH AX ;DAT1入栈 MOV AX, DAT2 PUSH AX ;DAT2入栈 CALL Addition ;调用子程序 MOV SUM, AX MOV AH, 4CH INT 21H MAIN ENDP Addition PROC PUSH BP MOV BP, SP ;得到栈顶地址 MOV AX, BP+4 ;取第二个数 ADD AX, BP+6 ;取第一个数和第二个数相加 POP BP RET 4 ;SP+4,丢掉堆栈无用参数 Addition ENDP CODE ENDS END START,例:编写一个程序找出内存N个连续的字节(字或者双字)空间中存放的无符号数的最大值。,程序清单: STACK SEGMENT STACK STACK STAK DW 50 DUP(?) ;堆栈段大小是50个字 STACK ENDS DATA SEGMENT ARRAY DB 3,12,45,21,97,56,8 ;存放7个数字 MAXNUM DB ? ;存放最大数 DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA,SS:STACK MAIN PROC START:MOV AX,DATA MOV DS,AX ;数据段寄存器赋值 XOR AX,AX,汇编程序设计举例,MOV BX,OFFSET ARRAY ;取数组的偏移量送BX MOV CX,6 ;比较的次数送CX MOV AL,BX ;取第一个数 LABLE:INC BX ;偏移量加1,指向下一个数 CMP AL,BX ;比较AL和第N+1个数 JNB NEXT ;不低于则转入NEXT MOV AL,BX ;否则将大数送AL NEXT:LOOP LABLE ;继续下一次比较 MOV MAXNUM,AL ;最大数送MAXNUM单元 MOV BX,AX CALL Display ;调用显示子程序 MOV AH,4CH INT 21H MAIN ENDP Display PROC ;显示子程序 Display ENDP CODE ENDS END START,例:编写一个程序使内存5个连续的字节(字或者双字)空间中存放的无符号数按序排列存放。 分析:冒泡法,将低地址字节空间中的数和其他4个字节空间的数分别4次两两比较,大则交换两个字节空间的数据,否则不交换;经过1趟比较之后最大的数交换至高字节地址空间。对于5个数据,只要经过四趟比较数据就会按序排列存放。 利用BX寄存器存放比较的趟数,每次比较完1趟后BX的值减1,当BX的值为0时,比较结束。,程序清单: STACK SEGMENT STACK STACK STAK DW 50 DUP(?) ;堆栈段大小是50个字 STACK ENDS DATA SEGMENT ARRAY DB Z,P,S,E,M ;存放5个数 DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA,SS:STACK ;绑定各个段与段寄存器 START:MOV AX,DATA MOV DS,AX,MOV BX,4 ;送大循环的次数,比较的趟数 SORT:MOV CX,BX ;送小循环的次数,每趟比较的次数 MOV SI,OFFSET ARRAY ;取数组的偏移量送SI COMP:MOV AL,SI ;送数组中第n个数 CMP AL,SI+1 ;比较数组中第n个数和n+1个数 JNA LABLE XCHG AL,SI+1 MOV SI,AL ;大于则交换两个数 LABLE:INC SI ;指向下一个数 LOOP COMP ;继续下一次比较 DEC BX ;完成了一趟比较,大循环减1 JNZ SORT ;未完成排序,则转入下一趟 MOV CX,5 ;循环显示5个

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论