匯編語言---指令格式和基本語法


匯編語言的指令格式,目前有兩種不同的標准:Windows下的匯編語言基本上都遵循Intel風格的語法,比如:MASM、NASM;而Unix/Linux下的匯編語言基本上都遵循AT&T風格的語法;
一、匯編語言語句的通用格式
[名稱[:]] 指令碼 [第一操作數][,第二操作數] ;注釋
匯編語言的指令碼的操作數的個數可以是0、1、2個;當操作數的個數為2的時候,語句還有兩種不同的格式:
Windows下Intel風格的匯編語言語句格式為:
[名稱[:]] 指令碼 目的操作數DST,源操作數SRC ;注釋
Unix/Linux下AT&T風格的匯編語言語句格式為:
[名稱[:]] 指令碼 源操作數SRC,目的操作數DST ;注釋
例如: CYCLE: ADD AX,02H ;(AX)<-(AX)+02H
解釋:
匯編語言語句格式中的"名稱"並不是所有語句都必需的,但是,如果語句中帶有"名稱",那么,大多數情況下,"名稱"都表示的是內存中某一存儲單元的地址,也就是"名稱"后面各項在內存中存放的第一個存儲單元的地址(包括該"名稱"所在段的段地址和段內偏移地址);比如上面的指令中,CYCLE就是該語句的名稱,CYCLE表示的就是其后面的機器指令碼在內存中存放的第一個地址;"名稱"與指令碼之間的分隔符可以是冒號":",也可以是空格字符" ";當以冒號分割時,該名稱代表的是一個標號;當以空格分割時,該名稱代表的可能是標號,也可能是變量;當指令碼有多個操作數的時候,相鄰兩個操作數之間要用逗號","分割;指令碼與操作數之間必須以空格分割;匯編語言語句的注釋必須以分號";"開頭;
二、組成語句的元素
1、常數:
匯編語言中的常數有整數、字符串;二進制、八進制、十進制、十六進制;匯編語言采用不同的后綴區分:
B:二進制數; O:八進制數; D:十進制數; H:十六進制數;
當一個數值后面沒有后綴的時候,默認為十進制數;
字符串常數是用一對單引號('')括起來的一串字符;
2、表達式:
由操作數和操作符組成;
算數運算操作符: +、-、*、/、MOD,等;取模運算MOD是取兩數相除的余數;
邏輯運算操作符: AND(邏輯與)、OR(邏輯或)、NOT(邏輯非)、XOR(邏輯異或);
注意:邏輯運算符同時又可以是邏輯運算指令的指令碼,只有當它們出現在指令的操作數部分時,才是操作符;例如:
ADD AL,0CH ADD 0FH  ;第一個ADD是指令碼,第二個ADD是操作符;
關系運算操作符: EQ(相等)、NE(不等)、LT(小於)、GT(大於)、LE(小於等於)、GE(大於等於);
匯編語言中的表達式不能單獨構成語句,只能是語句的組成部分;
注意:語句中表達式的求值不是在語句執行時完成的,而是在對源程序進行匯編鏈接時完成的.所以,語句中各表達式的值必須在匯編或鏈接時就是確定的,也就是說,表達式中各標識符的值在匯編或鏈接時就應該是確定的;
3、標號:
標號是由標識符表示的指令的名稱,用於指示對應指令的位置(地址);
標號具有三個屬性:段地址、偏移地址和類型;
標號的段地址和偏移地址屬性是指該標號所對應的指令所在段的段地址和段內偏移地址;
標號的類型有兩種:NEAR和FAR;標號定義成NEAR類型,表示該標號在段內使用,而定義成FAR類型則表示該標號可以在段間使用;
標號的定義:在指令碼前面加上標識符和冒號":";
例如:START: PUSH DS
這條語句里面,START就是我們定義的標號,它代表指令PUSH的地址,所以,標號可以作為程序轉移指令的操作數(即:要轉向的地址);標號還可以采用偽指令來定義;例如:用LABEL偽指令和過程定義偽指令來定義;
4、變量:
與高級語言一樣,並不是所有的操作數都是常數,匯編語言也有自己的變量,變量的值在程序運行期間是可以被改變的;
A.定義變量:匯編語言中,變量的定義是通過偽指令來完成的;定義變量的偽指令格式如下:
變量名 DB 表達式 ;定義字節變量,又稱單字節變量(1個連續字節),DB-->BYTE
變量名 DW 表達式 ;定義字變量,又稱雙字節變量(2個連續字節),DW-->WORD
變量名 DD 表達式 ;定義雙字變量,又稱四字節變量(4個連續字節),DD-->DWORD
變量名 DF 表達式 ;定義六字節變量,又稱六字節變量(6個連續字節),DF-->FWORD
變量名 DQ 表達式 ;定義長字變量,又稱八字節變量(8個連續字節),DQ-->QWORD
變量名 DT 表達式 ;定義十字節變量(10個連續字節),DT-->TBYTE;
其中,變量名是一個合法的標識符,變量名后面不能加冒號":",只能用空格;變量名不是必要的,可有可無;變量的類型由關鍵字DB、DW、DD、DQ、DT來定義;
變量定義語句中的"表達式"是用於對變量進行初始化的,可有一下幾種情況:
(1).一個或多個常數或表達式;當為多個常數或表達式時,期間要用逗號隔開;如DATA1--DATA4;
(2).帶單引號的字符串;
對於字節型(DB)變量,每個變量的大小為1個字節,每個變量的值不能超過1個字符,每個字節內存入一個字符的ASCII碼值,整個字符串可以在同一對單引號內給出,這相當於是定義了一個字符數組,如DATA5;
對於字類型(DW)變量,每個變量的大小為2個字節,每個變量的值不能超過2個字符,若為2個字符時,同樣遵循高位存入高字節,低位存入低字節的規則;若為1個字符,則該字符的ASCII碼值存入到低字節,高字節為00,如DATA6;
對於雙字類型(DD)變量,每個變量的大小為4個字節,每個變量的值不能超過2個字符,若為2個字符,同樣遵循高位存入高字節,低位存入低字節的規則;但是2個字符的值被存入到雙字變量的最低2個字節中,1個字符的值被存入到雙字變量的最低1個字節中;
對於長字類型(DQ)變量,每個變量的大小為8個字節,每個變量的值不能超過2個字符,若為2個字符,同樣遵循高位存入高字節,低位存入低字節的規則;但是2個字符的值被存入到長字變量的最低2個字節中,1個字符的值被存入到長字變量的最低1個字節中;
(3).一個問號"?",表示該變量的值不確定,即:該變量所表示的內存單元中的內容是不確定的,或者說是,當表達式為問號時,變量所對應的內存區中並沒有存入新的值,而只是預留出了相應的存儲空間;如DATA7、DATA8
(4).重復方式;此時的格式為: 重復次數 DUP(表達式);重復方式指出表達式的值可以重復地存儲到變量對應的內存區中,重復的次數由偽指令給出,相當於定義數組;如DATA9、DATA10
定義變量的例子:
DATA1  DB 20H            ;1字節變量
DATA2  DW 0204H,1000H    ;2字節變量
DATA3  DB (-1*3),(15/3)  ;1字節變量
DATA4  DD 123456H        ;4字節變量
DATA5  DB '0123'         ;字符串變量,相當於一個字符數組
DATA6  DW 'AB','C','D'   ;字符串變量,相當於一個字符串數組;
DATA7  DB ?              ;1字節變量,未初始化
DATA8  DD ?              ;4字節變量,未初始化
DATA9  DB 5 DUP(0)       ;1字節變量,用5個0初始化,相當於是一個具有5個DB型元素的數組
DATA10 DW 3 DUP(?)       ;2字節變量,未初始化,相當於是一個具有3個DW型元素的數組
變量定義語句中偽指令的功能是在變量名所對應的地址開始的內存區依次存入表達式中的各項值,表達式中的每項值所占用內存字節數與變量的類型對應;
總結:一個變量的變量名實際上就代表了該變量所對應的內存區在內存段中的有效地址(偏移地址);高地址是指地址值相對較大,低地址是指地址值相對較小,高地址與低地址是相對而言的;
5、變量的屬性:
(1).屬性介紹
一個變量具有一下屬性:
A.段地址(SEG):變量所在段的段地址;
B.偏移地址(OFFSET):變量所在段內的偏移地址;
C.類型(TYPE):變量的類型定義了每個變量所占用的內存字節數,對於DB、DW、DD、DQ、DT類型定義的變量所占用的內存字節數分別是1、2、4、8、10;通常又將DB、DW、DD類型所定義的變量分別成為BYTE類型、WORD類型、DWORD類型變量;
常用標識符的類型值列表:
標識符種類  字節變量  字變量  雙字變量  近標號NEAR  遠標號FAR
TYPE的值     1          2        4          -1           -2
D.長度(LENGTH):變量定義時,一個變量名所定義的變量個數;在含有DUP操作符的變量定義中,變量名所定義的變量個數為定義格式中的重復次數;在其它各種變量定義中,每個變量名所定義的變量個數均為1個;
E.大小(SIZE):變量定義語句中,分配給同一個變量名的所有變量的總的字節數,其值為該變量的類型與長度的成績;
其中,段地址、偏移地址和類型屬性是變量的主屬性,而長度和大小屬性是變量的輔助屬性;
(2).屬性操作符:
操作符    表達式              含義
SEG        SEG 變量名或標號       取出變量名或標號所在段的段地址
OFFSET     OFFSET 變量名或標號    取出變量名或標號所在段內的偏移地址
TYPE       TYPE 變量名或標號      取出變量名或標號的類型(變量所占用的字節數)
LENGTH     LENGTH 變量名          取出變量的長度
SIZE       SIZE 變量名            取出變量的大小
這些操作符不能單獨構成語句,只能作為表達式的組成部分,並且表達式的求值也是在匯編過程中完成的;
6.強制類型轉換操作符PTR
格式:數據類型 PTR 地址表達式
格式中的"數據類型"可以是BYTE、WORD、DWORD、NEAR、FAR;前三種類型是變量的類型,后兩種類型是標號的類型;格式中的表達式可以是變量、標號、其它地址表達式;
PTR操作符的功能是用來重新定義已定義的變量或標號的類型,其作用域只在當前語句中; 例如:
DATA1 DW 02H
MOV BYTE PTR DATA1,AL
這條指令中,是把DATA1的類型轉換為BYTE類型,然后把AL中的內容存放到DATA1的最低一個字節中;作用域只在這條MOV語句中,過了這條語句,DATA1仍然是DW類型,即:DATA1原來的類型並沒有被修改;
7、復合數據類型:
符合數據類型,除了用DUP定義的重復數據類型之外,與C/C++語言一樣,匯編語言中也有結構體類型、聯合類型、記錄類型;
(1).結構體類型:
A.類型定義格式:
結構類型名 STRUC [對齊類型Alignment][,NONUNIQUE]
           Field1 Type1 Exp1
           Field2 Type2 Exp2
           ......
           FieldN TypeN ExpN
