彙編僞指令

  彙編僞指令 

段定義僞指令
 
  段定義僞指令是表示一個段開始和結束的命令,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,以免與十進制數發生混淆。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章