[汇编]伪指令(二)

来源:互联网 发布:国税局在线发票软件 编辑:程序博客网 时间:2024/06/05 11:38
[汇编]伪指令(二)

数据定义及存储器分配伪指令

  80x86提供了各种数据及存储器分配伪指令,这些伪指令在汇编程序对源程序进行汇编期间,由汇编程序完成数据类型定义及存储器分配等功能。

  数据定义及存储器分配伪指令的格式是:

 [变量] 助记符 操作数[, …,操作数] [ ;注释]

  下面介绍ORG伪指令以及常用的数据定义伪指令。

  ORG(origin)
  ORG伪指令用来表示起始的偏移地址,紧接着ORG的数值就是偏移地址的起始值。ORG伪操作常用在数据段指定数据的存储地址,有时也用来指定代码段的起始地址。

  DB(define byte)
  DB伪指令用来定义字节,对其后的每个数据都存储在一个字节中。DB能定义十进制数、二进制数、十六进制数和ASCII字符,二进制数和十六进制数要分别用"B"和"H"表示,ASCII字符用单引号(' ')括起来。DB还是唯一能定义字符串的伪操作,串中的每个字符占用一个字节。

  DW(define word)
  DW伪指令用来定义字,对其后的每个数据分配2个字节(1个字),数据的低8位存储在低字节地址中,高8位存储在高字节地址中,如下例中的变量DATA8的数据存储在0070字地址中,其中0070字节存储0BAH,0071字节存储03H。DW还可存储变量或标号的偏移地址。见左面DW伪指令的例子。

  DD(define doubleword)
  DD伪指令用来定义双字,对其后的每个数据分配4个字节(2个字)。该伪指令同样将数据转换为十六进制,并根据低地址存储低字节,高地址存储高字节的规则来存放数据。如下例DATA15的存储情况是:00A8:0F2H,00A9H:57H,00AAH:2AH,00ABH:5CH。
  用DD存入地址时,第一个字为偏移地址,第二个字为段地址。

  DQ(define quadword)
  
DQ伪指令用来定义4字,即64位字长的数据,DQ之后的每个数据占用8个字节(4个字)。

  DT(define ten bytes)
  DT伪指令用来为压缩的BCD数据分配存储单元,它虽然可以分配10个字节(5个字),但最多只能输入18个数字,要注意的是,数据后面不需要加"H"。左面是DQ和DT的例子。

  DUP(duplicate)
  DUP伪指令可以按照给定的次数来复制某个(某些)操作数,它可以避免多次键入同样一个数据。例如,把6个FFH存入相继字节中,可以用下面两种方法,显然用DUP的方法更简便些。

 存入6字节的FFH
DATA20 DB 0FFH 0FFH 0FFH 0FFH 0FFH 0FFH;
DATA21 DB 6 DUP(0FFH)  

  DUP操作一般用来保留数据区,如用数据定义伪指令"DB 64 DUP(?)"可为堆栈段保留64个字节单元。DUP还可以嵌套,其用法见左例。

  PTR属性操作符
  PTR指定操作数的类型属性,它优先于隐含的类型属性。其格式为:

  类型 PTR 变量[ ± 常数表达式]

  其中类型可以是BYTE、WORD、DWORD、FWORD、QWORD或TBYTE,这样变量的类型就可以指定了。

  LABEL伪指令
  LABEL可以使同一个变量具有不同的类型属性。其格式为:

  变量名 LABEL 类型
或 标号  LABEL 类型

  其中变量的数据类型可以是BYTE,WORD,DWORD,标号的代码类型可以是NEAR或FAR。
  数据定义及存储器分配伪指令格式中的"变量"是操作数的符号地址,它是可有可无的,它的作用与指令语句前的标号相同,区别是变量后面不加冒号。如果语句中有变量,那么汇编程序将操作数的第一个字节的偏移地址赋于这个变量。

  "注释"字段用来说明该伪指令的功能,它也不是必须有的。
  "助记符"字段说明所用伪指令的助记符。

  DB(define byte)
 
 请看下面数据定义的例子,注意DB定义的每个数据的存储情况,左边第一列是汇编程序为数据分配的字节地址,第二列是相应地址中存储的数据或ASCII字符(均用十六进制表示)。变量DATA7定义了3个数据和一个字符串,每个数据或串用","分开,它们分别存储在偏移地址002E开始的6个字节单元中。

           ; DB 例子的列表文件
 0000  19       DATA1  DB  25        ; 十进制数
 0001  89       DATA2  DB  10001001B     ; 二进制数
 0002  12       DATA3  DB  12H        ; 十六进制数
 0010              ORG 0010H       ; 指定偏移地址为10h
 0010  32 35 39 31   DATA4  DB  '2591'      ; ASCII码数
 0018              ORG 0018H       ; 指定偏移地址为18h
 0018  00       DATA5  DB  ?        ; 保留一个字节
 0020              ORG 0020H       ; 指定偏移地址为20h
 0020  4D 79 20 6E 61 6D DATA6  DB  'My name is Joe' ; ASCII码字符
     65 20 69 73 20 4A
     6F 65
 002E  0A 10 02 31 30 42 DATA7  DB  10,10H,10B,'10B' ; 不同的数据类型

  DW(define word)