結構類型名 ENDS
說明:結構體中的字段名可有可無;若有字段名,則字段名必須唯一,每個字段可獨立存取;若沒有字段名,則通過偏移量來存取;
對齊方式Alignment:定義每個字段的字節對齊邊界,對齊值有1、2、4、8、16字節對齊,值必須是2的冪次方;對齊類似於C/C++中結構體字段的對齊;
NONUNIQUE:要求結構體中的字段必須用全名才能訪問;
結構體中的字段可以有字段名,也可以沒有字段名;有字段名的字段可直接使用該字段名來訪問,沒有字段名的字段可用使用該字段在結構體中的偏移量來訪問;
例如:
PERSON STRUC
       NO   DD ?          ;有名字段,偏移量為0
       NAME DB 10 DUP(?)  ;有名字段,偏移量為4
            DB 1          ;無名字段,偏移量為14
PERSON ENDS
B.結構類型變量的定義:
[變量名] 結構類型名 <[字段值列表]>
字段值列表中的各個字段之間用逗號","分割,字段值的排列順序及類型應該與該結構定義時說明的各個字段相一致;如果結構變量中某個字段的值使用定義結構時說明的缺省值,那么可用逗號來表示;如果所有字段都使用定義結構體時說明的各個字段的缺省值,則可省去字段值列表,只需保留一對尖括號"<>"即可;
例如:
Per1 PERSON <>             ;所有字段都是用默認值
Per2 PERSON <1,'bdx',60>   ;所有字段都重新初始化
Per3 PERSON <2, , 90>      ;第二個字段使用默認值;
C.結構體類型字段的引用:
格式: 結構變量名.字段名
這種引用方式與高級語言中的引用方式完全一致;另外,還可以使用偏移量來訪問某個字段;
方式1:使用字段名直接引用
MOV AX,Per3.NAME
方式2:使用字段的在結構體中的偏移量來引用
LEA SI,Per3   ;取變量Per3對應內存塊的有效地址
MOV AX,[SI+4] ;寄存器相對尋址,4是字段NAME的偏移量
(2).聯合體類型:
A.類型定義格式:
[聯合體類型名] UNION [對齊方式Alignment][,NONUNIQUE]
           Field1 Type1 Exp1
           Field2 Type2 Exp2
           ......
           FieldN TypeN ExpN
