⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 汇009.txt

📁 会变语言实现的一些程序
💻 TXT
📖 第 1 页 / 共 3 页
字号:
ABS MACRO word1 
CMP word1, 0 
JGE next 
NEG word1 
next: 
 ENDM 

假设对宏ABS有以下两次引用,点击它们将会显示汇编程序对它们进行宏扩展后所得到程序片段:

    ABS  BX 
  1     CMP BX, 0
  1     JGE  next
  1     NEG BX
  1 next: 
 
    ABS  AL 
  1     CMP AL, 0
  1     JGE  next
  1     NEG AL
  1 next: 

在上述程序片段中,显然标号next定义了二次,所以,汇编程序将显示“标号重复定义”的错误信息。为了避免这种情况的发生,我们需要用下面的方法来定义该宏。

方法2:
 
 ABS MACRO word1 
  LOCAL next 
CMP word1, 0 
JGE next 
NEG word1 
next: 
 ENDM 

假设对宏ABS有以下两次引用,点击它们将会显示汇编程序对它们进行宏扩展时所得到程序片段:

    ABS  BX 
  1      CMP BX, 0
  1      JGE  ??0000
  1      NEG BX
  1 ??0000: 
 
    ABS  AL 
  1      CMP AL, 0
  1      JGE ??0001
  1      NEG AL
  1 ??0001: 

在上述程序片段中,宏体内部的局部标号next分别用符号??0000和??0001来对应它的二次引用。因此,汇编程序不会再显示“标号重复定义”的错误信息。

伪指令LOCAL在子程序中也可起作用(参见7.5.10节),但它的作用与宏定义的作用是不同的,有关该伪指令在子程序的宏定义中功能的主要差异如表9.1所列。

表9.1 伪指令LOCAL在子程序和宏中的比较

 在子程序中 在宏定义中 
语句的位置 在所有指令之前 在所有指令之前 
伪指令的作用 说明局部变量 说明局部标号 
伪指令的格式 可用一条伪指令来说明多个局部变量,也可连续用多条伪指令来说明 可用一条伪指令来说明多个局部标号,也可连续用多条伪指令来说明 
调用或引用 子程序的不同调用,其局部变量名保存不变 在每次宏引用的扩展时,将会自动产生出一个唯一的局部标号 
9.4 重复汇编伪指令
在编写源程序时,有时会出现连续相同或相似的语句(组)。当出现这种情况时,可利用重复伪指令来重复语句,从而达到简化程序的目的。

重复汇编伪指令所定义的重复块是宏的一种特殊形式,也是由伪指令ENDM来结束重复块。用重复汇编伪指令定义的重复块也可带有参数,并在汇编过程中参数被实参代替,但重复块不会被命名,不能在程序的其它地方引用。

9.4.1 伪指令REPT
伪指令REPT的作用是把一组语句重复指定的次数,该重复次数由伪指令后面的数值表达式来确定。其一般使用格式如下:

 REPT 数值表达式 
重复的语句组 
ENDM 

例9.8 定义100个初值为32的字节单元,该存储单元的起始符号地址为Table。

解:  
方法1:用伪指令REPT来实现
 左边重复块的汇编结果如下:  
 Table LABEL TYPE  Table LABEL TYPE
 
REPT  100  DB 32
 
DB 32  …
 
ENDM  DB 32    ;上述字节定义重复100次
 

方法2:用重复操作符DUP来实现

Table DB 100 DUP(32)

从上例来看,用伪指令REPT重复定义的存储单元可以用重复操作符DUP来代替,其实前者的功能会更灵活、更强大。

例9.9 定义100个初值分别为1,2,…,100的字节单元,该存储单元的起始符号地址为Table。

解:  
 Table LABEL TYPE  左边重复块的汇编结果相当于:  
 COUNT = 1  Table LABEL TYPE  
REPT  100   DB 1  
DB COUNT  DB 2  
COUNT = COUNT + 1  …  
ENDM  DB 100  

上面定义了100个字节,其初值为1,2,…,100。本例好象不能用重复操作符DUP来说明字节存储单元。

例9.10 计算1+2+…+1000,并把其值存入寄存器AX。

解:  
方法1:用伪指令REPT来实现
 左边重复块的汇编结果与下面程序段相一致:  
 …  …  
