汇编伪指令 

段定义伪指令
 
  段定义伪指令是表示一个段开始和结束的命令,80x86有两种段定义的方式:完整段定义和简化段定义,分别使用不同的段定义伪指令来表示各种段。

 
1 完整的段定义伪指令

  完整段定义伪指令的格式如下:

  段名 SEGMENT
    .
    .
    .
  段名 ENDS

  段名由用户命名。对于数据段、附加段和堆栈段来说,段内一般是存储单元的定义、分配等伪指令语句;对于代码段中则主要是指令及伪指令语句。

  定义了段还必须说明哪个段是代码段,哪个段是数据段。ASSUME伪指令就是建立段和段寄存器关系的伪指令,其格式为:

  ASSUME 段寄存器名: 段名,…

  段寄存器名必须是CS、DS、ES和SS中的一个,而段名必须是由SEGMENT定义的段名。

 
·定位类型:说明段的起始边界值(物理地址)。
  
  ·组合类型:说明程序连接时的段组合方法。

  ·类别:在单引号中给出连接时组成段组的类型名。连接程序可把相同类别的段的位置靠在一起。
 
 例4.1

  ; * * * * * * * * * * * * * * * * * * * * * * *
  data_seg1 segment        ; 定义数据段
            .
            .
            .
  data_seg1 ends
  ; * * * * * * * * * * * * * * * * * * * * * * *
  data_seg2 segment        ; 定义附加段
            .
            .
            .
  data_seg2 ends
  ; * * * * * * * * * * * * * * * * * * * * * * *
  code_seg segment         ; 定义代码段

   assume cs:code_seg, ds:data_seg1, es:data_seg2

  start:              ; 程序执行的起始地址
  ; set DS register to current data segment
     mov   ax, data_seg1   ; 数据段地址
     mov   ds, ax       ; 存入DS寄存器

  ; set ES register to current extra segment
     mov   ax, data_seg2   ; 附加段地址
     mov   es, ax       ; 存入ES寄存器
            .
            .
            .
   code_seg ends          ; 代码段结束
  ; * * * * * * * * * * * * * * * * * * * * * * * * * *
     end   start

  由于ASSUME伪指令只是指定某个段分配给哪一个段寄存器,它并不能把段地址装入段寄存器中,所以在代码段中,还必须把段地址装入相应的段寄存器中:

  MOV    AX,DATA_SEG1    ; 数据段地址
  MOV    DS,AX        ; 存入DS寄存器
  MOV    AX,DATA_SEG2    ; 附加段地址
  MOV    ES,AX        ; 存入ES寄存器

  如果程序中还定义了堆栈段STACK_SEG,也需要把段地址装入SS中:
  MOV    AX,STACK_SEG    ; 堆栈段地址
  MOV    SS,AX        ; 存入ES寄存器

  注意,在程序中不需要用指令装入代码段的段地址,因为在程序初始化时,装入程序已将代码段的段地址装入CS寄存器了。

  为了对段定义作进一步地控制,SEGMENT伪指令还可以增加类型及属性的说明,其格式如下:

  段名   SEGMENT  [定位类型][组合类型]['类别']
             .
            .
            .
  段名   ENDS

  [ ]中的内容是可选的,一般情况下,这些说明可以不用。但是,如果需要用连接程序把本程序与其他程序模块相连接时,就需要提供类型和属性的说明。

   ·定位类型:说明段的起始边界值(物理地址)。
定位类型
说 明
BYTE
段可以从任何地址边界开始
WORD
段从字边界开始,即段的起始边界值为偶数
DWORD
段从双字的边界开始,即段的起始边界值为4的倍数
PARA
段从小段边界开始,即段的起始边界值为16 (或10H) 的倍数
PAGE
段从页边界开始,即段的起始边界值为256 (或100H) 的倍数

  注意:
  定位类型的缺省项是PARA,即在未指定定位类型的情况下,则连接程序默认为PARA。BYTE和WORD用于把其它段(通常是数据段)连入一个段时使用;DWORD一般用于运行在80386及后继机型上的程序。


  ·组合类型:说明程序连接时的段组合方法。
       
组合类型
说 明
PRIVATE
该段为私有段,连接时将不与其它模块中的同名段合并
PUBLIC
该段连接时将与其它同名段连接在一起,连接次序由连接命令指定
COMMON
该段在连接时与其它同名段有相同的起始地址,所以会产生覆盖
AT 表达式
段地址=表达式的值,其值必为16位但AT不能用来指定代码段
MEMORY
与PUBLIC同义
STACK
将多个同名堆栈段连接在一起,SP设置在第一个堆栈段的开始

  注意:组合类型的缺省项是PRIVATE。

 
在连接之前已定义两个目标模块如下:

  模块1   SSEG  SEGMENT  PARA  STACK
       DSEG1 SEGMENT  PARA  PUBLIC 'Data'
       DSEG2 SEGMENT  PARA
       CSEG  SEGMENT  PARA 'Code'

  模块2   DSEG1 SEGMENT  PARA PUBLIC 'Data'
       DSEG2 SEGMENT  PARA
       CSEG  SEGMENT  PARA 'Code'

  以上两个模块分别汇编后产生 .OBJ 文件,经连接程序连接后产生的 .EXE模块如下:

  模块1   CSEG  SEGMENT  PARA 'Code'
  模块2   CSEG  SEGMENT  PARA 'Code'
  模块1+2  DSEG1 SEGMENT  PARA PUBLIC 'Data'
  模块1   DSEG2 SEGMENT  PARA
  模块2   DSEG2 SEGMENT  PARA
  模块1   SSEG  SEGMENT  PARA STACK
   2 存储模型与简化段定义伪指令

  较新版本的汇编程序(MASM5.0与MASM6.0)除支持完整段定义伪指令外,还提供了一种新的简单易用的存储模型和简化的段定义伪指令。

  
1.存储模型伪指令
  存储模型的作用是什么呢?存储模型决定一个程序的规模,也确定进行子程序调用、指令转移和数据访问的缺省属性(NEAR或FAR)。当使用简化段定义的源程序格式时,在段定义语句之前必须有存储模型 .MODEL语句,说明在存储器中应如何安放各个段。

  MODEL伪指令的常用格式如下:
.  .MODEL 存储模型

  2. 简化的段伪指令
  简化的段定义语句书写简短,语句.CODE、.DATA和.STACK分别表示代码数据段和堆栈段的开始,一个段的开始自动结束前面一个段。采用简化段指令之前必须有存储模型语句.MODEL。

  3.与简化段定义有关的预定义符号
  汇编程序给出了与简化段定义有关的一组预定义符号,它们可在程序中出现,并由汇编程序识别使用。有关的预定义符号如下:
  (1)@code 由.CODE 伪指令定义的段名或段组名。
  (2)@data 由.DATA 伪指令定义的段名,或由 .DATA 、.DATA?、
    .CONST和 .STACK所定义的段组名。
  (3)@stack 堆栈段的段名或段组名。

  4.简化段定义举例

  1. 存储模型伪指令

 表  MASM 5.0和MASM 6.0支持的存储模型:
存储模型
功 能
适用操作系统
Tiny (微型) 所有数据和代码都放在一个段内,其访问都为NEAR型,整个程序≤64K,并会产生.COM文件。 MS-DOS
Small (小型) 所有代码在一个64KB的段内,所有数据在另一个64KB的段内(包括数据段,堆栈段和附加段)。 MS-DOS
Windows
Medium (中型) 所有代码>64K时可放在多个代码段中,转移或调用可为FAR型。所有数据限在一个段内,DS可保持不变。 MS-DOS
Windows
Compact(紧凑型) 所有代码限在一个段内,转移或调用可为NEAR型。数据>64K时,可放在多个段中。 MS-DOS
Windows
Large (大型) 允许代码段和数据段都可超过64K,被放置在有多个段内,所以数据和代码都是远访问。 MS-DOS
Windows
Huge (巨型) 单个数据项可以超过64K,其它同Large模型 MS-DOS
Windows
Flat (平展型) 所有代码和数据放置在一个段中,但段地址是32位的,所以整个程序可为4GB。MASM 6.0支持该模型。 OS/2
WindowsNT

  注意:Small 模型是一般应用程序最常用的一种模型,因为只有一个代码段和一个数据段,所以数据和代码都是近访问的。这种模型的数据段是指数据段、堆栈段和附加段的总和。

   在DOS下用汇编语言编程时,可根据程序的不同特点选择前6种模型,一般可以选用SMALL模型。另外,TINY模型将产生COM程序,其他模型产生 EXE程序。FLAT模型只能运行在32位x86 CPU上,DOS下不允许使用这种模型。当与高级语言混合编程时,两者的存储模型应当一致。


  2. 简化的段伪指令

 表 简化段伪指令的格式如下表:

简化段伪指令
功 能
注释
.CODE [段名] 创建一个代码段 段名为可选项,如不给出段名,则采用默认段名。对于多个代码段的模型,则应为每个代码段指定段名。
.DATA 创建一个数据段 段名是:_DATA
.DATA? 创建无初值变量的数据段 段名是:_BSS
.FARDATA [段名] 建立有初值的远调用数据段 可指定段名,如不指定,则将以FAR_DATA命名。
.FARDATA? [段名] 建立无初值的远调用数据段 可指定段名,如不指定,则将以FAR_BSS命名。
.CONST 建立只读的常量数据段 段名是:CONST
.STACK [大小] 创建一个堆栈段并指定堆栈段大小 段名是:stack。如不指定堆栈段大小,则缺省值为1KB

  3.与简化段定义有关的预定义符号

  下面的举例说明预定义符号的使用方法。在完整的段定义情况下,在程序的一开始,需要用段名装入数据段寄存器,如例4.1中的
       mov   ax,data_seg1
       mov   ds,ax
  若用简化段定义,则数据段只用.data来定义,而并未给出段名,此时可用
       mov   ax,@data
       mov   ds,ax
  这里预定义符号@data就给出了数据段的段名。

  4.简化段定义举例
  
 
   .MODEL   SMALL
   .STACK   100H    ; 定义堆栈段及其大小
   .DATA         ; 定义数据段
       .
       .
       .
   .CODE         ; 定义代码段
 START:           ; 起始执行地址标号
   MOV     AX, @DATA ; 数据段地址
   MOV     DS, AX   ; 存入数据段寄存器
       .
       .
       .
   MOV    AX, 4C00H
   INT    21H
   END    START    ; 程序结束


  
从例可以看出,简化段定义比完整的段定义简单得多。但由于完整的段定义可以全面地说明段的各种类型与属性,因此在很多情况下仍需使用它。
 
段组定义伪指令

  段组定义伪指令能把多个同类段合并为一个64KB的物理段,并用一个段组名统一存取它。段组定义伪指令GROUP的格式如下:

  段组名 GROUP 段名 [, 段名 …]

  我们已经知道在各种存储模型中,汇编程序自动地把各数据段组成一个段组DGROUP,以便程序在访问各数据段时使用一个数据段寄存器DS,而GROUP伪指令允许用户自行指定段组。
 例  将两个数据段DSEG1 和DSEG2合并在一个段组DATAGROUP中。

   
;----------------------------------------------------

   DSEG1  SEGMENT WORD PUBLIC 'DATA'
       .
       .
       .
   DSEG1  ENDS
   ;---------------------------------------------------

   DSEG2  SEGMENT WORD PUBLIC 'DATA'
       .
       .
       .
   DSEG2  ENDS
   MOV     AX, @DATA ; 数据段地址
   MOV     DS, AX   ; 存入数据段寄存器
       .
       .
       .
   ;---------------------------------------------------
    DATAGROUP   GROUP DSEG1, DSEG2   ;组合成段组

   CSEG    SEGMENT PARA PUBLIC 'CODE'
        
ASSUME CS : CSEG, DS : DATAGROUP
   
START:  MOV   AX, DATAGROUP
       MOV   DS, AX          ;DS赋值为段组地址
         .
         .
         .
       
MOV   AX, 4C00H
        INT   21H
  
CSEG   ENDS
   ;--------------------------------------------
---------
       
END    START

  利用GROUP伪指令定义段组后,段组内统一为一个段地址,各段定义的变量和标号都可以用同一个段寄存器进行访问。
程序开始和结束伪指令

  在程序的开始可以用NAME或TITLE作为模块的名字,其格式为:
 
    NAME      模块名
    TITLE     文件名

  表示源程序结束的伪指令的格式为:
   
    END      [标号]
  注意:NAME及TITLE伪指令并不是必需的,如果程序中既无NAME又无TITLE伪指令,则将用源文件名作为模块名。程序中经常使用TITLE,这样可以在列表文件中打印出标题来。

   END伪指令中的"标号"指示程序开始执行的起始地址。如果多个程序模块相连接,则只有主程序的END要加上标号,其他子程序模块则只用END而不必指 定标号。例4.1~4.3的最后使用了END START伪指令。汇编程序将在遇END时结束汇编,并且程序在运行时从START开始执行。
数据定义及存储器分配伪指令

  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,以免与十进制数发生混淆。



4.2.1 处理器选择伪操作
    由于80x86的所有处理器都支持8086/8088指令系统,但每一种高档机型又都增加了一些新的指令,因此在编写程序时都要对所用处理器有一个确定的选择。
    本组伪操作的就是告诉汇编程序应该选择哪一种指令系统。
    本组伪操作,一般放在整个程序的最前面,如不给出处理器选择,则默认为.8086。也可放在程序中,如程序中用了一条80486所增加的指令,则可在该指令的上一行加上.486。
    处理器选择伪操作主要有以下几种:
        .8086       选择8086指令系统
        .286        选择80286指令系统
        .286 P      选择保护方式下的80286指令系统
        .386        选择80386指令系统
        .386 P      选择保护方式下的80386指令系统
        .486        选择80486指令系统
        .486 P      选择保护方式下的80486指令系统 
        .586        选择Pentium指令系统
        .586 P      选择保护方式下的Pentium指令系统   
    保护方式下的指令系统是指包括特权指令在内的指令系统。

4.2.2 段定义伪操作

    该组伪操作为确定标号和变量(代码段和数据段的符号地址)的偏移地址;把有关信息通过目标模块传送给连接程序,以便连接程序把不同的段和模块连接在一起,形成一个可执行程序。
1.完整的段定义伪操作
        段名    segment [定位]  [组合]  [段字]  [ ‘类别’ ]
                ...     ;语句序列
        段名    ends
    完整段定义由SEGMENT和ENDS这一对伪指令实现,SEGMENT伪指令定义一个逻辑段的开始,ENDS伪指令表示一个段的结束。段定义指 令后的4个关键字用于确定段的各种属性,堆栈段要采用stack组合类型,代码段应具有‘code’类别,其他为可选属性参数。如果不指定,则采用默认参 数;但如果指定,注意要按照上列次序。
    语句序列:数据段、附加段、和堆栈段中,一般是存储单元的定义、分配等伪操作;代码段则是指令及伪操作。
(1)定位类型(align_type)
    指定逻辑段在主存储器中的边界,可为:
    PARA    段的起始地址必须从小段边界开始(xxxx 0000b)。这样,偏移地址可以从0开始。
    BYTE    该段可以从任何地址开始(xxxx xxxxb),这样起始偏移地址可能不是0。
    WORD    该段必须从字的边界开始(xxxx xxx0b),即段起始地址必须为偶数。
    DWORD   该段必须从双字的边界开始(xxxxxx00b)。
    PAGE    该段必须从页的边界开始(0000 0000b),该地址能被256整除。
    默认定位类型:
    简化段定义伪指令的代码和数据段默认采用WORD定位,堆栈段默认采用PARA定位。
    完整段定义伪指令的默认定位属性是PARA,其低4位已经是0,所以默认情况下数据段的偏移地址从0开始。
(2)组合类型(combine_type)
    指定多个逻辑段之间的关系,可为:
    PRIVATE 该段为私有段,在连接时将不与其他模块中同名分段合并。这是完整段定义伪指令默认的段组合方式。
    PUBLIC  该段连接时,可以把不同模块中的同名段相邻地连接在一起,其连接次序由连接命令指定。每一分段都从小段的边界开始,因此个模块的原有段之间可能存在小于16字节的间隙。这是简化段定义伪指令默认的段组合。
    MEMORY  与PUBLIC同义。
    STACK   把不同模块中的同名段组合而形成一个堆栈段。该段的长度为各原有段的总和,各原有段之间并无PUBLIC所连接段中的间隙,而且栈顶可自动指向连接后形成的大段堆栈段的栈顶。这是堆栈段必须具有的段组合。
    COMMON  该段连接时,可以把不同模块中的同名段重叠而形成一个段,由于各同名段有相同的起始地址,所以会产生覆盖。COMMON的连接长度是各分段中的最大长度。重叠部分的内容取决于排列在最后一段的内容。
    AT expression   使段地址是表达式所计算出来的16位值。但它不能用来指定代码段。
(3)使用类型(use_type)
    为支持32位段而设置的属性,只适用于386及其后继机型。它用来说明使用16位寻址方式还是32位寻址方式。它们可以是:
    USE16       使用16位寻址方式。
    USE32       使用32位寻址方式。
    当使用16位寻址方式时,段长<=64KB,地址的形式是16位段地址和16偏移地址;当使用32位寻址方式时,段长可大4GB,地址的形 式是16位段地址和32位偏移地址。编写运行于实模式(8086工作方式)的汇编语言程序,必须采用USE16。使用类型的默认项是USE16。
(4)类别(‘class’)
    在引号中给出连接时组成段组的类型名,段组的类型名可以是任意名称。类型说明并不能把相同类别的段合并起来,但在连接程序组织段时,可将所有的同 类别段相邻分配。大多数MASM程序使用 ‘code’、‘data’和‘stack’来分别指名代码段、数据段和堆栈段,以保持所有代码和数据的连续。
指定段寄存器伪指令ASSUME
    ASSUME  段寄存器:段名 [,段寄存器名:段名, ...]
    通知MASM用指定的段寄存器来寻址对应的逻辑段,即明确段和段寄存器的关系。
    ASSUME说明分配情况。汇编程序会根据数据所在的逻辑段,在需要时自动插入段超越前缀。这是ASSUME伪指令的主要功能。其中段寄存器必须 是CS、DS、ES、SS(386及其后继机型还有FS和GS)之一,段名则必须是由SEGMENT定义的段中的段名。
    ASSUME伪指令并不为段寄存器设定初值,连接程序LINK将正确设置CS : IP和SS : SP。
    由于数据段通常都需要,所以在样板源程序中,首先为DS赋值;如果使用附加段,还要赋值ES。
    ASSUME  NOTHING则可取消前面由ASSUME所指定的段寄存器。
    完整段定义举例说明例4.1。
    ASSUME并不能把段地址装入段寄存器中,所以代码段中要有这样的操作。如果有堆栈段,也需把段地址装入SS中。代码段不需要,代码段的这一操作是在程序初始化时完成的。
2. 存储模型与简化段定义伪操作
(1) MODEL伪操作
    .MODEL  存储模式    [,模式选项]
    使用简化段定义,必须有存储模式伪指令。
    .model语句必须位于所有段定义语句之前。用来说明在存储器中是如何安放各个段的。
    存储模式决定一个程序的规模,确定进行子程序调用、指令转移和数据访问的缺省属性。
    MASM有7种不同的存储模式:
        ①  TINY        ②  SMALL
        ③ MEDIUM       ④ COMPACT
        ⑤  LARGE       ⑥  HUGE
        ⑦  FLAT
① Tiny
    微型模式是MASM 6.0才引入的,用于创建COM类型程序,COM程序必须从0100H的存储单元开始。这种模型一般用于小程序。用微型模式编写汇编语言程序时,所有的段 地址寄存器都被设置为同一值。这意味着代码段、数据段、堆栈段都在同一个段内,不大于64KB;访问操作数或指令都只需要使用16位偏移地址。
② Small
    一般的程序(例如本书的绝大多数程序示例和习题)都可用这种模式。在小型模式下,一个程序至多只能有一个代码段和一个数据段,每段不大于 64KB。这里的数据段是指数据段、堆栈段和附加段的总和,它们共用同一个段基址,总长度不可超过64KB;因此小模式下程序的最大长度为128KB。访 问操作数或指令都只需要使用16位偏移地址;这意味着诸如指令转移、程序调用以及数据访问等都是近属性(NEAR),即小型模式下的调用类型和数据指针缺 省分别为近调用和近指针。
③ Medium
    中型模式是与紧凑模式互补的模式。适合于数据量小但代码量大的程序。中型模式的代码段可以超过64KB,有多个;但数据段只能有一个不大于 64KB的段。这种模式下数据是近访问;但代码则是远访问,即调用类型缺省是远(FAR)调用,因为要利用段地址区别多个代码段。
④ Compact
    适合于数据量大但代码量小的程序。紧凑模式下,代码段被限制在一个不大于64KB的段内;而数据段则可以有多个,超过64KB。这种模式下的代码是近访问,即调用类型缺省仍为近调用;而数据则缺省为远(FAR)访问,因为必须用段地址来区别多个数据段。
⑤ Large
    较大型程序通常采用的存储模式。大型模式允许的代码段和数据段都有多个,都可以超过64KB;但全部的静态数据(不能改变的数据)仍限制在64K字节内。大型模式下的数据和代码都可以远访问。
⑥ Huge
    HUGE(巨型模式)与大型模式基本相同,只是静态数据不再被限制在64K字节之内。
⑦ Flat
    平展模式用于创建一个32位的程序,它只能运行在32位x86 CPU上。DOS下不能使用FLAT模式,而编写32位Windows 9.x或Windows-NT的程序时,必须采用FLAT模式。MASM5版本不支持这种模型,当MASM6可以支持。
    DOS下编程可选择前六种模式,一般可以选用SMALL模式。TINY模式产生COM程序,其他模式产生EXE程序,FLAT模式只能用于32位程序。
Model options允许用户指定三种选项:
  • 高级语言接口

  • 操作系统

  • 堆栈距离

    高级语言接口:该汇编程序作为某一高级语言程序的过程而为该高级语言程序调用时,应该用C,BASIC,FORTRAN,PASCAL等来说明。
    操作系统:说明程序运行于哪个操作系统之下,可用OS_DOS或OS_OS2来说明,默认项是OS_DOS。
    堆栈距离:可用NEARSTACK 或FARSTACK来说明。NEARSTACK是指把堆栈段和数据段组合到一个DGROUP段中,DS和SS均指向DGROUP段;FARSTACK是指堆栈段和数据段并不合并。
    当存储模型为TINY、SMALL、MEDIUM和FLAT时,默认项是NEARSTACK;当存储模型为COMPACT、LARGE和HUGE时,默认项是FARSTACK。
    例如:
        . MODEL  SMALL , C
        . MODEL  LARGE , PASCAL , OS_DOS , FARSTACK
(2)简化的段定义伪操作
    汇编程序给出的标准段有下列几种:
        Code                        代码段
        Initialized  data           初始化数据段
        Uninitialized data          未初始化数据段
        Far initialized data        远初始化数据段
        Far uninitialized data      远未初始化数据段
        Constants                   常数段
        Stack                       堆栈段
    这种分段方法把数据段分得更细,可便于与高级语言的兼容。在为高级语言编写某一个汇编过程时,可采用这种标准段模式。
    若编写一个独立的汇编语言程序,不需要细分。一般采用下述三个标准段即可。
        .CODE
        .DATA
        .STACK
    简化段定义伪指令指明一个逻辑段的开始,同时自动结束前面的一个段。
    采用简化段定义伪指令前,需有.model语句。
    使用简化段定义,各段名称和其他用户所需的信息可以使用MASM预定义符号,例如:@data表示由.data等定义的数据段的段名。
    对于以上标准段,可有以下简化段伪操作:
    堆栈段伪指令
        .STACK [大小]  
    堆栈段伪指令.STACK创建一个堆栈段,段名是:stack。
    它的参数指定堆栈段所占存储区的字节数,默认是1KB(= 1024 = 400h字节)。
    数据段伪指令
        .DATA
    数据段伪指令.data创建一个数据段,段名是:_DATA。它用于定义具有初值的变量,当然也允许定义无初值的变量。
    代码段伪指令
        .CODE [段名]
    代码段伪指令.code创建一个代码段,它的参数指定该代码段的段名。
(3)与简化段定义有关的预定义符号
    汇编程序给出了与简化段定义有关的一组预定义符号,它们可在程序中出现,并由汇编程序识别使用。
    如在完整段定义下,在程序一开始,需要用段名装入相应寄存器,如例4.1中的相应语句。
    若用简化段定义,则数据段只用.DATA来定义,而并未给出段名,此时可用
                mov  ax ,@data
                mov  ds , ax
    另外,还有一些预定义符号,它们也可与条件汇编伪操作相配合,以帮助用户编写一些较为复杂的代码。这里不作介绍。预定义符号@data给出了段名
(4)用MODEL定义存储模型时的段默认属性
    表4.1给出了使用MODEL伪操作时的段默认情况。
    模型列给出了可定义的7种模型;
    伪操作列给出了对应每一种模型可定义7种段的伪操作;
  • 名字列给出了各段所用段名;

  • 定位列给出了段的起始地址边界的类型;

  • 组合列给出了段的组合类型;

  • 类列给出了各段所属类;

  • 组列给出各种模型下所建立的数组。

(5)简化段定义举例
    例4.2、例4.3、例4.4
3. 段组定义伪操作
    汇编程序自动地把各数据段组成一个64KB段组DGROUP,以便程序在访问各数据段时使用一个数据段寄存器DS。
    格式:grpname  DGROUP  segname[, segname]
    其中,grpname为段组名,segname则为段名。
    DGROUP伪操作允许用户自行指定段组。
    定义段组后,段组内各段就统一为一个段地址,各段定义的变量和标号的偏移地址就相对于段组基地址计算。offset操作符取变量和标号相对于段组 的偏移地址,如果没有段组则取得相对于段的偏移地址。offset后可以跟段组中的某个段名,表示该段最后一个字节后面字节相对于段组的偏移地址。
4. 段顺序伪操作
    .SEG        ;按照源程序的各段顺序
    .DOSSEG     ;按照微软使用的标准DOS规定
    .ALPHA      ;按照段名的字母顺序
    段顺序伪指令确定各逻辑段在主存的前后位置。
    完整段定义格式中,默认按照源程序各段的书写顺序安排(即.seg)。
    采用.model伪指令的简化段定义格式,则是规定的标准DOS程序顺序( 即.dosseg ):

4.2.3 程序开始和结束伪操作

1. 程序开始处的伪操作
    在程序的开始处可以用NAME或TITLE作为模块的名字。
    格式:
    NAME  module_name          
    或
    TITLE  text
    汇编程序将以给出的module_name或text中的前六个字符作为模块名。Text最多可有60个字符。
    TITLE伪操作可指定列表文件的每一页上打印的标题。
    如果程序中既无NAME又无TITLE伪操作,则将用源文件名作为模块名。
    NAME或TITLE伪操作并不是必要的,但一般经常使用TITLE,以便在列表文件中打印出标题来。
2. 汇编结束伪操作
    表示源程序结束的伪操作。
    格式:  END [label]
    可选的标号label指示程序开始执行的起始地址,连接程序将据此设置CS : IP值。如果多个程序模块相连接,则只有主程序要使用标号,其他子程序模块则只用END而不必指定标号。
    指示汇编程序MASM到此结束汇编过程。源程序的最后必须有一条END语句。
    例4.1~4.5已使用END START表示程序结束,而程序则从START开始执行。
3. 程序开始伪操作
    MASM6.0增加了这个伪操作。
    .STARTUP
    用来定义程序的初始入口点,并且产生设置DS,SS和SP的代码。如果程序中使用了.STARTUP,则结束程序的END为操作中不必再指定程序的入口点标号。
4. 程序中止伪操作
    MASM6.0增加了这个伪操作。
    .EXIT  [return_value]
    用来产生退出程序并返回操作系统的代码。Return_value为返回给操作系统的值,常用0作为返回值。
    例如.exit 0对应的代码是:
            mov ax,4c00h
            int 21h
    DOS功能调用的4ch子功能(返回DOS):
        入口参数:AH=4ch,AL=返回数码
    退出程序与汇编结束是两码事。

4.2.4 数据定义及存储器分配伪操作
    该类伪操作又称变量定义伪指令。
    变量定义(Define)伪指令为变量申请固定长度的存储空间,并可同时将相应的存储单元初始化。
            变量名  伪指令助记符  初值表
    格式:
        [Variable]  Mnemonic  Operand , … , Operand [;Commnet]
    变量名(variable)为用户自定义标识符,表示初值表首元素的逻辑地址;用这个符号表示地址,常称为符号地址。变量名可以没有。这种情况,汇编程序将直接为初值表分配空间,无符号地址。设置变量名是为了方便存取它指示的存储单元。
    初值表是用逗号分隔的参数。主要由数值常数、表达式或?、DUP组成:
        ?——表示初值不确定,即未赋初值;
        DUP——表示重复初值。
    DUP的格式为:
            Repeat_count  DUP (operand , … , opreand)
其中repeat_count可以是一个表达式,它的值应该是一个正整数,用来指定括号中的操作数的重复次数。
    变量定义伪指令助记符(Mnemonic),根据申请的主存空间单位分类,说明所定义的数据类型。
        DB——定义字节伪指令
        DW——定义字伪指令
        DD——定义双字伪指令
        DF——定义3字伪指令
        DQ——定义4字伪指令
        DT——定义10字节伪指令
    这些伪操作可以把其后跟着的数据存入指定的存储单元,形成初始化数据;或者只分配存储空间而并不存入确定的数值,形成未初始化数据。
1. 定义字节单元伪指令DB
    DB伪指令用于分配一个或多个字节单元,并可以将它们初始化为指定值。初值表中每个数据一定是字节量(Byte),存放一个8位数据:
         可以是0~255的无符号数
         或是-128~+127带符号数
         也可以是字符串常数
2. 定义字单元伪指令DW
    DW伪指令用于分配一个或多个字单元,并可以将它们初始化为指定值。初值表中每个数据一定是字量(Word),一个字单元可用于存放任何16位数据:
         一个段地址
        一个偏移地址
         两个字符
         0~65535之间的无符号数
         -32768~+32767之间的带符号数
3. 定义双字单元伪指令DD
    DD伪指令用于分配一个或多个双字单元,并可以将它们初始化为指定值。初值表中每个数据是一个32位的双字量(Double Word):
         可以是有符号或无符号的32位整数
         也可以用来表达16位段地址(高位字)和16位的偏移地址(低位字)的远指针
      vardd       DD 0,?,12345678h
        farpoint        DD 00400078h
4. 其他数据单元定义伪指令
    定义3字伪指令DF——用于为一个或多个6字节变量分配空间及初始化。6字节常用在32位CPU中表示一个48位远指针(16位段选择器:32位偏移地址)
    定义4字伪指令DQ——用于为一个或多个8字节变量分配空间及初始化。8字节变量可以表达一个64位整数
    定义10字节伪指令DT——用于为一个或多个10字节变量分配空间及初始化。10字节变量可以表达扩展精度浮点数
    例4.7
        DATA_BYTE  DB  10 , 4, 10H
        DATA_WORD  DW  100 , 100H , -5
        DATA_DW    DD  3*20 , 0FFFDH
    汇编程序可以在汇编期间在存储器中存入数据,如图4.2所示。
    例4.8
        MESSAGE     DB  ‘HELLO’
                    DB  ‘AB’
                    DW  ‘AB’
    则存储器存储情况如图4.5所示。
    例4.9    操作数?可以保留存储空间,但不存入数据。如:
        ABC  DB  0 , ? , ? , ? , 0
        DEF  DW  ? , 52 , ?
    经汇编后的存储情况如图4.4所示。
    例4.11 DUP操作可以嵌套,例如:
        ARRAY3  db 100 dup(0 , 2 dup(1 , 2) ,0 , 3)
    则汇编后的结果如图4.6所示。
    例4.10
      ARRAY1   DB  2  DUP(0 , 1 , 2 , ?)
      ARRAY2   DB  100  DUP(?)
    汇编后的存储情况如图4.5所示。
    例4.12
        PARAMETER_TABLE DW  PAR1
                        DW  PAR2
                        DW  PAR3
        INTERSEG_DATA   DD  DATA1
                        DD DATA2
    则汇编程序的存储情况如图4.7所示。
    386及其后继机型具有16位段地址及32位偏移地址组成的48位远地址,可用DF伪指令来定义。
    例4.13
            .386
      Dataseg  segment  para use32  ‘data’
          Parse_table  db  2048  dup(0)
          Tblptr       df  Parse_table
      Dataseg   ends
    汇编后的存储情况如图4.8所示。
5. 变量定义伪指令使用说明
    操作数中的变量或标号可以是表达式,汇编后,存储器中应该存入表达式的值。
    DB、DW、DD、DF、DQ、DT等伪操作在MASM6中可用BYTE、WORD、DWORD、FWORD、QWORD、TBYTE来取代,其含义是等同的。

4.2.5 表达式赋值伪操作
    符号定义伪指令:用于常量定义,利用一个标识符表达的一个数值。
    等价EQU伪指令:Expression_name  EQU  Expression
        符号名 EQU 数值表达式
        符号名 EQU <字符串>
    其中符号名不允许重复定义。
        等号=伪指令
        符号名 = 数值表达式
    符号名允许重复定义。
    常数若使用有意义的符号名来表示,可以提高程序的可读性,同时更具有通用性。
    例:
        CONSTANT    EQU 256     ;数赋以符号名
        DATA        EQU HEIGHT+12   ;地址表达式赋以符号名
        ALPHA       EQU 7           
        BETA        EQU ALPHA-2   
        ADDR        EQU VAR+BETA      
           
        B           EQU [BETA]  ;变址引用赋以符号名B
        P8          EQU DS:[BP+8]  
        ;加段前缀的变址引用赋以 符号名P8
    必须注意:在EQU语句的表达式中,如果有变量或标号的表达式,则在该语句前应该先给出它们的定义。
    例如:AB  EQU  DATA_ONE+2
    则必须放在DATA_ONE的定义之后才行,否则汇编程序将出错。
    例:
    ;******************************************
    EMP     EQU  7      ;EMP的值为7
    …
    EMP  EQU  EMP+1     ;错误
    ;这种情况不允许
    ;******************************************
    …
    EMP=7           ;EMP的值为7
    …
    EMP=EMP+1       ;EMP的值为8
    ;这种情况是允许的

4.2.6  地址计数器与对准伪操作
1. 地址计数器$
  地址计数器(location counter)用来保存当前正在汇编的指令的偏移地址。当开始汇编或在每一段开始时,把地址计数器初始化为零。汇编过程中,每处理一条指令,地址计数器 就增加一个值,此值为该指令所需要的字节数。地址计数器的值可用符号“$”表示。汇编语言允许用户直接用$来引用地址计数器的值。
    例如:
    指令JNS $+6的转向地址为JNS指令的首地址加上6。
    当$用在指令中时,它表示本条指令的第一个字节的地址。这里,$+6必须是另一条指令的首地址。否则,汇编程序将指示出错信息。
    当$用在伪操作的参数字段时,则表示地址计数器的当前值。
    例4.17
        ARRAY  DW  1 , 2 , $+4 , 3 , 4 , $+4
    这里,$表示当前偏移地址。汇编后的存储区如图4.9所示。
2. ORG伪操作
    定位伪指令控制数据的偏移地址。
    ORG 参数        或  ORG  constant expression
    ORG伪指令是将当前偏移地址指针指向参数表达的偏移地址。
        ORG 100h             ;从100h处安排数据或程序
        ORG $+10             ;使偏移地址加10,即跳过10个字节空间
    如常数表达式的值为n,则ORG伪操作可以使下一个字节的地址成为常数表达式的值n 。
    常数表达式也可以表示从当前已定义过的符号开始的位移量,或表示从当前地址计数器值$开始的位移量。
3. EVEN伪操作
    EVEN    ;从偶地址开始
    EVEN伪指令使下一个变量或指令开始于偶数字节地址。
    EVEN伪操作可以保证字数组从偶数地址开始。
    例如:DATA_SEG  SEGMENT
                    …
                    EVEN
    WORD_ARRAY      DW 100 DUP(?)
            …
        DATA_SEG        ENDS
4. ALIGN伪操作
    ALIGN n     ;从n的整数倍地址开始
    ALIGN伪操作是将当前偏移地址指针指向n(n是2的乘方)的整数倍的地址。如果原地址指针已指向n的整数倍地址,则不做调整;否则将指针加以1~n-1中的一个数,使地址指针指向下一个n的整数倍地址。ALIGN 2与EVEN等价。
    Data segment
        data01 db 1,2,3         ;data01的偏移地址为0000h
            even                ;等价于align 2
        data02 dw 5             ;data02的偏移地址为0004h
            align 4    
        data03 dd 6             ;data03的偏移地址为0008h
            org $+10h
        data04 db ‘abc’       ;data04的偏移地址为001ch
     Data ends

4.2.7  基数控制伪操作
    MASM提供基数控制.RADIX伪指令可以改变默认进制,其格式是:
        .RADIX n
    其中,n用来表示基数值(用十进制数表示)。
    例如:
        MOV BX , 0FFH               .RADIX  16
                            与
        MOV     BX , 178            MOV BX , 0FFH
                                    MOV BX , 178D
是等价的。
    .RADIX 16把基数定位十六进制后,十进制数后面都应跟字母D。如果某个十六进制数的末字符为D,则应在其后跟字母H,以免与十进制数发生混淆。