[聯合體類型名] ENDS
說明:聯合體類型中的各個字段相互覆蓋,即:同樣的存儲單元被多個不同類型的字段所對應,並且每個字段在聯合體類型中的偏移量都是0;聯合體類型所占用的字節數是其所有字段所占字節數的最大值,即:聯合體所占用的字節數是這個聯合體的所有字段中占用字節數最多的那個字段占用的字節數;
對齊方式Alignment:可用1、2、4、8、16個字節來指定聯合體中各個字段字節的對齊邊界,其缺省的對齊邊界是1字節;還可用使用偽指令ALIGN或EVEN來重新定界,也可使用命令行選項/Zp來定界;
NONUNIQUE:要求聯合體類型中的字段必須使用全名才能訪問;
例如:
DATE UNION
     YEAR  DB 2010
     MONTH DB 07
     DAY   DB 04
DATE ENDS
B.聯合體類型變量的定義:
聯合體類型的變量只能使用第一個字段的數據類型來進行初始化;例如:
DATE1 DATE <2011>   ;定義一個聯合體類型變量DATE1,並使用第一個字段的數據類型進行初始化
DATE2 DATE <'2011'> ;初始化錯誤,只能使用第一個字段的數據類型進行初始化;
C.聯合體類型字段的引用:
格式: 聯合體類型變量名.字段名
例如:
MOV DATE1.YEAR,2012  ;給聯合體類型變量字段賦值
MOV AL,DATE1.MONTH   ;AL=07
MOV BX,DATE1.YEAR    ;BX=2012
MOV DATE1.MONTH,08   ;月份置為8月
(3).記錄類型:
A.類型定義格式:
匯編語言中的記錄類型與高級語言中的記錄類型不同,在匯編語言中,記錄類型是為按照二進制位存取數據提供方便的;記錄類型的說明要用到另一個關鍵字RECORD,格式如下:
記錄名 RECORD 字段[,字段,...]
其中,"字段"代表: 字段名:寬度[=初始值表達式]
說明:記錄名代表該記錄類型;記錄類型可以由多個字段組成,相鄰兩個字段之間用逗號隔開;記錄類型中字段的屬性包括字段名、寬度和初始值;記錄類型中,字段的"寬度"屬性表示該字段所占用的二進制位數,它必須是一個常數,並且所有字段的寬度之和不能大於16(即:<=16);如果記錄類型中所有字段的寬度之和大於8,則系統會自動為該記錄類型分配2字節的空間,否則只分配1個字節的空間;記錄類型的最后一個字段排在所分配空間的最低位,然后對記錄中的字段依次"從右向左"分配二進制位,左邊沒有分完的二進制位自動補0;初值表達式給出的是該字段的缺省值,如果初值超過了該字段所表示的范圍,那么,在匯編時將產生錯誤提示信息,如果某字段沒有初值表達式,則其初值為0;
例1:
COLOR RECORD BLINK:1,BACK:3=0,INTENSE:1=1,FORE:3
該COLOR類型的二進制位分布如下圖所示:


該類型的各個字段寬度為:1、3、1、3,所以,該記錄占用8個二進制位,系統為它分配1個字節;
例2:
FLOAT RECORD DSIGN:1,DATA:8,ESIGN:1,EXP:4
該FLOAT類型的二進制位分布如下圖所示: 