表 

           ; DW 伪指令例子的列表文件
 0070               0RG 70H        ;指定起始地址
 0070  03BA      DATA8  DW  954        ; 十进制数
 0072  0954      DATA9  DW  100101010100B   ; binary
 0074  253F      DATA10 DW  253FH       ; 十六进制数
 0076  FFFB      DATA11 DW  -5        ; 负数
 0080              ORG 80H
 0080  0009 FFFF 0007 000C DATA12 DW 9,-1,7,0CH,00100000B,100,'HI'
     0020 0064 4849                ; 各种类型数据 
  DD(define doubleword)



           ; DD例子的列表文件
 00A0                ORG 00A0H        ; 指定起始地址
 00A0  FF030000      DATA13 DD  1023          ; 十进制数
 00A4  5C960800      DATA14 DD  10001001011001011100B ; 二进制数
 00A8  F2572A5C      DATA15 DD  5C2A57F2H        ; 十六进制数
 00AC  23000000 89470300 DATA16 DD 23H,34789H,65533     ; 各种数据
     FDFF0000  
  DT(define ten bytes)


           ; DQ、DT例子的列表文件
 00C0               ORG 00C0H
 00C0  C223450000000000 DATA17 DQ  4523C2H     ; 十六进制数
 00C8  4948000000000000 DATA18 DQ  'HI'       ; ASCII字符
 00D0  0000000000000000 DATA19 DQ  ?        ; 分配8个字节单元
 00E0               ORG 00E0H
 00E0  2998564379860000 DATA20 DT  867943569829   ; 压缩的BCD数
     0000
 00EA  0000000000000000 DATA21 DT  ?        ; 分配10个字节单元
     0000 
  DUP(duplicate)


           ; DUP例子的列表文件
 0100               ORG 0100H      ; 数据区的起始地址
 0100  0020[       DATA22 DB  32 DUP(?)    ; 保留32字节
      ??
            ]
 0120               ORG 0120H
 0120  0005[       DATA23 DB  5 DUP(2 DUP(99)); 存入10个字节的99
         0002[
             63
            ]
             ]
 012A  0008[       ATA24  DW  8 DUP(?)     ; 保留8个字节
        ????
            ] 
  对数据定义伪指令前面的变量还要注意它的类型属性问题。变量表示该伪指令中的第一个数据项的偏移地址,此外,它还具有一个类型属性,用来表示该语句中的每一个数据项的长度(以字节为单位表示),因此DB伪指令的类型属性为1,DW为2,DD为4,DQ为8,DT为10。变量表达式的属性和变量是相同的。汇编程序可以用这种隐含的类型属性来确定某些指令是字指令还是字节指令。

  下例中变量OPER1为字节类型属性,OPER2为字类型属性,所以第一条MOV指令应为字节指令,第二条MOV指令应为字指令。而第三条指令的变量表达式OPER1+1为字节类型属性,AX却为字寄存器,第四条指令的OPER2为字类型属性,AL为字节寄存器,因此,汇编程序将指示这两条MOV指令出错:"类型不匹配"。

   OPER1   DB ?, ?
   OPER2   DW ?, ?
     .
     .
     .
    
        MOV  OPER1, 0   ;字节指令
        MOV  OPER2, 0   ;字指令
        MOV  AX, OPER1+1 ;错误指令:类型不匹配
        MOV  AL, OPER2  ;错误指令:类型不匹配

  PTR属性操作符
  下例中的两条MOV指令把OPER1+1的类型属性指定为字,把OPER2的类型属性指定为字节,这样指令中两个操作数的属性就一致了,汇编时就不会出错了。

   OPER1   DB ?, ?
   OPER2   DW ?, ?
     .
     .
     .

        MOV  AX, WORD PTR OPER1+1
        MOV  AL, BYTE PTR OPER2

  LABEL伪指令

  例如:
    BYTE_ARRAY   LABEL BYTE
    WORD_ARRAY   DW   50 DUP (?)

  在50个字数组中的第一个字节的地址赋予两个不同类型的变量名:字节类型的变量BYTE_ARRAY和字类型变量WORD_ARRAY。

  在程序中访问数组单元时,要按指令类型来选择变量,如下面两条指令:

    MOV    WORD_ARRAY + 2,0   ; 字指令,
                    ; 把该数组的第3个和第4个字节置0
    MOV    BYTE_ARRAY + 2,0   ; 字节指令,
                    ; 把该数组的第3个字节置0

表达式赋值伪操作EQU

  EQU
