第四章 汇编程序设计
description
Transcript of 第四章 汇编程序设计
11
4.1 4.1 常量、变量和标号常量、变量和标号4.2 4.2 汇编语言源程序格式汇编语言源程序格式4.3 4.3 伪指令伪指令4.4 4.4 顺序程序设计顺序程序设计4.5 4.5 分支程序设计分支程序设计4.6 4.6 循环程序设计循环程序设计4.7 4.7 子程序子程序
第四章 汇编程序设计第四章 汇编程序设计
22
44 .. 1 1 常量、变量和标号常量、变量和标号 汇编语言的数据可以分为常量和变量。常量可以作为指令的立即数或者汇编语言的数据可以分为常量和变量。常量可以作为指令的立即数或者伪指令的参数,变量作为存储器的操作数。汇编语言中的标号、名字,具伪指令的参数,变量作为存储器的操作数。汇编语言中的标号、名字,具有逻辑地址和类型属性,主要用于作地址操作数。有逻辑地址和类型属性,主要用于作地址操作数。
4.1.1 4.1.1 常量表示一个固定的值常量表示一个固定的值,有,有 44 种形式;种形式; 1.1. 常量常量 由二进制、八进制、十进制和十六进制形式表达的数值。由二进制、八进制、十进制和十六进制形式表达的数值。 (( 11 )二进制由)二进制由 00 、、 11 两个数字组成,以字母两个数字组成,以字母 BB (或(或 bb )结尾;例如)结尾;例如 101101
101011B101011B 。。 (( 22 )八进制由)八进制由 0—70—7 这这 88 个数字组成,以字母个数字组成,以字母 QQ (或(或 qq )结尾;例如)结尾;例如 4545
6701Q6701Q 。。 (( 33 )十进制由)十进制由 0—90—9 这这 1010 个数字组成,以字母个数字组成,以字母 DD (或(或 dd )结尾;例如)结尾;例如 11
26789D26789D 。但十进制可以省略后缀字母。因此,默认的不加后缀字母的数就。但十进制可以省略后缀字母。因此,默认的不加后缀字母的数就是十进制数。是十进制数。
(( 44 )十六进制由)十六进制由 0—90—9 、、 A—FA—F 组成,以字母组成,以字母 HH (或(或 hh )结尾;例如)结尾;例如 456456ABHABH 。以字母。以字母 A—FA—F 开头时,数的前面要加开头时,数的前面要加 00 ,以示与标识符加以区别。,以示与标识符加以区别。
2.2. 字符串字符串 字符串常以单引号或双引号括起来的单个字符或者多个字符,例如:‘字符串常以单引号或双引号括起来的单个字符或者多个字符,例如:‘ ff
g1256K^&*KK’g1256K^&*KK’ ;其数值是每个字符对应的;其数值是每个字符对应的 ASCASC 码;码; ASCASC 码表见附录。 码表见附录。
33
3 .符号常量 符号常量使用标识符来表达一个数值;符号定义伪指令有 “ EQU” 和
“ =” 格式为: 符号名 EQU 数值表达式 符号名 EQU < 字符串 > ;或者用引号 符号名 = 表达式 例如: X EQU 56 ;含义为 MOV X , 56 Y EQU “ hello” ;含义为 MOV Y ,“ hello” Z = 13 ;含义为 MOV Z , 13 4 .数字表达式 数字表达式由操作符连接的各种常量所构成表达式;汇编语言进行汇
编过程中,最终得到一个确定的数值,因此,也称为常量。 例如: MOV AL , 1*2+3 ;( AL ) = 1*2+3 = 5 MOV AH , 13H OR 45H MOV BH , 110110B SHL 2 汇编所用的运算符,见表4.1。
44
4.1.2 4.1.2 变量变量 变量就是内存单元;变量先定义后使用。变量就是内存单元;变量先定义后使用。 格式: 变量名 伪指令 初值格式: 变量名 伪指令 初值 (( 11 ))变量名是用户自己定义的标识符,这个符号表示内存地址,常称为变量名是用户自己定义的标识符,这个符号表示内存地址,常称为符号地址。当然,变量名可以没有,初值分配的地址称为无符号地址。符号地址。当然,变量名可以没有,初值分配的地址称为无符号地址。 (( 22 ))初值是用逗号分开的参数,主要由常量、表达式、?、初值是用逗号分开的参数,主要由常量、表达式、?、 DUP DUP 组成组成 其中:?表示初值不确定或未赋初值。其中:?表示初值不确定或未赋初值。 DUPDUP (( 55 )表示重复初值 )表示重复初值 5 5 次。次。 (( 33 )变量定义的伪指令有 )变量定义的伪指令有 DBDB 、、 DWDW 、、 DDDD 、、 DFDF 、、 DQDQ 、、 DTDT
例如: 例如: DATA SEGMENT DATA SEGMENT ;数据段 ;数据段 X DB X DB -- 56H 56H ; ; XX 的值的值 == -- 56H 56H Y DB 80HY DB 80H ,?,“,?,“ W” W” ,, 3 DUP3 DUP (( 00 ) ;) ; Z DW Z DW ? ;? ; ZZ 无初值无初值 DATA ENDSDATA ENDS
变量定义在数据段 变量定义在数据段 DATA SEGMENTDATA SEGMENT 内;内; X X 为字节型数据,值为-为字节型数据,值为- 5656HH ;;
YY 为字节型;为字节型; ZZ 单元为字型数据,没有初值。单元为字型数据,没有初值。 本例在内存的分配方法见本例在内存的分配方法见图图4.1 4.1 。。
55
以一个完整的汇编语言程序来说明;以一个完整的汇编语言程序来说明; DATA SEGMENT DATA SEGMENT ;定义数据段,段名为;定义数据段,段名为 DATADATA
X DB 34H X DB 34H ;定义各种数据;定义各种数据 Y DW “HH”Y DW “HH”
…… ……....
DATA ENDS DATA ENDS ;数据段定义结束;数据段定义结束 STACK SEGMENT STACK SEGMENT ;定义堆栈段,段名为;定义堆栈段,段名为 STACKSTACK
DB 100 DUPDB 100 DUP (( 00 ) ;开辟堆栈区域) ;开辟堆栈区域 100100 ,初值为,初值为 0 0
STACK ENDS STACK ENDS ;堆栈段定义结束;堆栈段定义结束 CODE SEGMENT CODE SEGMENT ;定义代码段,段名为;定义代码段,段名为 CODECODE
ASSUME CSASSUME CS :: CODECODE ,, DSDS :: DATADATA ,, SSSS :: STACK STACK
START:MOV AXSTART:MOV AX ,, DATA DATA
MOV DSMOV DS ,, AX AX ;这两条给;这两条给 DSDS 赋初值赋初值 …… …… ;为源程序指令序列;为源程序指令序列 MOV AH,4CH MOV AH,4CH ;; DOSDOS 调用调用 INT 21HINT 21H ,功能号,功能号 4CH4CH
INT 21H INT 21H ;程序终止;程序终止CODE ENDS CODE ENDS ;代码段结束;代码段结束END START END START ;汇编结束;汇编结束 返回本章目录
66
4.2 4.2 汇编语言的源程序格式汇编语言的源程序格式 以一个完整的汇编语言程序来说明; DATA SEGMENT ;定义数据段,段名为 DATA X DB 34H ;定义各种数据 Y DW “HH” …….. DATA ENDS ;数据段定义结束 STACK SEGMENT ;定义堆栈段,段名为 STACK DB 100 DUP ( 0 ) ;开辟堆栈区域 100 ,初值为 0 STACK ENDS ;堆栈段定义结束 CODE SEGMENT ;定义代码段,段名为 CODE ASSUME CS : CODE , DS : DATA , SS : STACK START:MOV AX , DATA MOV DS , AX ;这两条给 DS 赋初值 …… ;为源程序指令序列 MOV AH,4CH ; DOS 调用 INT 21H ,功能号 4CH INT 21H ;程序终止CODE ENDS ;代码段结束END START ;汇编结束
77
汇编语言源程序应包括: ( 1 )汇编语言源程序存入内存时,分四个段进行存放;程序中一般有
二个段:数据段、代码段;而附加数据段用于存放字符串数据,当程序没有用到字符串数据时可省略,堆栈段在内存中建立堆栈区,用于中断、子程序的调用,当程序没有用到中断、子程序时可省略;数据段在内存中建立工作区,存放程序需要进行操作的数据、变量等;代码段存放程序执行的指令集合,完成程序的操作。段与段之间随意存放。
( 2 )每个段以 “段标识符 SEGMENT” 开始,以 “段标识符 END” 结束 START:MOV AX,DATA 表示程序操作指令开始,整个程序以 “ END START” 结束,两个 START 相对应,当然可用你感兴趣的标识符。
( 3 )伪指令 ASSUME 告诉汇编程序,段地址与段寄存器之间的关系,各段在内存的起始地址。源程序要对数据段寄存器 DS 进行初始化,采用两条指令 MOV AX,DATA 和 MOV DS,AX实现。
( 4 )如果要对指令进行说明,在一条指令后加 “ ;” 接着写说明部分;汇编语言在编译时,对此不作处理。操作数之间、参数之间用 “ ,” 号分隔;其它部分一般用多个空格分隔符,标号后加 “ :” 号,表示逻辑地址;原则上一条指令书写一行。
返回本章目录
88
44 .. 3 3 伪指令伪指令
伪指令是用来对相关指令进行说明;主要有段定义、过程定义,数据定伪指令是用来对相关指令进行说明;主要有段定义、过程定义,数据定义、符号定义,模块定义、程序结构定义等,由于不产生代码,因此称为伪指义、符号定义,模块定义、程序结构定义等,由于不产生代码,因此称为伪指令。常用的有下几种:令。常用的有下几种:
11 .变量定义伪指令:.变量定义伪指令:为变量申请固定长度的内存空间;为变量申请固定长度的内存空间; (( 11 )定义字节变量:用于分配一个或多个字节单元)定义字节变量:用于分配一个或多个字节单元 例如: 例如: X DB ‘a’ X DB ‘a’ ;分配一个字节单元 ;分配一个字节单元 Y DB 10 DUPY DB 10 DUP (( 00 ) 连续分配) 连续分配 1111 个字节单元个字节单元 (( 22 ) 定义字变量:用于分配一个或多个字单元) 定义字变量:用于分配一个或多个字单元 例如: 例如: Z DW 8080H Z DW 8080H ;分配;分配 11 个字单元,一个字个字单元,一个字 22 个字节个字节 W DW W DW ?,‘?,‘ ABC’ ABC’ ;分配多个字单元;分配多个字单元 (( 33 )) DD DD 定义双字变量,定义双字变量, DQ DQ 定义 定义 4 4 字变量,字变量, DT DT 定义 定义 1010 字变量字变量 22 .符号定义伪指令:.符号定义伪指令:为程序中的表达式赋予一个名字为程序中的表达式赋予一个名字 (( 11 )) EQU EQU 伪指令:将表达式的值赋给其前面的名字,以名字来代替表达式;伪指令:将表达式的值赋给其前面的名字,以名字来代替表达式;
程序中不允许对已经定义过的名字重新赋新的值。程序中不允许对已经定义过的名字重新赋新的值。 例如: 例如: X EQU 100 X EQU 100 ;将 ;将 100 100 赋给 赋给 XX
(( 22 )) = = 伪指令:将表达式的值赋给其前面的名字,与 伪指令:将表达式的值赋给其前面的名字,与 EQU EQU 区别在于:区别在于: = = 伪指令定义后,可以多次改变,重新给变量赋新的值。伪指令定义后,可以多次改变,重新给变量赋新的值。
99
3 . ASSUME 段分配伪指令:设定四个段与对应的寄存器之间的关系 例如: ASSUME CS : CODE1,DS : DATA1,SS : STACK1 4 . SEGMENT/ENDS 段定义伪指令:对数据段、代码段、堆栈段、
附加数据段进行定义和赋予一个名字,指明类型、类别等; 例如: AA SEGMENT …….. AA ENDS 这里 SEGMENT 表示定义的一个逻辑段开始, ENDS 表示所定义的
逻辑段结束,逻辑段的名称为 AA 。类型、类别等不作介绍。 5 . ORG 定位伪指令: ORG 是起始位置设定; 6 .程序计数器伪指令 $ :表示当前偏移地址的值。例如: DATA SEGMENT Y DW 8899H BUF DB 10 ,- 45H , 66H ,“ A” N = $ - BUF ;当前地址 $ - BUF 的偏移地址, BUF 数据
的个数 X DB 12 ORG $ + 10 ;设置 Z 的地址偏移量为当前位置后移 10 个单
元 Z DW “ABCDEF” DATA ENDS 7 . PROC 过程定义伪指令: PROC 定义一个过程。
返回本章目录
1010
44 .. 4 4 顺序程序设计顺序程序设计 顺序程序结构是最基本、最常见的结构,完全按照指令书写的顺序程序结构是最基本、最常见的结构,完全按照指令书写的顺序执行每条指令。顺序程序结构在程序中都会出现,是复杂结构顺序执行每条指令。顺序程序结构在程序中都会出现,是复杂结构的一部分;是分支程序的其中一个分支;循环程序的循环体内就是的一部分;是分支程序的其中一个分支;循环程序的循环体内就是顺序程序构成。顺序程序构成。 例如:有三个变量 例如:有三个变量 AA 、、 BB 、、 CC ,其值分别为 ,其值分别为 33 、、 44 、、 55 ,求出 ,求出 AA 、、 BB 、、C C 的和,将和存入变量 的和,将和存入变量 SUMSUM 中。中。 DATA SEGMENT DATA SEGMENT ;定义数据段;定义数据段 A DB 3A DB 3
B DB 4B DB 4
C DB 5 C DB 5 ;给 ;给 AA ,, BB ,, CC 赋初值赋初值 SUM DB SUM DB ? ;存放和,无初值? ;存放和,无初值 DATA ENDDDATA ENDD
CODE SEGMENTCODE SEGMENT
ASSUME CSASSUME CS :: CODE,DSCODE,DS :: DATA DATA ;本程序只需两个段;本程序只需两个段START:MOV AX,DATA START:MOV AX,DATA ;初始化 ;初始化 DS DS
1111
START:MOV AX , DATA ;初始化 DS MOV DS , AX MOV BH , A ;将 A 的值送到 BH寄存器 ADD BH , B ;进行求和 ADD BH , C MOV SUM , AH ;存入运算结果 MOV AH , 4CH ;返回 DOS INT 21HCODE ENDS ;代码段结束END START ;汇编结束 本例子,源程序仅由代码段和数据段两部分组成。在数据段,定义了
变量 A 、 B 、 C ,即内存中数据段的三个连续的单元,并赋给了初值,接着定义了存储和的变量 SUM ,即数据段中的第四个单元,由于没有初值,用?表示,当然也可赋初值 0 。
执行代码段中的指令,对于顺序程序结构,从第一条指令开始执行,依次执行第二条,……直至最后一条指令。 返回本章目录
1212
44 .. 5 5 分支程序设计分支程序设计
汇编语言中,使用无条件指令 汇编语言中,使用无条件指令 JMP JMP 和条件转移指令 和条件转移指令 JJCCCC 来实现来实现分支程序设计。条件转移指令的条件指的是:分支程序设计。条件转移指令的条件指的是: FLAG FLAG 的标志位。影响的标志位。影响FLAGFLAG 、设置 、设置 FLAG FLAG 标志位的指令主要有算术运算指令、比较指令标志位的指令主要有算术运算指令、比较指令CMPCMP 、测试指令 、测试指令 TESTTEST ;因此,;因此, JJCC CC 前面一般有影响标志位的指令。前面一般有影响标志位的指令。分支程序结构有单分支和多分支两种。分支程序结构有单分支和多分支两种。 11 .单分支程序设计.单分支程序设计 例如:内存单元例如:内存单元 XX 中存放一个数据,求出中存放一个数据,求出 XX 的绝对值,存入内存的绝对值,存入内存单元 单元 YY 中。中。见示意图见示意图4.2 4.2 。。 DATA SEGMENT DATA SEGMENT
X DB —23D X DB —23D ;请随意存入一个数据;请随意存入一个数据 Y DB ? Y DB ? ;存放 ;存放 XX 的绝对值的绝对值 DATA ENDSDATA ENDS
CODE SEGMENTCODE SEGMENT
ASSUME DSASSUME DS :: DATADATA ,, CSCS :: CODE CODE
1313
见示意图4.2
START : MOV AX , DATA MOV DS , AX MOV AH , X ;取出 X 单元的值 CMP AH , 0 ;判断 X 值 JGE LP1 ; X 为正数,直接存放 NEG AH ; X 为负数,求绝对值(补码)LP1: MOV Y , AH ;存入 X 的绝对值 MOV AH , 4CH ;返回 DOS INT 21H CODE ENDS ;代码段结束 END START ;汇编结束 单分支程序设计,当条件满足(成立)时,发生转移,跳过分支体;
当条件不满足(不成立)时,按程序书写的顺序向下执行分支体。
1414
22 .多分支程序设计.多分支程序设计 实际问题存在多个条件,进行不同的操作时,用到多分支程序。实际问题存在多个条件,进行不同的操作时,用到多分支程序。 例如:键盘上输入一个字符,如果是数字字符,将之对应的十进 制数据,例如:键盘上输入一个字符,如果是数字字符,将之对应的十进 制数据,存入内在单元 存入内在单元 DD ,否则,将 ‘,否则,将 ‘ X’ X’ 字符存入单元 字符存入单元 DD ,流程,流程见图见图4.3 4.3 。。 D DB D DB ? ;根据输入的结果存放? ;根据输入的结果存放 DXDX 的值的值STARTSTART :: MOV AXMOV AX ,, DATADATA MOV DSMOV DS ,, AX AX MOV AHMOV AH ,, 01H 01H ;从键盘输入一个字符;从键盘输入一个字符 INT 21HINT 21H CMP ALCMP AL ,‘,‘ 0’ 0’ ;输入的字符与‘;输入的字符与‘ 0’0’比较比较 JB LP1 JB LP1 ;小于‘;小于‘ 0’0’ ,不是数字字符,不是数字字符 CMP ALCMP AL ,‘,‘ 9’ 9’ ;与‘;与‘ 9’9’比较比较 JA LP1 JA LP1 ;大于‘;大于‘ 9’9’ ,不是数字字符,不是数字字符 SUB ALSUB AL ,, 30H 30H ;将输入的数字字符转为对应的数据;将输入的数字字符转为对应的数据 MOV DMOV D ,, AL AL JMP EXITJMP EXIT LP1:MOV DLP1:MOV D ,‘,‘ X’ X’ ;输入的不是数字字符,将‘;输入的不是数字字符,将‘ X’X’ 存入存入 DD 单元单元 EXIT:MOV AHEXIT:MOV AH ,, 4CH 4CH ;返回;返回 DOSDOS INT 21HINT 21HCODE ENDS CODE ENDS ;代码段结束;代码段结束END START END START ;汇编结束;汇编结束 返回本章目录
1515
44 .. 6 6 循环结构程序设计循环结构程序设计
循环结构程序是指满足条件时,重复执行一段指令,称为循环循环结构程序是指满足条件时,重复执行一段指令,称为循环体;不满足条件时,绕过循环体。循环结构一般由三个部分组成:体;不满足条件时,绕过循环体。循环结构一般由三个部分组成: (( 11 )循环初始化部分:为循环开始作准备。赋循环次数、处理)循环初始化部分:为循环开始作准备。赋循环次数、处理多个数据时的初地址、所用内存数据单元的初始化、所用寄存器的多个数据时的初地址、所用内存数据单元的初始化、所用寄存器的初始化等;初始化等; (( 22 )循环体:重复执行的指令序列;还包括修改控制循环所用)循环体:重复执行的指令序列;还包括修改控制循环所用的参数,如计数器、操作时所用地址的指针等。的参数,如计数器、操作时所用地址的指针等。 (( 33 )循环控制部分:判断循环条件是否成立,确定循环是否继)循环控制部分:判断循环条件是否成立,确定循环是否继续。循环的控制方法有两种;续。循环的控制方法有两种; 先执行循环体,然后判断循环条件是否成立;循环体一定要执先执行循环体,然后判断循环条件是否成立;循环体一定要执行一次。这点设计程序时要留意,否则,程序执行结果出错。行一次。这点设计程序时要留意,否则,程序执行结果出错。 先判断循环条件是否成立,如果成立,进入循环体,不成立,先判断循环条件是否成立,如果成立,进入循环体,不成立,不进入循环体;循环体可能一次都不执行。不进入循环体;循环体可能一次都不执行。 循环结构程序设计的几种常用的控制循环方法:循环结构程序设计的几种常用的控制循环方法:
1616
1 .计数控制循环 计数控制循环这种方式,事先就知道要循环的次数,将要循环的
次数先存入 CX 中,每执行一次循环, CX 的值减 1 ,当( CX ) = 0时,结束循环。次数来作为控制循环,最好的方法是利用 8086 汇编系统提供的循环指令 LOOP 和 JCXZ 来实现。
例如:内存 BUF 区域,存放有 10 个带符号的字节数据,将它们求和,存入字节单元 SUM 中(和不超过字节)。
BUF DB 23 ,- 45 ,- 56 , 0 , 21 , 34 , 78 , 9 , 8 ,-32
SUM DB 0 ;不考虑和超过字节 START:MOV AX , DATA MOV DS , AX MOV CX , 10 ;循环次数赋初值 MOV SI , OFFSET BUF ;第一个数据单元的地址初值 MOV AH , 0 ;累加寄存清 0
1717
LP1:ADD AH , [ SI ] ;求和
INC SI ;指向下个单元
DEC CX ;循环次数修改
CMP CX , 0 ;循环条件判断
JNZ LP1 ;次数未到,循环继续
MOV SUM , AH ;循环结束,存放结果
EXIT:MOV AH , 4CH ;返回 DOS
INT 21H
CODE ENDS ;代码段结束
END START ;汇编结束
1818
2 .条件控制循环 实际应用中,循环次数是无法事先知道的,计数控制循环受到很大的局限性;循环次数是实际问题中的某个条件来控制,以结束循环,控制循环的。 例如:内存 BUF 区域有多个带符号的数据,以回车结束,统计正数的个数,并将统计的个数存入内存 SUM 单元。 工作流程见图 4.4 。 BUF DB 23 ,- 45 ,- 56 , 0 , 21 , 34 , 78 , 9 , 8,- 32….,0DH SUM DW 0 START:MOV AX , DATA MOV DS , AX MOV SI , OFFSET BUF ;第一个数据单元的地址初值
1919
工作流程见图 4.4 。LP1:MOV AH , [ SI ] ;取出当前单元的数据 CMP AH , 0DH ;当前单元的数据是回车符吗 JZ EXIT ;是回车符,循环结束 CMP AH , 0 JS LP2 ;是负数,不统计,进入下个单元 INC SUM ;是正数,统计 LP2 INC SI ;进入下一个单元 JMP LP1 ;继续循环EXIT : MOV AH , 4CH ;返回 DOS INT 21HCODE ENDS ;代码段结束 END START ;汇编结束 返回本章目录
2020
程序中一段指令是实现固定的功能,而每次调用的参数不同,这些功能经常用到,这时采用子程序。这样设计结构清楚,程序的维护方便。当主程序需要执行这个子程序功能时,通过调用该子程序,执行子程序,子程序完成后返回主程序调用处,继续主程序后面的指令的执行。与子程序有关的指令有子程序的调用 CALL 、子程序返回 RET 两条指令。
4.6.1 子程序的调用指令 子程序的调用有 4 种情况,类似于无条件的转移 JMP 的情况。 (1) 段内调用,直接寻址 格式: CALL label ; 当前 IP 入栈,实现转移,转到偏移地址为 label处执行 (2) 段内调用,间接寻址 格式: CALL r16/m16 ; 当前 IP 入栈,转到偏移地址为 r16/m16 的内容指示的位置执行 (3) 段间调用,直接寻址 格式: CALL far ptr label ; 当前 IP 入栈,实现转移,转到 label 所在的段,偏移地址为 label处执行 (4) 段间调用,间接寻址 格式: CALL far ptr mem ; 当前 IP 入栈,实现转移,转到 mem 所在的段,偏移地址为 mem处执行
44 .. 7 7 子程序子程序
2121
4.7.34.7.3 子程序定义伪指令子程序定义伪指令 子程序在汇编语言中称为过程,每个子程序过程有一个唯一的过程名;子程序在汇编语言中称为过程,每个子程序过程有一个唯一的过程名;由一对伪指令由一对伪指令 PROCPROC 和和 ENDPENDP 定义。格式为:定义。格式为: 过程名 过程名 PROCPROC (属性)(属性) 指令系列 ;过程体指令系列 ;过程体 过程名 过程名 ENDPENDP
例如:编写将寄存器例如:编写将寄存器 ALAL 的低的低 44 位的一个位的一个 1616 进制数,转换成相应的进制数,转换成相应的 ASCIIASCII码码
的子程序的子程序 HEXASC PROC HEXASC PROC ;定义一个过程,名为;定义一个过程,名为 HEXASCHEXASC
AND ALAND AL ,, 0FH 0FH ;截取;截取 ALAL 的低的低 44位位 OR ALOR AL ,, 30H 30H ;; 0-90-9 的的 ASCASC 码为码为 3030 -- 39H39H
CMP ALCMP AL ,, 39H 39H ;判断是;判断是 00 -- 99 ,还是,还是 AA -- FF
JBE LP1 JBE LP1 ;; ALAL 内容内容 <39H<39H ,, ALAL 为为 00 -- 99
ADD ALADD AL ,, 7 7 ;; AA -- FF 的的 ASCASC 码,比码,比 9D9D大大 77
LP1:RETLP1:RET
HEXASC ENDP HEXASC ENDP ;名为;名为 HEXASCHEXASC 的过程结束的过程结束
2222
通过上面的子程序的例子,看出过程编写的规则: ( 1 )以 “过程名 PROC” 开始,以 “过程名 ENDP” 结束;
子程序过程体内包含有 RET 指令,遇到此指令,即返回主程序,从而结束了子程序的执行。
( 2 )子程序所用到的寄存器,子程序开始时,都应该利用堆栈来保护,防止子程序使用时破坏其原来的数据;子程序返回调用者前进行恢复原来的数据。
( 3 )子程序安排在主程序的代码段之外,最好放在主程序终止执行的位置,也可放在主程序开始执行之前。
( 4 )子程序允许与主程序共用一个数据段;也可以使用不同的数据段。
( 5 )子程序可以有多个出口(即内有多个 RET 指令);多个入口,即主程序与子程序多个参数传递。
2323
4.7.4 4.7.4 子程序参数的传递子程序参数的传递 主程序与子程序的参数传递,指主程序要子程序处理的数据通过什 主程序与子程序的参数传递,指主程序要子程序处理的数据通过什么途径、方式、方法传送给子程序。方法有:用寄存器、用变量、用堆么途径、方式、方法传送给子程序。方法有:用寄存器、用变量、用堆栈。栈。 11 .寄存器法.寄存器法 主程序需要子程序处理的数据,存放在一个事先约定的寄存器中,主程序需要子程序处理的数据,存放在一个事先约定的寄存器中,子程序到这个寄存器中取出数据进行处理,结果传给调用者。子程序到这个寄存器中取出数据进行处理,结果传给调用者。 22 .内存单元变量法.内存单元变量法 主程序需要子程序处理的数据,存放在一个事先约定的内存单元变主程序需要子程序处理的数据,存放在一个事先约定的内存单元变量中。量中。 33 .堆栈法.堆栈法 主程序将要转换的数据压入堆栈内,再调用子程序,子程序从堆栈主程序将要转换的数据压入堆栈内,再调用子程序,子程序从堆栈弹出数据,处理的结果也可压入堆栈返回给调用者。弹出数据,处理的结果也可压入堆栈返回给调用者。 举一个完整的包括主程序、子程序及调用的例子,来进行整体说明。举一个完整的包括主程序、子程序及调用的例子,来进行整体说明。例如:将内存单元 例如:将内存单元 X X 的一个一位十进制数据显示出来;将一位十进制数的一个一位十进制数据显示出来;将一位十进制数据转为对应的 据转为对应的 ASC ASC 码用子程序,主程序决定码用子程序,主程序决定 XX 单元的数据及显示这个单元的数据及显示这个
数。数。
2424
DATA SEGMENT X DB ? ;存放被显示的数 Y DB 0 ;存放此数转换好的 ASC 码 DATA ENDSCODE SEGMENT ASSUME DS : DATA , CS : CODESTART : MOV AX , DATA MOV DS , AX MOV X , 9D ;十进制数存入 X 单元 CALL DTOA ;调用子程序 DTOA 进行转换 MOV AH , 02H ;显示一个字符用 02H 号功能调用 MOV DL , Y ; Y 为要显示的数的 ASC 码 INT 21H EXIT : MOV AH , 4CH ;返回 DOS INT 21HCODE ENDS ;代码段结束
2525
DTOA PROC ;定义一个子程序,名为 DTOA
PUSH AX ; 子程序要用 AX ,保护 AX原来的数
MOV AH , X ;从 X取出参数
ADD AH , 30H ;转换 9D 的 ASC 为 39H
MOV Y , AH ; ASC 码存入 Y 单元
POP AX ;恢复 AX寄存器
RET ;返回调用者
DTOA ENDP ;子程序 DTOA 结束
END START ;汇编结束返回本章目录
2626
图图 4.1 4.1 数据变量定义的存储格式数据变量定义的存储格式
0001H
0002H
0003H
0004H
0005H
0006H
0007H
0008H
0009H
X
Y
Y+1
Y+2
Y+3
Y+4
Y+5
Z
内存变量 内存单元 内存偏移地址
-56H
80H
‘ ’?
‘ W‘
0
0
0
0
返回 4
2727
图图 4.2 4.2 单项分支程序结构图单项分支程序结构图
条件成立
条件不成立
JCC条件成立吗?
X为正数吗?
分支体指令序列:
求 X的绝对值
将绝对值存入 Y
返回 12 返回 13
2828
图图 4.3 4.3 多分支程序结构示意图多分支程序结构示意图
条件不成立
条件成立
条件成立
条件不成立
JCC条件 1
成立吗?
值<’0’吗?
JCC条件 2
成立吗?
值>’9’吗?
分支体 2指令序列:
将字符 X存入 D单元
分支体 1指令序列:
将数字字符转为数值
将数值存入 D单元
返回 14
2929
图图 4.4 4.4 条件控制控制循环示意图条件控制控制循环示意图
是
不是
不是
不是
是
取出当前 SI指向的单元的数据
SI指向内存BUF的第一个单元
当前单元的内容
是回车吗?
当前单元的内容
是正数吗?
正数个数+1
SI指向下一个内存单元
结束
返回 18 返回 19
3030
表表 4.1 80864.1 8086 汇编运算符汇编运算符
算术运算符 逻辑运算符 移位运算符 关系运算符
+ ( 加法 ) AND ( 与 ) SHL ( 逻辑左移 ) EQ ( 相等 )
- ( 减法 ) OR ( 或 ) SHR ( 逻辑右移 ) NE ( 不相等 )
* ( 乘法 ) NOT ( 非 ) SAL ( 算术左移 ) GT ( 大于 )
/ ( 除法 ) XOR (异或) SAR ( 算术右移 ) GE (大于等于)
MOD ( 取余 ) LT ( 小于 )
LE (小于等于)
返回 3