該類型的總寬度是14個二進制位,所以,系統為它分配2個字節的空間;
B.記錄類型變量的定義:
[變量名] 記錄類型名 <[字段值列表]>
說明:變量名就是該記錄類型的變量名,它可缺省,則不能使用符號名來訪問該內存單元;字段值列表是用於給各個字段賦初值,相鄰兩個字段值之間用逗號","隔開,其字段值的排列順序及大小應該按照記錄類型定義時說明的各個字段的順序和大小來排列;如果記錄類型變量的某個字段使用默認值,那么,可用逗號來表示,如果所有字段都是用默認值,則可省去字段值列表,但必須保留一對尖括號"<>";
例如:
COLOR1 COLOR <>, <1,7,0,5>, <1,,0,7>
FLOAT1 FLOAT <1,23H,0,3>, <0,89H,1,5>
C.記錄類型字段的引用:
格式: 記錄類型變量名.字段名
例如: MOV AL,COLOR1.FORE
D.記錄類型的專用操作符:
操作符WIDTH和MASK是專用於記錄類型的操作符,利用它們可用得到記錄類型的不同屬性;
WIDTH:用於返回記錄或其字段的二進制位數,即:記錄類型或記錄類型字段的寬度;書寫格式如下:
WIDTH 記錄名     或     WIDTH 記錄字段名
例如:記錄類型COLOR,那么,WIDTH COLOR的值為8,WIDTH BACK的值為3,WIDTH BLINK的值為1;
MASK:它返回一個8位或16位的二進制數,在該二進制數中,被指定記錄或字段使用的對應位的值為1,否則,其值為0;書寫格式如下:
MASK 記錄名     或     記錄字段名
例如:記錄類型FLOAT,那么,MASK EXP的值為000FH,MASK DATA的值為1FE0H,MASK DSIGN的值為2000H;
記錄字段:記錄字段名是一個特殊的操作符,它本身也是一個操作數,其返回值是該字段移到該字段所在記錄的最低位所需要的位數,即:該字段最低位在記錄中的位置;
例如:記錄類型FLOAT,則有:
MOV CL,EXP     相當於    MOV CL,0
MOV CL,DATA    相當於    MOV CL,5
(4).類型重定義:
已知某一數據類型,程序員可以定義這個數據類型的別名或指針類型.表達這種定義的偽指令是TYPEDEF,其定義形式如下:
新數據類型名 TYPEDEF [位距][PTR] 已知數據類型
其中,"位距"是NEAR、FAR、PROC等;
例如:
CHAR  TYPEDEF BYTE     ;給BYTE類型定義另外一個別名CHAR,C++中就是: typedef BYTE CHAR
PCHAR TYPEDEF PTR CHAR ;定義一個字符指針數據類型PCHAR,C++中就是:typedef PTR CHAR PCHAR,即:typedef char* PCHAR
那么,下面的變量定義就是合法的了:
CH1  CHAR 'ABCDEF'  ;定義一個字符串常量
PCH1 PCHAR CH1      ;定義一個指向字符串常量CH1的變量
這個功能類似於C++語言中的typedef語句;
8.表達式中的操作符:
HIGH(高8位)、LOW(低8位)
SEG(段地址)、OFFSET(偏移量)、TYPE(數據類型)、LENGTH(變量長度)、SIZE(變量容量)
WIDTH(記錄/記錄字段的寬度)、MASK(記錄/記錄字段的屏蔽位),等等;
其中,HIGH和LOW分別用於選取表達式計算結果的高8位和低8位,使用格式如下:
HIGH 表達式      LOW 表達式
9.運算符和操作符的優先級:
優先級: 高 LENGTH、SIZE、WIDTH、MASK、()、[]、.(用於結構字段)、<>(用於記錄類型)
        ↓ PTR、SEG、OFFSET、TYPE、THIS、:(用於段超越前綴)
           *、/、MOD、SHL、SHR
        ↓ HIGH、LOW
           +、-
        ↓ EQ、NE、LT、LE、GT、GE
           NOT
        ↓ AND
           OR、XOR
優先級: 低 SHORT
10.地址表達式:
地址表達式是計算存儲器單元地址的表達式,它可由標號、變量名和由方括號"[]"括起來的基址或變址寄存器組成;其計算結果表示一個存儲器單元的地址,而不是該存儲器單元中的值;
注意:匯編語言中,對地址數值的運算都是以字節為單位的,而不是以數據類型的大小為單位的;例如:
W1 DW 1234H,5678H
則,地址表達式W1+1處的內存單元中的數據是7812H,而不是5678H;W1+1表示W1為起始地址,其下一個字節單元的地址,W1+2表示從地址W1出開始,其后2個字節單元地址;
11.符號定義語句:
在程序中,經常會用到一些常數或數值表達式,並把它們直接寫在指令值,當時當需要修改的時候,就要對它們逐一進行修改,這無疑就增加了維護程序的工作量,而且每個常量或表達式所代表的含義也容易忘記;於是,匯編語言提供了為常量或表達式定義一個符號名的方法;一旦定義了符號名,在指令中就可以直接使用它們了;這個功能就類似於C語言中使用宏定義指令#define定義常量的功能相似,也與C++中使用const關鍵字定義常量的功能相似;
( 1).等價語句EQU
一般格式:
符號名 EQU 表達式
作用:左邊的符號名代表右邊的表達式;
注意:等價語句不會給符號名分配存儲空間,符號名不能與其它符號名重名,即:符號名必須唯一;符號名也不能被重新定義;程序中凡是出現"表達式"的地方,都使用"符號名"來替換;
(2).使用符號名代表常量或表達式
把一個常量或表達式定義成一個具有一定含義的符號名之后,在程序中就可以用該符號名來代表該常量或表達式;例如:
NUMBER EQU 100        ;給緩沖區的長度取一個符號名
BUFF_LEN EQU NUMBER+2
CR EQU 13             ;給"回車"符的ASCII碼定義一個符號名
LN EQU 10             ;給"換行"符的ASCII碼定義一個符號名
(3).用符號名代表字符串
例如:
GREETING EQU 'How are you!'
(4).用符號名代表關鍵字或指令碼
例如:
MOVE EQU MOV   ;給指令碼MOV取另外一個符號名MOVE
COUNTER EQU CX ;給寄存器CX取一個叫做"計數器"的符號名
12.等號語句
匯編語言提供了使用等號"="來定義符號常數的方法,即:可用符號名代表一個常數;一般格式如下:
符號名 = 表達式
數值表達式在匯編時應該可以計算出值,它不能含有向前引用的符號名稱;用等號語句定義的符號名可以被重新定義;可把等號語句看成是高級語言中的一個賦值語句,可以被多次賦值,這一點是與EQU不同的地方;例如:
ABC = 10 + 200*5    ;ABC的值為1010
ABC1 = 5*ABC + 21   ;ABC1的值為5071
COUNT = 1           ;COUNT的值為1
COUNT = 2*COUNT + 1 ;COUNT的值為3
注意:偽指令"="和偽指令"EQU"定義符號名時,凡是在程序中出現符號名的地方,都是用右邊的常量或表達式來替代;
13.標號定義語句
該語句定義一個指定的符號名,該符號名的段地址和偏移地址與下面緊跟存儲單元的相應屬性相同,但是,該符號名的類型是新指定的;
LABEL語句的一般格式如下:
符號名 LABEL 數據類型
常用的數據類型有:BYTE、WORD、DWORD、結構類型、記錄類型、NEAR、FAR;
其中,前五中類型是變量的類型,后面兩種類型是標號的類型;如果格式中的"數據類型"是前面五種類型之一的話,"符號名"就是變量名;如果格式中的"數據類型"是后面的兩種類型之一的話,"符號名"就是標號名;變量名和標號名都具有段地址和偏移地址的屬性;
例如:
WBUFFER LABEL WORD
BUFFER DB 200 DUP(0)
這個LABEL定義語句中,WBUFFER與BUFFER具有完全相同的段地址和偏移地址,但是它們的數據類型不同,目的就是為了使用兩種不同類型的操作來訪問同一塊內存區;
注意:偽指令本身不占用內存空間;

 

匯編語言的指令格式,目前有兩種不同的標准:Windows下的匯編語言基本上都遵循Intel風格的語法,比如:MASM、NASM;而Unix/Linux下的匯編語言基本上都遵循AT&T風格的語法;
一、匯編語言語句的通用格式
[名稱[:]] 指令碼 [第一操作數][,第二操作數] ;注釋
匯編語言的指令碼的操作數的個數可以是0、1、2個;當操作數的個數為2的時候,語句還有兩種不同的格式:
Windows下Intel風格的匯編語言語句格式為:
[名稱[:]] 指令碼 目的操作數DST,源操作數SRC ;注釋
Unix/Linux下AT&T風格的匯編語言語句格式為:
[名稱[:]] 指令碼 源操作數SRC,目的操作數DST ;注釋
例如: CYCLE: ADD AX,02H ;(AX)<-(AX)+02H
解釋:
匯編語言語句格式中的"名稱"並不是所有語句都必需的,但是,如果語句中帶有"名稱",那么,大多數情況下,"名稱"都表示的是內存中某一存儲單元的地址,也就是"名稱"后面各項在內存中存放的第一個存儲單元的地址(包括該"名稱"所在段的段地址和段內偏移地址);比如上面的指令中,CYCLE就是該語句的名稱,CYCLE表示的就是其后面的機器指令碼在內存中存放的第一個地址;"名稱"與指令碼之間的分隔符可以是冒號":",也可以是空格字符" ";當以冒號分割時,該名稱代表的是一個標號;當以空格分割時,該名稱代表的可能是標號,也可能是變量;當指令碼有多個操作數的時候,相鄰兩個操作數之間要用逗號","分割;指令碼與操作數之間必須以空格分割;匯編語言語句的注釋必須以分號";"開頭;
二、組成語句的元素
1、常數:
匯編語言中的常數有整數、字符串;二進制、八進制、十進制、十六進制;匯編語言采用不同的后綴區分:
B:二進制數; O:八進制數; D:十進制數; H:十六進制數;
當一個數值后面沒有后綴的時候,默認為十進制數;
字符串常數是用一對單引號('')括起來的一串字符;
2、表達式:
由操作數和操作符組成;
算數運算操作符: +、-、*、/、MOD,等;取模運算MOD是取兩數相除的余數;
邏輯運算操作符: AND(邏輯與)、OR(邏輯或)、NOT(邏輯非)、XOR(邏輯異或);
注意:邏輯運算符同時又可以是邏輯運算指令的指令碼,只有當它們出現在指令的操作數部分時,才是操作符;例如:
ADD AL,0CH ADD 0FH  ;第一個ADD是指令碼,第二個ADD是操作符;
關系運算操作符: EQ(相等)、NE(不等)、LT(小於)、GT(大於)、LE(小於等於)、GE(大於等於);
匯編語言中的表達式不能單獨構成語句,只能是語句的組成部分;
注意:語句中表達式的求值不是在語句執行時完成的,而是在對源程序進行匯編鏈接時完成的.所以,語句中各表達式的值必須在匯編或鏈接時就是確定的,也就是說,表達式中各標識符的值在匯編或鏈接時就應該是確定的;
3、標號:
標號是由標識符表示的指令的名稱,用於指示對應指令的位置(地址);
標號具有三個屬性:段地址、偏移地址和類型;
標號的段地址和偏移地址屬性是指該標號所對應的指令所在段的段地址和段內偏移地址;
標號的類型有兩種:NEAR和FAR;標號定義成NEAR類型,表示該標號在段內使用,而定義成FAR類型則表示該標號可以在段間使用;
標號的定義:在指令碼前面加上標識符和冒號":";
例如:START: PUSH DS
這條語句里面,START就是我們定義的標號,它代表指令PUSH的地址,所以,標號可以作為程序轉移指令的操作數(即:要轉向的地址);標號還可以采用偽指令來定義;例如:用LABEL偽指令和過程定義偽指令來定義;
4、變量:
與高級語言一樣,並不是所有的操作數都是常數,匯編語言也有自己的變量,變量的值在程序運行期間是可以被改變的;
A.定義變量:匯編語言中,變量的定義是通過偽指令來完成的;定義變量的偽指令格式如下:
變量名 DB 表達式 ;定義字節變量,又稱單字節變量(1個連續字節),DB-->BYTE
變量名 DW 表達式 ;定義字變量,又稱雙字節變量(2個連續字節),DW-->WORD
變量名 DD 表達式 ;定義雙字變量,又稱四字節變量(4個連續字節),DD-->DWORD
變量名 DF 表達式 ;定義六字節變量,又稱六字節變量(6個連續字節),DF-->FWORD
變量名 DQ 表達式 ;定義長字變量,又稱八字節變量(8個連續字節),DQ-->QWORD
變量名 DT 表達式 ;定義十字節變量(10個連續字節),DT-->TBYTE;
其中,變量名是一個合法的標識符,變量名后面不能加冒號":",只能用空格;變量名不是必要的,可有可無;變量的類型由關鍵字DB、DW、DD、DQ、DT來定義;
變量定義語句中的"表達式"是用於對變量進行初始化的,可有一下幾種情況:
(1).一個或多個常數或表達式;當為多個常數或表達式時,期間要用逗號隔開;如DATA1--DATA4;
(2).帶單引號的字符串;
對於字節型(DB)變量,每個變量的大小為1個字節,每個變量的值不能超過1個字符,每個字節內存入一個字符的ASCII碼值,整個字符串可以在同一對單引號內給出,這相當於是定義了一個字符數組,如DATA5;
對於字類型(DW)變量,每個變量的大小為2個字節,每個變量的值不能超過2個字符,若為2個字符時,同樣遵循高位存入高字節,低位存入低字節的規則;若為1個字符,則該字符的ASCII碼值存入到低字節,高字節為00,如DATA6;
對於雙字類型(DD)變量,每個變量的大小為4個字節,每個變量的值不能超過2個字符,若為2個字符,同樣遵循高位存入高字節,低位存入低字節的規則;但是2個字符的值被存入到雙字變量的最低2個字節中,1個字符的值被存入到雙字變量的最低1個字節中;
對於長字類型(DQ)變量,每個變量的大小為8個字節,每個變量的值不能超過2個字符,若為2個字符,同樣遵循高位存入高字節,低位存入低字節的規則;但是2個字符的值被存入到長字變量的最低2個字節中,1個字符的值被存入到長字變量的最低1個字節中;
(3).一個問號"?",表示該變量的值不確定,即:該變量所表示的內存單元中的內容是不確定的,或者說是,當表達式為問號時,變量所對應的內存區中並沒有存入新的值,而只是預留出了相應的存儲空間;如DATA7、DATA8
(4).重復方式;此時的格式為: 重復次數 DUP(表達式);重復方式指出表達式的值可以重復地存儲到變量對應的內存區中,重復的次數由偽指令給出,相當於定義數組;如DATA9、DATA10
定義變量的例子:
DATA1  DB 20H            ;1字節變量
DATA2  DW 0204H,1000H    ;2字節變量
DATA3  DB (-1*3),(15/3)  ;1字節變量
DATA4  DD 123456H        ;4字節變量
DATA5  DB '0123'         ;字符串變量,相當於一個字符數組
DATA6  DW 'AB','C','D'   ;字符串變量,相當於一個字符串數組;
DATA7  DB ?              ;1字節變量,未初始化
DATA8  DD ?              ;4字節變量,未初始化
DATA9  DB 5 DUP(0)       ;1字節變量,用5個0初始化,相當於是一個具有5個DB型元素的數組
DATA10 DW 3 DUP(?)       ;2字節變量,未初始化,相當於是一個具有3個DW型元素的數組
變量定義語句中偽指令的功能是在變量名所對應的地址開始的內存區依次存入表達式中的各項值,表達式中的每項值所占用內存字節數與變量的類型對應;
總結:一個變量的變量名實際上就代表了該變量所對應的內存區在內存段中的有效地址(偏移地址);高地址是指地址值相對較大,低地址是指地址值相對較小,高地址與低地址是相對而言的;
5、變量的屬性:
(1).屬性介紹
一個變量具有一下屬性:
A.段地址(SEG):變量所在段的段地址;
B.偏移地址(OFFSET):變量所在段內的偏移地址;
C.類型(TYPE):變量的類型定義了每個變量所占用的內存字節數,對於DB、DW、DD、DQ、DT類型定義的變量所占用的內存字節數分別是1、2、4、8、10;通常又將DB、DW、DD類型所定義的變量分別成為BYTE類型、WORD類型、DWORD類型變量;
常用標識符的類型值列表:
標識符種類  字節變量  字變量  雙字變量  近標號NEAR  遠標號FAR
TYPE的值     1          2        4          -1           -2
D.長度(LENGTH):變量定義時,一個變量名所定義的變量個數;在含有DUP操作符的變量定義中,變量名所定義的變量個數為定義格式中的重復次數;在其它各種變量定義中,每個變量名所定義的變量個數均為1個;
E.大小(SIZE):變量定義語句中,分配給同一個變量名的所有變量的總的字節數,其值為該變量的類型與長度的成績;
其中,段地址、偏移地址和類型屬性是變量的主屬性,而長度和大小屬性是變量的輔助屬性;
(2).屬性操作符:
操作符    表達式              含義
SEG        SEG 變量名或標號       取出變量名或標號所在段的段地址
OFFSET     OFFSET 變量名或標號    取出變量名或標號所在段內的偏移地址
TYPE       TYPE 變量名或標號      取出變量名或標號的類型(變量所占用的字節數)
LENGTH     LENGTH 變量名          取出變量的長度
SIZE       SIZE 變量名            取出變量的大小
這些操作符不能單獨構成語句,只能作為表達式的組成部分,並且表達式的求值也是在匯編過程中完成的;
6.強制類型轉換操作符PTR
格式:數據類型 PTR 地址表達式
格式中的"數據類型"可以是BYTE、WORD、DWORD、NEAR、FAR;前三種類型是變量的類型,后兩種類型是標號的類型;格式中的表達式可以是變量、標號、其它地址表達式;
PTR操作符的功能是用來重新定義已定義的變量或標號的類型,其作用域只在當前語句中; 例如:
DATA1 DW 02H
MOV BYTE PTR DATA1,AL
這條指令中,是把DATA1的類型轉換為BYTE類型,然后把AL中的內容存放到DATA1的最低一個字節中;作用域只在這條MOV語句中,過了這條語句,DATA1仍然是DW類型,即:DATA1原來的類型並沒有被修改;
7、復合數據類型:
符合數據類型,除了用DUP定義的重復數據類型之外,與C/C++語言一樣,匯編語言中也有結構體類型、聯合類型、記錄類型;
(1).結構體類型:
A.類型定義格式:
結構類型名 STRUC [對齊類型Alignment][,NONUNIQUE]
           Field1 Type1 Exp1
           Field2 Type2 Exp2
           ......
           FieldN TypeN ExpN