MOV AX, 0  MOV AX, 0  
COUNT = 1  ADD AX, 1  
REPT  1000  ADD AX, 2  
ADD AX, COUNT  …  
COUNT = COUNT + 1  ADD AX, 1000  ;把AX从1累加到1000  
ENDM  …  
…  虽然上面这些语句的执行能完成本例所指定的功能,但它是用1000条加法指令来直接计算的,这1000条指令无疑会大大增加目标代码的长度。
 
方法2:用循环指令LOOP来实现
 
MOV AX, 0 
MOV CX, 1000 
again: ADD AX, CX 
LOOP again 

由例9.10,不难看出:伪指令REPT与循环指令起作用的时期和方式是截然不同的。它们之间的主要差异如表9.1所列。

表9.1 伪指令REPT与循环指令LOOP之间的主要差异

  伪指令REPT
 循环指令LOOP
 
起作用的时期
 汇编程序把源文件翻译成目标文件时期
 程序的执行时期
 
起作用的方式
 把被重复的指令(组)直接重复写入目标文件
 通过反复执行同一指令(组)来实现重复
 
重复次数对目标文件的影响
 由于重复次数决定着被重复指令(组)写入目标文件的次数,所以,改变重复次数一定会改变目标文件的字节数
 由于重复的指令数与重复次数无关,所以,改变重复次数不会改变目标文件的字节数
 9.4 重复汇编伪指令
在编写源程序时,有时会出现连续相同或相似的语句(组)。当出现这种情况时,可利用重复伪指令来重复语句,从而达到简化程序的目的。

重复汇编伪指令所定义的重复块是宏的一种特殊形式,也是由伪指令ENDM来结束重复块。用重复汇编伪指令定义的重复块也可带有参数,并在汇编过程中参数被实参代替,但重复块不会被命名,不能在程序的其它地方引用。

9.4.1 伪指令REPT
伪指令REPT的作用是把一组语句重复指定的次数,该重复次数由伪指令后面的数值表达式来确定。其一般使用格式如下:

 REPT 数值表达式 
重复的语句组 
ENDM 

例9.8 定义100个初值为32的字节单元,该存储单元的起始符号地址为Table。

解:  
方法1:用伪指令REPT来实现
 左边重复块的汇编结果如下:  
 Table LABEL TYPE  Table LABEL TYPE
 
REPT  100  DB 32
 
DB 32  …
 
ENDM  DB 32    ;上述字节定义重复100次
 

方法2:用重复操作符DUP来实现

Table DB 100 DUP(32)

从上例来看,用伪指令REPT重复定义的存储单元可以用重复操作符DUP来代替,其实前者的功能会更灵活、更强大。

例9.9 定义100个初值分别为1,2,…,100的字节单元,该存储单元的起始符号地址为Table。

解:  
 Table LABEL TYPE  左边重复块的汇编结果相当于:  
 COUNT = 1  Table LABEL TYPE  
REPT  100   DB 1  
DB COUNT  DB 2  
COUNT = COUNT + 1  …  
ENDM  DB 100  

上面定义了100个字节,其初值为1,2,…,100。本例好象不能用重复操作符DUP来说明字节存储单元。

例9.10 计算1+2+…+1000,并把其值存入寄存器AX。

解:  
方法1:用伪指令REPT来实现
 左边重复块的汇编结果与下面程序段相一致:  
 …  …  
MOV AX, 0  MOV AX, 0  
COUNT = 1  ADD AX, 1  
REPT  1000  ADD AX, 2  
ADD AX, COUNT  …  
COUNT = COUNT + 1  ADD AX, 1000  ;把AX从1累加到1000  
ENDM  …  
…  虽然上面这些语句的执行能完成本例所指定的功能,但它是用1000条加法指令来直接计算的,这1000条指令无疑会大大增加目标代码的长度。
 
方法2:用循环指令LOOP来实现
 
MOV AX, 0 
MOV CX, 1000 
again: ADD AX, CX 
LOOP again 

由例9.10,不难看出:伪指令REPT与循环指令起作用的时期和方式是截然不同的。它们之间的主要差异如表9.1所列。

表9.1 伪指令REPT与循环指令LOOP之间的主要差异

  伪指令REPT
 循环指令LOOP
 
起作用的时期
 汇编程序把源文件翻译成目标文件时期
 程序的执行时期
 
起作用的方式
 把被重复的指令(组)直接重复写入目标文件
 通过反复执行同一指令(组)来实现重复
 
重复次数对目标文件的影响
 由于重复次数决定着被重复指令(组)写入目标文件的次数,所以,改变重复次数一定会改变目标文件的字节数
 由于重复的指令数与重复次数无关,所以,改变重复次数不会改变目标文件的字节数
 
9.4.2 伪指令IRP
伪指令IRP的作用是用每个参数创建一组语句,其重复次数由伪指令后面参数表中参数的个数来确定。其一般使用格式如下:

 IRP 形式参数, <实参1, 实参2, ……, 实参n> 
重复的语句组 
ENDM 

例9.11 把16位通用寄存器之值相加,并把结果存入寄存器AX。

解:由于16位通用寄存器名是一些不同的符号,不能用计数的方法来依次访问它们,所以,我们需要用伪指令IRP来实现。

 IRP REG, <BX, CX, DX, SP, BP, SI, DI> 
ADD  AX, REG 
ENDM 

9.4.3 伪指令IRPC
伪指令IRPC的作用与IRP相似,其实参表是一个字符串,并对字符串中的每个字符创建一组语句,所以,其重复次数是由该字符串中的字符数来确定。其一般使用格式如下:

 IRPC 形式参数, 字符串 
重复的语句组 
ENDM 

例9.12 定义10个字节存储单元,保存数字0~9的平方数。

解:

 IRPC X, 0123456789 
DB  X*X 
ENDM 

例9.13 把16位数据寄存器之值相加,并把结果存入寄存器DI。

解:由于16位数据寄存器是AX、BX、CX和DX,它们的名称中只有第一个字符不同,所以,可以用伪指令IRPC来实现。

 XOR DI, DI 
IRPC REG, ABCD 
ADD  DI, REG&X            ;符号&是连接运算符 
ENDM 
9.5 条件汇编伪指令
条件汇编伪指令是告诉汇编程序:根据某种条件确定一组程序段是否加入到目标程序中。使用条件汇编伪指令的主要目的是:同一个源程序能根据不同的汇编条件生成不同功能的目标程序,增强宏定义的使用范围。

条件汇编伪指令与高级语言(如:C/C++)的条件编译语句在书写形式上相似,在所起作用方面是完全一致的。

9.5.1 条件汇编伪指令的功能
条件汇编伪指令的一般格式如下:

 IFnnnn 条件表达式 
语句组1 
[ELSE 
 语句组2] 
ENDIF 

其中:IFnnnn是表9.2中的伪指令,“[…]”内的语句是可选的。

条件汇编伪指令是在汇编程序把源程序转换成目标程序时起作用,其一般含义是:若条件汇编伪指令后面的“条件表达式”为真,那么,语句组1将被汇编;否则,语句组2将被汇编(如果含有ELSE伪指令)。

语句组1或语句组2内还可以包有条件汇编伪指令,这时,就形成了嵌套的条件汇编伪指令。一个嵌套的ELSE伪指令总是与最近的、还没有与其它ELSE伪指令相比配的IFnnnn伪指令相比配。

每条条件汇编伪指令的具体含义如表9.3所示。

表9.3 条件汇编伪指令及其功能一览表

伪指令
 含义
 
IF exp
 若数值表达式exp的值不为0,则语句组1包含在目标文件中
 
IFE exp
 若数值表达式exp的值为0,则语句组1包含在目标文件中
 
IFDEF label
 若标号label有定义或被说明为EXTRN,则语句组1包含在目标文件中
 
IFNDEF label
 若标号label没有定义,也没被说明为EXTRN,则语句组1包含在目标文件中
 
IFB <参数>
 在宏引用时,若该形参没有相应的实参相对应,则语句组1包含在目标文件中
 
IFNB <参数>
 在宏引用时,若该形参没有相应的实参相对应,则语句组1包含在目标文件中
 
IFIDN <参数1>, <参数2>
 若参数1=参数2,则语句组1包含在目标文件中
 
IFDIF <参数1>, <参数2>
 若参数1≠参数2,则语句组1包含在目标文件中
 
IF1
 若汇编程序在第一遍扫描时,则语句组1包含在目标文件中
 
IF2
 若汇编程序在第二遍扫描时,则语句组1包含在目标文件中
 

9.5.2 条件汇编伪指令的举例
例9.14 编写一个可用DOS或BIOS功能调用输入字符的宏定义。

解: 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -