第5章 汇编语言程序设计

编程实现多字节加法,如S=3B74AC60F8H+20D59E36C1H


DATA SEGMENT
  DATA1 DB 0F8H,60H,0ACH,74H,3BH
  DATA2 DB 0C1H,36H,9EH,0D5H,20H
DATA ENDS
CODE SEGMENT
  ASSUME CS:CODE,DS:DATA
  START:
        MOV AX,DATA
        MOV DS,AX
        MOV CX,5                 ;设置循环次数
        MOV SI,0                 ;置位移量初值
        CLC                      ;清进位CF
  LOOPER:
        MOV AL,DATA2[SI]         ;取一个加数
        ADC DATA1[SI],AL         ;和一个被加数相加,ADC dst,src  (dst)<-(dst)+(src)+(CF)
        INC SI                   ;位移量加1
        DEC CX                   ;循环次数减1
        JNZ LOOPER               ;不等于/非零转移
        MOV AH,4CH
        INT 21H
CODE ENDS
  END START






计算三个字节十六进制数之和:3BH+74H+2CH=?

DATA SEGMENT
  BUF DB 3BH,74H,2CH
  SUM DB ?
DATA ENDS
CODE SEGMENT
  ASSUME CS:CODE,DS:DATA
  START:
        MOV AX,DATA
        MOV DS,AX
        MOV AL,BUF   ;取第一个数
        ADD AL,BUF+1 ;与第二个数相加
        ADD AL,BUF+2 ;与第三个数相加
        MOV SUM,AL   ;存和值
        MOV AH,4CH
        INT 21H
CODE ENDS
  END START


tab1为首地址存放了200个带符号数,要求将各数求绝对值后存入以tab2为首地址的内存区。

DATA SEGMENT
  TAB1 DB 0E7H,0E4H,06H,11H,03H,01H
  TAB2 DB 6 DUP(?)
DATA ENDS
CODE SEGMENT
  ASSUME CS:CODE,DS:DATA
  START:
        MOV AX,DATA
        MOV DS,AX
        MOV CX,6
        MOV SI,0
  NEXT1:
        MOV AL,TAB1[SI]
        ;比较指令的执行结果将影响状态标志位。例如,若两个被比较的内容相等,则(ZF)=1
        ;又如,假设被比较的两个无符号数中,前者小于后者(即不够减),则(CF)=1,等等。
        CMP AL,0
        ;JNS正转移
        JNS NEXT
        ;NEG求补指令
        NEG AL
  NEXT:
        MOV TAB2[SI],AL
        INC SI
        DEC CX
        ;不等于,非零转移
        JNZ NEXT1

        MOV AH,4CH
        INT 21H
CODE ENDS
  END START




在数据段从MYDATA开始的存储单元中分别存放了两个8位无符号数,试比较它们的大小,并将大者传送到MAX单元。可编程如下:

DATA SEGMENT
  MYDATA DW 12,15
  MAX DW ?
DATA ENDS
CODE SEGMENT
  ASSUME CS:CODE,DS:DATA
  START:
        MOV AX,DATA
        MOV DS,AX
        LEA BX,MYDATA      ;将MYDATA的偏移地址送BX
        MOV AX,[BX]        ;第一个无符号数送AL
        INC BX             ;BX指向第二个无符号数
        CMP AX,[BX]        ;两个数比较
        ;JNC disp8 (IP)<-(IP)+disp8 (CF)=0 不进位转移
        JNC DONE           ;若CF=0,则转DONE
        MOV AX,[BX]        ;否则,第二个无符号数送AL
  DONE:
        MOV MAX,AX
        MOV AH,4CH
        INT 21H
CODE ENDS
  END START



计算4609+3857=?

本例要求实现十进制多位数的加法,假设被加数的每一位数都以ASCII码形式存放在内存中,低位在前,高位在后。另外留出4个存储单元,以便存放相加所得的结果。

DATA SEGMENT
  STRING1 DB 39H,30H,36H,34H
  STRING2 DB 35H,37H,38H,33H
  SUM DB ?,?,?,?
DATA ENDS
CODE SEGMENT
  ASSUME CS:CODE,DS:DATA
  START:
        MOV AX,DATA
        MOV DS,AX
        LEA SI,STRING1       ;(SI)<-被加数地址指针
        LEA BX,STRING2       ;(BX)<-加数地址指针
        LEA DI,SUM           ;(DI)<-结果地址指针
        MOV CX,4             ;(CX)<-循环次数
        CLC                  ;清进位标志CF
  NEXT:
        MOV AL,[SI]          ;取一个字节被加数
        ADC AL,[BX]          ;与加数相加 ADC dst,src  (dst)<-(dst)+(src)+(CF)
        AAA                  ;ASCII码调整
        MOV [DI],AL          ;送存
        INC SI
        INC BX
        INC DI
        DEC CX
        JNZ NEXT             ;如不为零,转NEXT
        MOV AH,4CH
        INT 21H
CODE ENDS
  END START




        汇编语言源程序的组织结构

       汇编语言源程序采用的是分段结构,即一个汇编语言源程序由若干段组成(一般由数据段和代码段组成),每一个段以SEGMENT语句开始,以ENDS语句结束,整个程序的结尾是END语句。

        在代码段中下面的内容是不可缺少的:

  (1)  定义段(使用SEGMENT/ENDS语句定义)

  (2)  约定段寄存器和段的关系(即物理段和逻辑段的关系,使用一个或多个ASSUME语句实现)

  (3)  装填段寄存器(只装填数据型段寄存器)

  (4)  设置返回DOS的方法

例如:
MYDARA   SEGMENT				; 定义数据段起始语句
        … …					; 定义数据
MYDATA   ENDS					; 定义数据段终止语句
MYCODE   SEGMENT				; 定义代码段起始语句
	ASSUME  CS:MYCODE,DS:MYDATA	; 约定段寄存器和段的关系
	START: 
		MOV  AX,MYDATA		; 装填相应的段寄存器
		MOV  DS,AX			
                                   … …			; 完成所需功能的程序段
		MOV  AH,4CH			; 设置返回DOS
		INT    21H
MYCODE   ENDS				; 定义代码段终止语句
END   START					; 程序结束

    汇编语言语句的类型和格式

    1.语句分类

    ① 指令性语句:也称指令语句,指令系统的指令,汇编后产生目标代码。

    ② 指示性语句:也称伪指令语句,告诉汇编程序如何汇编,汇编后不产生目标代码。

    ③宏指令语句:自定义语句,由指令语句和伪指令语句组成的指令集合,不展开时不产生目标代码。

    2. 语句格式

   汇编语言是由一条条的语句组成的,其每条语句的格式如下:

[名字][语句前缀]助记符[操作数][;注释]

  其中带方括号的部分表示任选项,既可以有,也可以没有。

  (1)名字

   名字是语句的符号地址,对于指令语句,名字称为标号,其后必须加冒号;对于伪指令语句名字可以是变量名、段名、过程名等,其后不能加冒号:

eg:LOOPERMOV   AL, DATA2[SI]

       DATA1   DB 0F8H, 60H,  0ACH, 74H, 3BH

       DATA    SEGMENT

    名字一般都有三个属性:段属性、偏移属性和类型属性

① 段属性:表示名字所在段的起始地址(即段地址)。

② 偏移属性:表示名字所在段的起始地址到定义该名字的地址之间的字节数(即偏移量)。偏移量是一个16位无符号数。

③ 类型属性:表示该名字的数据或地址的类型。

   对于标号和过程名,类型属性有 NEAR FAR 两种,表示只能在段内被引用还是可以在其它段被引用;
  对于变量类型属性有 BYTE( 字节 ) WORD( ) DWORD( 双字 ) QWORD( 四字 ) TBYTE( 十字节 ) 等,表示数据区中存取操作对象的大小。
   对于段名只有段属性,表示段的起始地址(段地址),而没有偏移属性和类型属性。

  (2)助记符

  在指令语句中,表示该指令语句的操作码,在伪指令语句中称为定义符,它们指出其语句的功能。

  (3) 操作数

  操作数即为操作的对象。在指令语句中,可能有单操作数或双操作数,也可能无操作数或隐含操作数;而在伪指令中可能有更多个操作数。当操作数不止一个时,相互之间应该用逗号隔开。

    可以作为操作数的有:常数、寄存器、标号、变量和表达式等。

  1)常量:是指令在中出现的哪些固定值,可以分为数值常数和字符串常数两类。

  2) 寄存器:80868088CPU的寄存器可以作为指令的操作数。

  3) 变量:是存储器中某个数据区的名字,因此在指令中可以作为存储器操作数。

  4) 表达式:使用运算符把常数、寄存器、标号、变量等连接起来的运算式。

  ① 表达式分为数值表达式和地址表达式两种。

  ② 表达式中常用的运算符有以下几种:

    算术运算符:+、-、*、/和MOD(模除,即两个整数相除后取余数)等。

   逻辑运算符:ANDORXORNOT等。

   关系运算符:EQNELTGTLEGE等。

   分析运算符:SEGOFFSETTYPESIZE

LENGTH等。

   合成运算符:PTRTHISSHORT等。

   其它运算符: :、LOWHIGH

   (4)注释

   注释是对汇编语句的功能或汇编程序的说明。

mov ax, 4eq3   ;4eq3为假,(ax)<-0000h
mov ax, 4ne3   ;4ne3为真,(ax)<-0ffffh

mov ax, data
mov ax, seg data

type, length, size

汇编语言源程序的上机过程

上机环境


上机过程


    (1) 编辑程序

     DOS环境下用EDIT编辑器

     WINDOWS环境下用记事本

    (2)汇编源程序

    宏汇编程序 MASM.EXE 或小汇编程序ASM.EXE

汇编程序主要有以下功能:

    ① 检查源程序中语法错误,给出错误提示信息

    ② 产生目标文件(.OBJ)、列表文件(.LST)及交叉引用文件(.CRF

    ③ 展开宏指令

MASM宏汇编的提示信息及回答


   (3) 连接目标文件

   通过 LINK.EXE 程序实现

   ① 将多模块连接,产生一个.EXE文件

   ② 连接库文件(.LIB)及产生连接映象文件(.MAP

LINK的提示信息及回答


   (4) 运行程序

   当我们建立了可执行文件后,就可以直接在DOS下执行该程序。

   程序调试

    DEBUG是一种面向汇编语言的动态调试工具,共有19条命令。DEBUG提供了可以跟踪、测试程序的环境和条件,使编辑者能够对.EXE.COM文件的执行进行动态跟踪调试,能够较快地查找出文件的错误和检查程序的运行结果。

    还可以利用DEBUG直接编写一段小的汇编程序,并进行调试和运行。

   DEBUG 常用命令

   A[ 起始地址]↙  汇编并保存一段指令语句

   U[ 起始地址]↙  反汇编

   T[=起始地址]↙  单步执行(执行一条语句)

   R[ 寄存器]↙    显示或修改寄存器内容

   D[存储单元逻辑地址]↙  显示存储单元

                              80个字节/次)

   N[文件名]↙     定义文件

   L↙              装入文件

例如:

DATA  SEGMENT
        NUM  DB  82H,68H,88H
        SUM  DB  ?
DATA  ENDS
CODE  SEGMENT
        ASSUME  CS:CODE,DS:DATA
        START:	MOV   AX,DATA
			MOV   DS,AX
			MOV   BX,OFFSET  NUM
			MOV   AL,[BX]
			INC     BX
			ADD    AL,[BX]
			INC     BX
			ADD    AL,[BX]
			MOV   SUM,AL
			MOV   AH,4CH
			INT     21H
CODE  ENDS
	  END   START

添加堆栈段
stack segment stack stack
	buf db 20 dup(?)
stack ends

5.3 伪指令语句

宏汇编程序MASM提供了约几十种伪指令,其中有一些伪指令小汇编ASM不支持,例如宏处理伪指令等。根据伪指令的功能,大致可以分为以下几类:

⒈方式伪指令

.8086。汇编程序将在80868088方式下操作。

.386。汇编程序将在80386方式下操作。

  3.数据定义伪指令

  数据定义伪指令的一般格式为:

[变量名] 伪操作符 操作数[,操作数]

  ⑴ DB 定义变量的类型为BYTE,给变量分配字节或字节串操作数。

  DW 定义变量的类型为WORD,给变量分配字操作数。

 DD 定义变量的类型为DWORD,给变量分配双字操作数。

    除了常数、表达式和字符串外,问号也可以作为数据定义伪指令的操作数,此时仅给变量保留相应的存储单元,而不赋与变量某个确定的初值。

    当同样的操作数重复多次时,可用重复操作符DUP表示,其形式为:

    n DUP(初值[,初值])

可以嵌套使用:

    ARR DB 100 DUP(3 DUP(8), 6)

    : 画图说明下列伪指令所定义的数据在内存中的存放形式。

ARV1  DB 3+4,43H,-2
ARV2  DW 474FH,1,?
COUNT  EQU  2
ARV3  DB  2DUP(1,COUNT DUP(2))
ARV4  DD ARV3
ARV5  DB ‘AB’
ARV6  DW ‘AB’
解:假设此数据段的段地址为 1234H ,即 DS 1234H ,则有:


DATA DB 101,0F0H     ;存入65H,F0H
EXPR DB 2*8+7          ;存入17H
STR   DB 'WELCOME'   ;存入8个字符的ASCII码值
AB     DB 'AB'               ;存入41H、42H
BA     DW 'AB'              ;存入42H、41H
ABDD  DD 'AB'              ;存入42H、41H,00、00
OFFAB  DW  AB            ;存入变量AB的偏移地址
ADRS   DW STR,STR+3,STR+5     ;存入3个偏移地址
TOTAL  DD  DATA         ;先存DATA的偏移地址,再存段地址


下面列出几个错误的数据定义伪指令语句。

ERROR1: DW 99 ;变量名后有冒号

ERROR2: DB 25*90  ;字节型变量的操作数超过255

ERROR3:  DD '1234'   ;超过2个字符的字符串变量只能用DB定义

2. 符号定义伪指令

EQU(赋值伪指令)

  名字 EQU 表达式

⑵=(等号伪指令)

  名字=表达式

LABEL(类型定义伪指令)

  名字 LABEL 类型

注意:

EQU=类似,但EQU不能对同一符号重复定义。

  count = 100

  mov cx, count

  ……

  count = count – 20

  mov bx, count

    4.段定义伪指令

    段定义伪指令的用途是在汇编语言源程序中定义逻辑段,常用的段定义伪指令有SEGMENTENDSASSUME

    SEGMENTENDS 伪指令

 段名 SEGMENT [定位类型][组合类型][类名]

 段名 ENDS

    定位类型。定位类型给出实际段起点的类型。它有PAGE(页类型)、PARA(节类型)、WORD(字类型)、BYTE(字节类型)四种类型。其中PARA为默认值。

例:
DATA  SEGMENT
        NUM  DB  82H,68H,88H
        SUM  DB  ?
DATA  ENDS
STACK SEGMENT STACK STACK
        BUF DB 20 DUP(?)
STACK ENDS
CODE  SEGMENT BYTE
        ASSUME  CS:CODE,DS:DATA
        START:	MOV   AX,DATA
			MOV   DS,AX
               ……

			MOV   AH,4CH
			INT     21H
CODE  ENDS
	  END   START

BYTE:   从字节开始

WORD:从字边界开始

PARA,从节边界开始, 1=16B

PAGE:  从页边界开始, 1=256B

    组合类型。组合类型在多模块程序设计中表示该段和其它同名段间的组合连接方法。组合类型有PUBLICCOMMONATMEMORYSTACK等。

    ③类名。类名是程序员任选的一个字符串,使用时必须用单引号括起来。其作用是在连接时决定各逻辑段的装入顺序。

    ASSUME伪指令

   它是用来说明逻辑段和物理段关系的伪指令,即告诉汇编程序在指令执行期间内存的哪一段是数据段,哪一段是堆栈段,哪一段是代码段。

     ASSUME 段寄存器名:段名[,段寄存器名:段名,]

5.过程定义伪指令

    过程名  PROCNEAR/FAR

            ……

            RET

            ……

    过程名  ENDP

注意:

1. 一定有 RET 语句,可能不止一条
2. 过程的定义可以嵌套
3. NEAR 只能被本段调用, FAR 可以被其他段调用

6.模块定义与连接伪指令

END [ 标号 ]

表示源程序到此结束,指示汇编程序停止汇编。

PUBLIC

说明本模块中某些符号是公共的,能被其他模块访问

EXTRN

说明本模块中某些符号是外部的,由别的模块中定义的,定义时需加PUBLIC

5.2汇编语言和DOS操作系统的接口

1. 用户程序在存储器中的位置

2.用户程序的装入

完成以下操作:

¬ 确定内存可用部分

   以便存放要执行的 .exe 文件。

­ 建立程序段前缀 PSP

  Program  Segment Prefix

  ◢  程序段前缀大小100H

         256个字节。

    存放执行过程中的控制信息。

    PSP最开始的两个字节CD20

       是一条 INT20H指令。

® 装入可执行程序 .exe

DSEG  SEGMENT
        STRING1  DB  1,2,3,4,5
DSEG  ENDS
ESEG  SEGMENT
        STRING2  DB  ?
ESEG  ENDS
SSEG  SEGMENT  STACK  ‘STACK’
                  DW  10  DUP(?)
SSEG  ENDS
CSEG  SEGMENT
        ASSUME  CS:CSEG,DS:DSEG
        ASSUME  ES:ESEG,SS:SSEG
        START: MOV   AX,DSEG
	       MOV   DS,AX
               MOV   AX,ESEG
	       MOV   ES,AX
	
               LEA  SI,STRING1
               LEA  DI,STRING2
               MOV  CX,5
               CLD
               REP  MOVSB
	       MOV   AH,4CH
	       INT     21H
CSEG  ENDS
END   START

    3.返回DOS的方法

    执行用户程序后,若要返回 DOS状态,即在屏幕上出现DOS提示符,等待输入新的命令,应在用户程序的最后安排完成此功能的程序段。

   为了保证用户程序执行完后,能回到DOS,可使用如下两种方法:

   (1)非标准方法:调用INT21H4CH功能,例如:

     MOV  AH4CH

     INT  21H

  (2) 标准方法:借用PSP首单元的INT20H返回DOS

  这种方法较麻烦。由于执行INT 20H的前提是CS:IP必须指向PSP首单元,否则执行INT20H反而会造成死机,因此在.EXE文件汇编格式中,不能直接执行INT20H。用下列方法可使在需返回DOS时,CS:IP指向PSP首单元。

  ① 把主程序定义成一个远过程。即:

  过程名  PROC FAR                 

                  
 
   RET

  过程名  ENDP   

  在给DSES赋初值之前,用下列三条指令,把PSP首单元的逻辑地址压入堆栈,即

     PUSH  DS     PSP段地址压栈

     MOV   AX0   ;或用XORAX,AX指令

     PUSH  AX     PSP段首单元的偏移地址

                  ;压栈(偏移地址为0000H)

  采取了以上措施之后,程序在返回DOS的时候,执行一条RET指令即可返回DOS。因为这条RET指令是远过程中的RET指令,它将从栈顶弹出四个字节,即把PSP首单元的逻辑地址反弹到CS:IP之中,于是CPU就自动从PSP首单元取出INT20H,执行它返回DOS

例如:

DATA  SEGMENT
        NUM  DB  82H,68H,88H
        SUM  DB  ?
DATA  ENDS
CODE  SEGMENT
        MAIN  PROC  FAR
        ASSUME  CS:CODE,DS:DATA
        START:  PUSH  DS
                XOR   AX,AX
                PUSH  AX	
                MOV   AX,DATA
                MOV   DS,AX
	        LEA    BX, NUM
	        MOV   AL,[BX]
		INC     BX
		ADD    AL,[BX]
		INC     BX
		ADD    AL,[BX]
		MOV   SUM,AL                             
                     RET
         MAIN   ENDP
CODE  ENDS
             END   START

    4.数据的输入与输出(DOS功能调用)

    微型计算机系统为汇编用户提供了两个程序接口来使用计算机的硬件资源,一个是DOS功能调用,另一个是ROM中的BIOS(basicinput/output system) 功能调用。DOS功能调用和BIOS功能调用都是由一系列的服务子程序构成的,但调用与返回不是使用子程序调用指令CALL和返回指令RET,而是通过软中断指令INT n和中断返回指令IRET调用和返回的。

  软中断(INTn指令)可分为三部分:

   ① ROM BIOS中断,占用类型号为10H~1FH     

   DOS中断,占用类型号为20H~3FH。目前使用的有20H~27H2FH,其余类型号保留。

   ③ 自由中断,占用类型号为40H~FFH,可供系统或应用程序设置开发的中断处理程序用。

   1DOS中断及功能调用

   目前DOS常用的9类中断(20H~27H2FH)分为两种:

   DOS专用中断:INT22HINT23HINT24H,用户不能使用。

   DOS可调用中断:INT20HINT27H(程序退出)INT25HINT26H(磁盘RW中断)INT2FH(假脱机打印文件)INT21H(系统功能调用)

   2BIOS中断调用

  BIOS中断功能依功能分为两种,一种为系统服务程序,另一种为设备驱动程序。其中中断类型号为10H16H17H的是显示器、键盘和打印机的驱动子程序。

  ①键盘输入子程序:INT16H

   ②显示输出子程序:INT10H

  ③打印输出子程序:INT17H

  3)DOSBIOS功能调用方法

  对于所有的功能调用,使用时一般需要经过以下三个步骤:

  ① 子程序入口参数送相应寄存器。

  ②子程序编号(功能号)AH寄存器:

            MOV AH,功能号。

  ③发中断请求:

            INT n

(系统功能调用使用INT 21H指令)。

  4)系统功能调用

    系统功能调用是指INT21H中断。它是可供系统程序和应用程序调用的一个极其重要的中断,内含近百个已经标准化了的系统调用子功能。它是构成操作系统内核的主要成分。

    这里我们主要介绍他的几个成用的功能。如下表所示。


INT21H 常用功能介绍

   1)键盘输入(1#功能)

    功能: 键盘输入一个字符,将其ASCII码存放于AL,并在屏幕上显示该字符

    输入字符ASCII®AL

         MOV AH,01H

         INT 21H

   2)字符显示(2#功能)

    功能:在屏幕上显示任意单个字符

    待输出字符ASCII®DL  

         MOV  DL,A                   

         MOV AH,2

         INT 21H

   3)字符串显示(9#  功能)

    功能:屏幕上显示一串以$结尾的字符

           待显示字符串首单元地址®DSDX

  DATA  SEGMENT

        BUF  DB  HOW DO YOU DO?$

  DATA  ENDS

      CODE  SEGMENT

   

          MOV DX,OFFSET BUF

          MOV AH,9

          INT 21H

 

  CODE  ENDS

   4)字符串输入(10#功能)

    功能: 键盘输入一串字符存至存储区

    存储区起始单元地址(段地址:偏移量)®(DS:DX)      存储区特点:

    首字节为存储区最大长度M1~255);

    第二字节存放输入字符串的实际长度

    第三字节以后为用户输入内容(含结束标识回车的ASCII0DH

例   从键盘输入一串字符,个数小于50
     其程序设计方法是:
	DATA   SEGMENT
	      BUF  DB  50
		   DB  ?
		   DB  50  DUP(?)
	DATA	  ENDS
	CODE	  SEGMENT           
	ASSUME CS:CODE, DS:DATA
	START:……
		LEA   DX, BUF
		  MOV   AH,  10
		  INT   21H
                                 ……
            CODE  ENDS
		END START



5.4 宏指令及其使用

    1.宏指令、宏定义和宏调用

   宏指令是源程序中具有独立功能的一段程序代码。在汇编语言中,如果在源程序中需要多次使用同一个程序段,可以将这个程序段定义(宏定义)为一个宏指令,然后每次需要的时候,即可简单地用宏指令名来代替(称为宏调用),从而避免了重复书写,使源程序更加简洁、易读。

    宏定义由MASM宏汇编程序提供的伪指令实现。

   1. 宏定义

       宏指令名 MACRO[形式参数]

                 ENDM

   2. 宏调用

       宏指令名 [实际参数]

   这就是说,只要在源程序中写上已定义过的宏指令名就算是调用该宏指令了。

   3. 宏展开

    具有宏调用的源程序被汇编时,每个宏调用将被MASM进行宏展开。

    宏展开实际上是用宏定义时设计的宏体去代替相应的宏指令,并用实际参数一一取代形式参数。

    由此可见,使用宏的过程共有三步:首先进行宏定义;然后可以进行宏调用;最后,汇编时由MASM进行宏展开。

    [] 若源程序中多处需要将ALCL寄存器中的两位压缩型的BCD数相加,并将和送回CL寄存器,则可象下述这样定义宏指令,然后在需要的地方进行调用。

    DECADD  MACRO

               ADD AL,CL

               DAA

               MOV CL,AL

            ENDM

显而易见,这是一个无形式参数的宏定义。

    如果对分别存放在任意8位寄存器或存储单元中的两个压缩型的BCD数进行加法运算,则可将上例宏定义改写为

    DECADD1 MACRO OPR1,OPR2

               MOV AL,OPR1

               ADD AL,OPR2

               DAA

               MOV OPR1,AL

            ENDM

    例如有以下宏调用,如何展开呢?

  DECADD1  DL, BUFFER

  DECADD1  AREA1, AREA2

则汇编时进行宏展开,得到以下指令:

         DECADD1  DL, BUFFER

                + MOV  AL, DL

                + ADD  AL, BUFFER

                + DAA

                + MOV  DL, AL

         DECADD1  AREA1, AREA2

                + MOV  AL, AREA1

                + ADD  AL, AREA2

                + DAA

                + MOV  AREA1, AL

    2.宏指令与子程序(过程)

   在汇编语言程序设计中,宏指令和子程序都给设计者提供了很大方便。他们都是可被程序多次调用的程序段,并且调用前必须由设计者根据需要按一定格式进行定义。然而,宏指令和子程序由于定义方法和其格式不同,因此,使用中有许多不同之处,主要是空间和时间的差异。

    子程序由CALL指令调用,由RET指令返回,所以汇编后子程序的机器码只占有一个程序段,不管调用多少次均如此,较为节约内存。宏指令在每次宏调用处宏展开时,宏体都要占一个程序段,调用次数愈多,占用内存愈多。因此从内存空间开销来说,子程序优于宏指令。

    从程序的执行时间来分析,每调用一次子程序都要保护和恢复返回地址(断点)及寄存器内容(现场)等,要消耗较多的时间。宏指令调用时不需要这个过程,执行时间较短。因此,从执行时间来分析,宏指令又优于子程序。

    综上所述,当某一需多次访问的程序段较长,访问次数又不是太多时,选用子程序结构较好。当某一需多次访问的程序段较短,访问次数又很频繁时,选用宏指令结构显然要更好些。












































  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值