是一个赋值伪操作(伪指令),它给一个数据标号赋于一个常数值,但这个常数不占用存储单元。当这个数据标号出现在程序中时,汇编程序即用它的常数值代替数据标号。EQU可以在数据段之外使用,甚至可用在代码段中间。

  = 伪操作

  赋值伪操作"="的作用与EQU类似。它们之间的区别是,EQU伪操作中的标号名是不允许重复定义的,而=伪操作是允许重复定义的。

  使用EQU操作的优点可从下面的例子中看出:

   COUNT   EQU  25
   COUNTER  DB   COUNT
     MOV  AL,  COUNT

  假定在数据段和代码段中要多次使用一个数据(如25),那么在编程时凡是用到25的地方都可用数据标号COUNT来表示。如果程序想修改这个数据,那么只需修改EQU的赋值,而无须修改程序中其它部分,如COUNTER和MOV语句就不必修改。
  
 
 EQU还可给表达式赋予一个名字,EQU的用法举例如下:

  DATA    EQU HEIGHT + 12   ; 地址表达式赋以符号名
  ALPHA    EQU 7        ; 常数赋以符号名
  BETA    EQU ALPHA-2     ; 把7-2=5赋以符号名BETA
  ADDR    EQU VAR + BETA    ; VAR+5赋以符号名ADDR。
  B      EQU [BP + 8]     ; 变址引用赋以符号名 B
  P8     EQU DS:[BP + 8]   ; 加段前缀的变址引用赋以符号名P8

  注意:在EQU语句的表达式中,如果有变量或标号的表达式,则在该语句前应该先给出它们的定义。如上例,ALPHA必须在BETA之前定义,否则汇编程序将指示出错。

  例如,  TMP  EQU 5
       TMP  EQU TMP+1 则是错误语句,因为TMP已赋值为5,就不能再把它定义为其它数值。
     而 TMP = 5
       TMP = TMP+1 则是允许使用的,因为=伪操作允许重复定义。第一个语句TMP的值为5,第二个语句TMP的值就为6了。

地址计数器与对准伪指令

  1.地址计数器$


  在汇编程序对源程序汇编的过程中,使用地址计数器来保存当前正在汇编的指令的地址。地址计数器的值在汇编语言中可用$来表示。

  当$用在伪指令的参数字段时,它所表示的是地址计数器的当前值

  2.EVEN伪指令

  EVEN伪指令使下一个变量或指令开始于偶数字节地址。

  3. ALIGN伪指令

  ALIGN伪指令使它后面的数据或指令从2的整数倍地址开始。其格式为:

    ALIGN 2n (n为任意整数)

 1.地址计数器$ 

  汇编语言允许用户直接用$来引用地址计数器的值,例如指令:

     JMP   $+ 6

  它的转向地址是JMP指令的首地址加上6。当$用在指令中时,它表示本条指令的第一个字节的地址。在这里,$+ 6必须是另一条指令的首地址。否则,汇编程序将指示出错信息。

  当$用在伪指令的参数字段时,则和它用在指令中的情况不同,它所表示的是地址计数器的当前值。例如指令:

    ARRAY   DW 1, 2, $+ 4, 3, 4, $+ 4
  
  假设汇编时ARRAY 分配的偏移地址为0074H,则汇编后,$+ 4所在的两个字单元:
  (ARRAY+4)=0078+4=007CH
  (ARRAY+0A)=007E+4=0082H

  应当注意,ARRAY数组中的两个$+ 4得到的结果是不同的,这是由于$的值是在不断变化的缘故。当在指令中用到$时,它只代表该指令的首地址,而与$本身所在的字节无关。

 2.EVEN伪指令

  例如:
    DATA_SEG  SEGMENT
          BYTE_DAT  DB ?
    EVEN
          WORD_DAT  DW 100 DUP (?)
    DATA_SEG  ENDS

  一个字的地址最好从偶地址开始,所以对于字数组为了保证它从偶地址开始,可以在DW定义之前用EVEN伪指令来达到这一目的。

 3. ALIGN伪指令

  例如:
.    
     ALIGN 4
     ARRAY DD 100 DUP (?)
     
  ALIGN伪指令保证了双字数组ARRAY地址边界从4的倍数开始。

  ALIGN伪指令是将当前偏移地址指针指向2的乘方的整数倍的地址,如果源地址指针以指向2的乘方的整数倍的地址,则不作调整;否则将指针加以一个数,使地址指针指向下一个2的乘方的整数倍的地址。

  当然,ALIGN 2和EVEN是等价的。

基数控制伪指令

  .RADIX
伪指令

  .RADIX可以把默认的基数改变为2~16范围内的任何基数。其格式如下:
     .RADIX 基数值

  其中基数值用十进制数来表示。

  例如:
    MOV   BX, 0FFH    ;16进制数标记为H
    MOV   BL, 10000101B ;二进制数标记为B
    MOV   BX, 178    ;10进制为默认的基数,可无标记
    .RADIX 16       ;以下程序默认16进制数
    MOV   BX, 0FF    ;16进制为默认的基数,可无标记
    MOV   BX, 178D    ;10进制数应加标记D

  应当注意,在用 .RADIX 16把基数定为十六进制后,十进制数后面都应跟字母D。在这种情况下,如果某个十六进制数的末字符为D,则应在其后跟字母H,以免与十进制数发生混淆。

0 0
原创粉丝点击