結構類型名 ENDS
說明:結構體中的字段名可有可無;若有字段名,則字段名必須唯一,每個字段可獨立存取;若沒有字段名,則通過偏移量來存取;
對齊方式Alignment:定義每個字段的字節對齊邊界,對齊值有1、2、4、8、16字節對齊,值必須是2的冪次方;對齊類似於C/C++中結構體字段的對齊;
NONUNIQUE:要求結構體中的字段必須用全名才能訪問;
結構體中的字段可以有字段名,也可以沒有字段名;有字段名的字段可直接使用該字段名來訪問,沒有字段名的字段可用使用該字段在結構體中的偏移量來訪問;
例如:
PERSON STRUC
       NO   DD ?          ;有名字段,偏移量為0
       NAME DB 10 DUP(?)  ;有名字段,偏移量為4
            DB 1          ;無名字段,偏移量為14
PERSON ENDS
B.結構類型變量的定義:
[變量名] 結構類型名 <[字段值列表]>
字段值列表中的各個字段之間用逗號","分割,字段值的排列順序及類型應該與該結構定義時說明的各個字段相一致;如果結構變量中某個字段的值使用定義結構時說明的缺省值,那么可用逗號來表示;如果所有字段都使用定義結構體時說明的各個字段的缺省值,則可省去字段值列表,只需保留一對尖括號"<>"即可;
例如:
Per1 PERSON <>             ;所有字段都是用默認值
Per2 PERSON <1,'bdx',60>   ;所有字段都重新初始化
Per3 PERSON <2, , 90>      ;第二個字段使用默認值;
C.結構體類型字段的引用:
格式: 結構變量名.字段名
這種引用方式與高級語言中的引用方式完全一致;另外,還可以使用偏移量來訪問某個字段;
方式1:使用字段名直接引用
MOV AX,Per3.NAME
方式2:使用字段的在結構體中的偏移量來引用
LEA SI,Per3   ;取變量Per3對應內存塊的有效地址
MOV AX,[SI+4] ;寄存器相對尋址,4是字段NAME的偏移量
(2).聯合體類型:
A.類型定義格式:
[聯合體類型名] UNION [對齊方式Alignment][,NONUNIQUE]
           Field1 Type1 Exp1
           Field2 Type2 Exp2
           ......
           FieldN TypeN ExpN
[聯合體類型名] ENDS
說明:聯合體類型中的各個字段相互覆蓋,即:同樣的存儲單元被多個不同類型的字段所對應,並且每個字段在聯合體類型中的偏移量都是0;聯合體類型所占用的字節數是其所有字段所占字節數的最大值,即:聯合體所占用的字節數是這個聯合體的所有字段中占用字節數最多的那個字段占用的字節數;
對齊方式Alignment:可用1、2、4、8、16個字節來指定聯合體中各個字段字節的對齊邊界,其缺省的對齊邊界是1字節;還可用使用偽指令ALIGN或EVEN來重新定界,也可使用命令行選項/Zp來定界;
NONUNIQUE:要求聯合體類型中的字段必須使用全名才能訪問;
例如:
DATE UNION
     YEAR  DB 2010
     MONTH DB 07
     DAY   DB 04
DATE ENDS
B.聯合體類型變量的定義:
聯合體類型的變量只能使用第一個字段的數據類型來進行初始化;例如:
DATE1 DATE <2011>   ;定義一個聯合體類型變量DATE1,並使用第一個字段的數據類型進行初始化
DATE2 DATE <'2011'> ;初始化錯誤,只能使用第一個字段的數據類型進行初始化;
C.聯合體類型字段的引用:
格式: 聯合體類型變量名.字段名
例如:
MOV DATE1.YEAR,2012  ;給聯合體類型變量字段賦值
MOV AL,DATE1.MONTH   ;AL=07
MOV BX,DATE1.YEAR    ;BX=2012
MOV DATE1.MONTH,08   ;月份置為8月
(3).記錄類型:
A.類型定義格式:
匯編語言中的記錄類型與高級語言中的記錄類型不同,在匯編語言中,記錄類型是為按照二進制位存取數據提供方便的;記錄類型的說明要用到另一個關鍵字RECORD,格式如下:
記錄名 RECORD 字段[,字段,...]
其中,"字段"代表: 字段名:寬度[=初始值表達式]
說明:記錄名代表該記錄類型;記錄類型可以由多個字段組成,相鄰兩個字段之間用逗號隔開;記錄類型中字段的屬性包括字段名、寬度和初始值;記錄類型中,字段的"寬度"屬性表示該字段所占用的二進制位數,它必須是一個常數,並且所有字段的寬度之和不能大於16(即:<=16);如果記錄類型中所有字段的寬度之和大於8,則系統會自動為該記錄類型分配2字節的空間,否則只分配1個字節的空間;記錄類型的最后一個字段排在所分配空間的最低位,然后對記錄中的字段依次"從右向左"分配二進制位,左邊沒有分完的二進制位自動補0;初值表達式給出的是該字段的缺省值,如果初值超過了該字段所表示的范圍,那么,在匯編時將產生錯誤提示信息,如果某字段沒有初值表達式,則其初值為0;
例1:
COLOR RECORD BLINK:1,BACK:3=0,INTENSE:1=1,FORE:3
該COLOR類型的二進制位分布如下圖所示:

匯編語言---指令格式和基本語法 - 哥哥 - 哥哥
該類型的各個字段寬度為:1、3、1、3,所以,該記錄占用8個二進制位,系統為它分配1個字節;
例2:
FLOAT RECORD DSIGN:1,DATA:8,ESIGN:1,EXP:4
該FLOAT類型的二進制位分布如下圖所示: 
匯編語言---指令格式和基本語法 - 哥哥 - 哥哥
該類型的總寬度是14個二進制位,所以,系統為它分配2個字節的空間;
B.記錄類型變量的定義:
[變量名] 記錄類型名 <[字段值列表]>
說明:變量名就是該記錄類型的變量名,它可缺省,則不能使用符號名來訪問該內存單元;字段值列表是用於給各個字段賦初值,相鄰兩個字段值之間用逗號","隔開,其字段值的排列順序及大小應該按照記錄類型定義時說明的各個字段的順序和大小來排列;如果記錄類型變量的某個字段使用默認值,那么,可用逗號來表示,如果所有字段都是用默認值,則可省去字段值列表,但必須保留一對尖括號"<>";
例如:
COLOR1 COLOR <>, <1,7,0,5>, <1,,0,7>
FLOAT1 FLOAT <1,23H,0,3>, <0,89H,1,5>
C.記錄類型字段的引用:
格式: 記錄類型變量名.字段名
例如: MOV AL,COLOR1.FORE
D.記錄類型的專用操作符:
操作符WIDTH和MASK是專用於記錄類型的操作符,利用它們可用得到記錄類型的不同屬性;
WIDTH:用於返回記錄或其字段的二進制位數,即:記錄類型或記錄類型字段的寬度;書寫格式如下:
WIDTH 記錄名     或     WIDTH 記錄字段名
例如:記錄類型COLOR,那么,WIDTH COLOR的值為8,WIDTH BACK的值為3,WIDTH BLINK的值為1;
MASK:它返回一個8位或16位的二進制數,在該二進制數中,被指定記錄或字段使用的對應位的值為1,否則,其值為0;書寫格式如下:
MASK 記錄名     或     記錄字段名
例如:記錄類型FLOAT,那么,MASK EXP的值為000FH,MASK DATA的值為1FE0H,MASK DSIGN的值為2000H;
記錄字段:記錄字段名是一個特殊的操作符,它本身也是一個操作數,其返回值是該字段移到該字段所在記錄的最低位所需要的位數,即:該字段最低位在記錄中的位置;
例如:記錄類型FLOAT,則有:
MOV CL,EXP     相當於    MOV CL,0
MOV CL,DATA    相當於    MOV CL,5
(4).類型重定義:
已知某一數據類型,程序員可以定義這個數據類型的別名或指針類型.表達這種定義的偽指令是TYPEDEF,其定義形式如下:
新數據類型名 TYPEDEF [位距][PTR] 已知數據類型
其中,"位距"是NEAR、FAR、PROC等;
例如:
CHAR  TYPEDEF BYTE     ;給BYTE類型定義另外一個別名CHAR,C++中就是: typedef BYTE CHAR
PCHAR TYPEDEF PTR CHAR ;定義一個字符指針數據類型PCHAR,C++中就是:typedef PTR CHAR PCHAR,即:typedef char* PCHAR
那么,下面的變量定義就是合法的了:
CH1  CHAR 'ABCDEF'  ;定義一個字符串常量
PCH1 PCHAR CH1      ;定義一個指向字符串常量CH1的變量
這個功能類似於C++語言中的typedef語句;
8.表達式中的操作符:
HIGH(高8位)、LOW(低8位)
SEG(段地址)、OFFSET(偏移量)、TYPE(數據類型)、LENGTH(變量長度)、SIZE(變量容量)
WIDTH(記錄/記錄字段的寬度)、MASK(記錄/記錄字段的屏蔽位),等等;
其中,HIGH和LOW分別用於選取表達式計算結果的高8位和低8位,使用格式如下:
HIGH 表達式      LOW 表達式
9.運算符和操作符的優先級:
優先級: 高 LENGTH、SIZE、WIDTH、MASK、()、[]、.(用於結構字段)、<>(用於記錄類型)
        ↓ PTR、SEG、OFFSET、TYPE、THIS、:(用於段超越前綴)
           *、/、MOD、SHL、SHR
        ↓ HIGH、LOW
           +、-
        ↓ EQ、NE、LT、LE、GT、GE
           NOT
        ↓ AND
           OR、XOR
優先級: 低 SHORT
10.地址表達式:
地址表達式是計算存儲器單元地址的表達式,它可由標號、變量名和由方括號"[]"括起來的基址或變址寄存器組成;其計算結果表示一個存儲器單元的地址,而不是該存儲器單元中的值;
注意:匯編語言中,對地址數值的運算都是以字節為單位的,而不是以數據類型的大小為單位的;例如:
W1 DW 1234H,5678H
則,地址表達式W1+1處的內存單元中的數據是7812H,而不是5678H;W1+1表示W1為起始地址,其下一個字節單元的地址,W1+2表示從地址W1出開始,其后2個字節單元地址;
11.符號定義語句:
在程序中,經常會用到一些常數或數值表達式,並把它們直接寫在指令值,當時當需要修改的時候,就要對它們逐一進行修改,這無疑就增加了維護程序的工作量,而且每個常量或表達式所代表的含義也容易忘記;於是,匯編語言提供了為常量或表達式定義一個符號名的方法;一旦定義了符號名,在指令中就可以直接使用它們了;這個功能就類似於C語言中使用宏定義指令#define定義常量的功能相似,也與C++中使用const關鍵字定義常量的功能相似;
( 1).等價語句EQU
一般格式:
符號名 EQU 表達式
作用:左邊的符號名代表右邊的表達式;
注意:等價語句不會給符號名分配存儲空間,符號名不能與其它符號名重名,即:符號名必須唯一;符號名也不能被重新定義;程序中凡是出現"表達式"的地方,都使用"符號名"來替換;
(2).使用符號名代表常量或表達式
把一個常量或表達式定義成一個具有一定含義的符號名之后,在程序中就可以用該符號名來代表該常量或表達式;例如:
NUMBER EQU 100        ;給緩沖區的長度取一個符號名
BUFF_LEN EQU NUMBER+2
CR EQU 13             ;給"回車"符的ASCII碼定義一個符號名
LN EQU 10             ;給"換行"符的ASCII碼定義一個符號名
(3).用符號名代表字符串
例如:
GREETING EQU 'How are you!'
(4).用符號名代表關鍵字或指令碼
例如:
MOVE EQU MOV   ;給指令碼MOV取另外一個符號名MOVE
COUNTER EQU CX ;給寄存器CX取一個叫做"計數器"的符號名
12.等號語句
匯編語言提供了使用等號"="來定義符號常數的方法,即:可用符號名代表一個常數;一般格式如下:
符號名 = 表達式
數值表達式在匯編時應該可以計算出值,它不能含有向前引用的符號名稱;用等號語句定義的符號名可以被重新定義;可把等號語句看成是高級語言中的一個賦值語句,可以被多次賦值,這一點是與EQU不同的地方;例如:
ABC = 10 + 200*5    ;ABC的值為1010
ABC1 = 5*ABC + 21   ;ABC1的值為5071
COUNT = 1           ;COUNT的值為1
COUNT = 2*COUNT + 1 ;COUNT的值為3
注意:偽指令"="和偽指令"EQU"定義符號名時,凡是在程序中出現符號名的地方,都是用右邊的常量或表達式來替代;
13.標號定義語句
該語句定義一個指定的符號名,該符號名的段地址和偏移地址與下面緊跟存儲單元的相應屬性相同,但是,該符號名的類型是新指定的;
LABEL語句的一般格式如下:
符號名 LABEL 數據類型
常用的數據類型有:BYTE、WORD、DWORD、結構類型、記錄類型、NEAR、FAR;
其中,前五中類型是變量的類型,后面兩種類型是標號的類型;如果格式中的"數據類型"是前面五種類型之一的話,"符號名"就是變量名;如果格式中的"數據類型"是后面的兩種類型之一的話,"符號名"就是標號名;變量名和標號名都具有段地址和偏移地址的屬性;
例如:
WBUFFER LABEL WORD
BUFFER DB 200 DUP(0)
這個LABEL定義語句中,WBUFFER與BUFFER具有完全相同的段地址和偏移地址,但是它們的數據類型不同,目的就是為了使用兩種不同類型的操作來訪問同一塊內存區;
注意:偽指令本身不占用內存空間;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM