學習指令關注:
- 指令的匯編格式
- 指令基本功能
- 指令支持的尋址方式
- 指令執行對標志位的影響
- 指令的特殊要求
數據傳送類指令
- 通用數據傳送指令:MOV、XCHG、PUSH、POP
- 累加器專用傳送指令:IN、OUT、XLAX
- 地址傳送指令:LEA、LDS、LES
- 標志寄存器傳送指令:LAHF、SAHF、PUSHF、POPF
- 符號擴展指令:CBW、CWD
除了SAHF和POPF指令外,均不影響標志位
通用數據傳送指令MOV
格式:MOV DST,SRC;
(DST)<--(SRC)
數據傳輸規則:
非法指令主要現象:
- 兩個操作數的類型不一致,或者不確定;
MOV [BX][SI],1;
兩個操作數類型不明確MOV BP,AL;
兩操作數類型不一樣
- CS不能作為目的操作數(不能顯示地修改),DX不能作為存儲器尋址的寄存器
- 傳送方向錯誤
后續的雙操作數指令一般也是這樣規定指令的
數據交換指令XCHG(exchange)
格式:XCHG OPR1,OPR2;
(OPR1)<-->(OPR2) 兩操作數值交換
注意:
- 遵守數據傳輸規則
- 兩個操作數都不能使用段寄存器和IP,也不能使用立即數
換碼指令XLAT(查表指令)
格式:XLAT
或XLAT OPR;
(DS:[BX+AL])->AL (OPR是為了提高可讀性)
可用於將一種代碼轉換為另外一種代碼
使用方法:
- 先在數據段中建立一張字節表格(長度不超過256,即2^8),表格的內容是要換取的代碼
- 表格的首地址送寄存器BX
- 要換取的對應編碼相對於表格首地址的位移量送寄存器AL
- 執行XLAT,AL中即為轉換后的編碼
堆棧操作
堆棧是主存中一塊連續的存儲區域,常用於數據的暫存、交換、子程序的參數傳遞等場合。
堆棧操作按照后進先出原則。
- 在8086系統里,堆棧所在的段為堆棧段,最大空間為64KB。
- 段地址由SS寄存器指示
- SP始終指示棧頂單元
- 8086系統從較大地址開始分配和使用(其他段地址從小地址開始)
SSEG SEGMENT STACK;堆棧段開始
DW 100 DUP(?) ;大小為100字
SSEG ENDS ;堆棧段結束
程序裝入時,操作系統將SSEG的段基址置入SS,堆棧段的字節置入SP,即200(0C8H)
如果未定義堆棧段,用戶程序裝入內存時:
ES,DS指向PSP(Program Segment Prefix 程序段前綴區);SS指向用戶程序區;CS指向用戶代碼段;(SP)=0000H指向64KB存儲器尾部
對於8086系統堆棧操作:
-
進棧操作:PUSH SRC
- 執行:(SP) <- (SP)-2; ((SP)+1,(SP)) <- (SRC);
-
出棧出棧:POP DST
- 執行:(DST) <- ((SP)+1,(SP)); (SP) <- (SP)+2;
注意:
- 對於8086系統堆棧操作只支持字為單位的操作
- 不支持立即尋址
- CS不能作為目的操作數
地址傳送指令
-
有效地址送寄存器指令:
LEZ REG, SRC; (REG) <- SRC
-
指針送寄存器和DS指令
LDS REG,SRC; (REG) <-(SRC), (DS) <- (SRC+2)
取兩個字分別送往寄存器和DS
-
指針送寄存器和ES指令
LES REG, SRC; (REG) <- (SRC), (ES) <- (SRC+2)
注意:
- REG不能為段寄存器
- SRC必須為存儲器尋址方式
標志寄存器傳送指令
操作數都隱藏
-
標志送AH指令:LAHF ; (AH) <- (FLAGS低字節)
-
AH送標志寄存器指令:SAHF; (FLAGS低字節) <- (AH)
-
標志進棧指令:PUSHF; (SP) <- (SP)-2, ((SP)+1, (SP)) <- (FLAGS)
-
標志出棧指令:POPF; (FLAGS)<- ((SP)+1,(SP)) , (SP)<-(SP)+2
POPF,PUSHF可用於子程序中,分別用來恢復主程序標志與保存主程序標志
類型轉換指令(符號位擴展指令)
- CBW; (AL)->AX 將字節擴展為字
- CWD; (AX)->(DX,AX) 將字擴展為雙字
操作數隱含,擴展為符號位擴展。
若(AX) = BA45H
CWD; (DX)=FFFFH,(AX)=BA45H
CBW; (AX)=0045H
關於無符號擴展,只要將高半部分清0即可,可以通過MOV來實現
算法運算類指令
加法指令
- 加法指令:ADD DST,SRC ;(DST)<-(DST)+(SRC)
- 帶進位加法:ADC DST,SRC ;(DST)<-(DST)+(SRC)+CF
- 加1指令:INC OPR
注意:
- 加法指令影響狀態標志位,但INC指令不影響CF標志位
- 支持的操作數類型和MOV同,但操作數不能為段寄存器
減法指令
- 減法指令:SUB DST,SRC ;(DST)<-(DST)-(SRC)
- 帶借位減法:SBB DST,SRC ;(DST)<-(DST)-(SRC)-CF
- 減一指令:DEC OPR ;(OPR)<-(OPR)-1
- 求補指令:NEG OPR ;(OPR)<-0-(OPR)
- 比較指令:CMP OPR1,OPR2 ;(OPR1)-(OPR2)
注意:
- 減法指令影響狀態標志位,但DEC指令不影響CF標志位
- 減法指令對標志位的影響和加法指令不同。詳細看
XYZW均為已定義的雙字數據,用指令序列實現:
W<-X+Y+24-Z
DATA SEGMENT X DD 778899AAH Y DD 9ABCDEF0H Z DD 56789ABCH W DD ? DATA ENDS CODE SEGMRNTma ASSUME CS:CODE,DS:DATA START:MOV AX,DATA MOV DS,AX MOV AX,WORD PTR X MOV DX,WORD PTR X+2 ADD AX,WORD PTR Y ;X+Y低字部分 ADC DX,WORD PTR Y+2;X+Y高字部分 ADD AX,24 ADC DX,0 SUB AX,WORD PTR Z SBB DX,WORD PTR Z+2 MOV WORD PTR W,AX MOV WORD PTR W+2,DX ;結構存入W
乘法指令
- 無符號數乘法指令:MUL SRC
- 有符號數乘法指令:IMUL SRC
執行操作:
(根據SRC類型判斷執行哪種操作,結果為雙倍字長)
- 字節操作:(AX)<-(AL)X(SRC)
- 字操作:(DX,AX)<-(AX)x(SRC)
注意:
-
SRC若為存儲器操作數時,注意ptr明確類型;SRC不能為立即數和段寄存器
-
除了CF與OF外,對其他標志位沒有定義(執行后標志是任意的,不可預測)
-
乘法指令對CF/OF的影響:(高半位有無有效數字)
MUL指令:\(CF,OF=\left\{\begin{array}{rcl}00 &乘積的高一半為0\\11&否則\end{array}\right.\)
IMUL指令:\(CF,OF=\left\{\begin{array}{rcl}00 &乘積的高一半是低一半的符號擴展\\11&否則\end{array}\right.\)
除法運算
- 無符號數除法運算:DIV SRC
- 有符號數除法運算:IDIV SRC
執行操作:(被除數是除數的雙倍)
-
字節操作:
(AL)<-(AX)/(SRC)的商
(AH)<-(AX)/(SRC)的余數
-
字操作
(AX)<-(DX,AX)/(SRC)的商
(DX)<-(DX,AX)/(SRC)的余數
注意:
- SRC若為存儲器操作數時,注意ptr明確類型;SRC不能為立即數
- 對所有的狀態標志位均無定義
- 兩N位數相除,應首先把被除數符號擴展為2N位
位運算類指令
邏輯運算指令
- 非:NOT OPR
- 與:AND DST,SRC
- 或:OR DST,SRC
- 異或:XOR DST,SRC
- 測試:TEST OPR1,OPR2 ;(OPR1)與(OPR2)
注意:
- NOT指令不影響標志位;除了NOT外,其他均影響
- CF,OF標志位清0;SF,PF,ZF根據運算結果的特征設置;AF無定義
應用:
-
OR:有選擇地使操作數置1
-
AND:有選擇地清0
-
TEST:位測試,與條件轉移指令一起完成對特定位的判斷,實現相應的程序轉移
判斷偶數:
TEST AL,1 ;若為0則為偶數,則ZF=1 JZ EVEN
-
XOR:
- 有選擇地取反(和1異或取反,和0異或不變)
- 寄存器清0(與自身進行邏輯異或,且執行速度快)
移位指令
-
邏輯左移:SHL OPR,CNT
CF<-左 右<-0
-
邏輯右移:SHR OPR,CNT
0->左 右->CF
-
算術左移:SAL OPR,CNT
CF<-左 右<-0
-
算術右移:SAR OPR,CNT
左->左 右->CF
-
循環左移:ROL OPR,CNT
CF<-左 右<-左
-
循環右移:ROR OPR,CNT
右->左 右->CF
-
帶進位循環左移:RCL OPR,CNT
CF<-左 右<-CF(初始)
-
帶進位循環右移:RCR OPR,CNT
CF(初始)->左 右->CF
操作數:
- OPR可用除立即數以外的任何尋址方式
- \(\left\{\begin{array}{rcl}CNT=1,&SHL&OPR,1\\CNT>1,&MOV&CL,CNT\\&SHL&OPR,CL\end{array}\right.\)
狀態標志位:
-
CF=移除的值
-
\(OF=\left\{\begin{array}{rcl}1&CNT=1時,最高有效位的值發生變化\\0&CNT=1時,最高有效位的值不變\end{array} \right.\)
當CNT>1時,OF不確定
-
除此之外,移位指令SF、ZF、PF根據移位結果設置,AF無定義
-
循環移位指令:不影響SF、ZF、PF、AF
用移位指令實現:AX<-(AX)x10
SHL AX,1 MOV BX,AX SHL AX,1 ;AX<-4(原AX) SHL AX,1 ;AX<-8(原AX) ADD AX,BX ;AX<-(8AX)+(2AX)
將DX,AX中32位數值左移一維
SHL AX,1 RCL DX,1
表達式計算(應用)
X、Y、Z、V、W均為16位有符號數,計算W<-(V-(X*Y+Z-1234))/X
MOV AX,X IMUL Y ;X*Y MOV CX,AX MOV BX,DX ;(BX,CX)為X*Y MOV AX,Z CWD ;(DX,AX)為Z ADD CX,AX ADC BX,DX ;(BX,CX)為X*Y+Z SUB CX,1234 SBB BX,0 ;(BX,CX)為X*Y+Z-1234 MOV AX,V CWD ;(DX,AX)為V SUB AX,CX SBB DX,BX ;(DX,AX)為V-(X*Y+Z-1234) IDIV X ;(V-(X*Y+Z-1234))/X,商在AX,余數在DX MOV W,AX ;保存結果
轉移控制類指令
指令尋址方式(確定下一條將要執行指令地址的方法)
-
順序尋址
-
跳轉尋址:通過轉移控制類指令實現(主要是改變CS:IP的值)
如何確定轉移控制類指令的轉向地址?
-
直接尋址(用標號表達)
指令代碼中直接給出地址差(目標地址相對於當前ip的位移量),將要轉移到的目標地址就是當前IP值加上地址差。
-
間接尋址方式(用存儲器或存儲器操作數表達)
代碼中指示寄存器或存儲單元,目標地址從中獲得
-
根據跳轉范圍不同,采用不同的轉移方式:
-
段內尋址
-
近轉移(near)
-
在當前代碼64kB范圍內注意
-
不需要修改CS段地址,只要改變IP偏移地址
-
-
短轉移(short)
- 轉移范圍可以用一個字
-
-
段間尋址
遠轉移(far)
- 在1MB范圍內
- 需要更改CS段地址和IP偏移地址
- 目標地址必須用一個32位數表達,即邏輯地址
實際編程過程中,匯編程序會選擇處理轉移方式,也可以人為規定。
無條件轉移指令
JMP OPR; 程序無條件轉向OPR指令的目標地址開始執行指令
JMP 指令支持段內、段間轉移:
-
段內轉移
JMP 標號
-
IP<-(IP)+標號(IP值的偏移量)
-
(CS)不變
-
-
段間轉移
JMP FAR PTR 標號
- (IP)<-標號轉移地址
- (CS)<-標號段地址
條件轉移指令
有二十多個,將Jcc當做條件轉移指令的一個統稱:
JCC label;條件滿足,發生轉移
-
若轉移:IP<-IP+8位位移量;否則順序執行
-
只支持短轉移
-
不影響標志位,但要利用標志位
根據利用的標志位不同,分為4種情況:
-
根據單個條件標志的設置情況轉移
測試條件 JZ(JE) ZF=1 JNZ(JNE) ZF=0 JS SF=1 JNS SF=0 JO OF=1 JNO OF=0 JP PF=1 JNP PF=0 JC CF=1 JNC CF=0 -
測試CX的值為0則轉移
JCXZ OPR ;(CX)=0
-
比較兩個無符號數,根據比較結果轉移
指令 轉移條件 說明 JA/JNBE OPR CF=0且ZF=0 X>Y時,轉移 JAE/JNB OPR CF=0或ZF=1 X>=Y時,轉移 JNAE/JBOPR CF=1且ZF=0 X<Y時,轉移 JNA/JBE OPR CF=1或ZF=1 X<=Y時,轉移 -
比較兩個有符號數,根據比較結果轉移
指令 轉移條件 說明 JG/JNLE OPR SF=OF且ZF=0 X>Y時,轉移 JGE/JNL OPR SF=OF或ZF=1 X>=Y時,轉移 JNGE/JL OPR SF!=OF且ZF=0 X<Y時,轉移 JNG/JLE OPR SF!=OF或ZF=1 X<=Y時,轉移
循環類指令
-
循環指令:
LOOP OPR
;測試條件:(CX)!=0 -
為0(相等)循環指令:
LOOPZ(LOOPE) OPR
;測試條件:ZF=1且(CX)!=0 -
不為零(不相等)循環指令:
LOOPNZ/LOOPNE OPR
;測試條件:ZF=0且(CX)!=0
執行步驟:
(CX)<-(CX)-1
- 檢測是否滿足測試條件,如果滿足則
(IP)<-(IP)+8
位位移量,循環;不滿足則退出循環,順序執行。
注意:
-
CX
為隱含計數器,存放循環次數 -
只支持短轉移
-
使用LOOPZ/LOOPE,LOONZ/LOOPNE指令來控制循環時,既有計數(CX)控制又有條件(ZF)控制。有兩種可能會結束循環。所以一般應用在循環結束后用條件轉移指令分開這兩種情況,分別處理。
MOV CX,10
L1: ...
...
LOOP L1 ;L1到LOOP指令之間指令序列將重復執行10次
指令"MOV CX,10"稱為"裝載循環計數器",必須在循環前執行;若在循環中執行會造成死循環
計算1+2+3……+100,結果保存到SUM中
XOR AX,AX;累加器清0 MOV BX,1 ;BX<-1 MOV CX,100 AGAIN:ADD AX,BX INC BX LOOP AGAIN MOV SUM,AX
子程序調用和返回指令
子程序是完成特定功能的一段程序
當主程序執行這個功能時,采用CALL調用指令轉移到子程序起始處;完成子程序后,采用RET指令返回到主程序繼續執行(利用堆棧保存返回地址)
子程序定義偽指令:
子程序名 PROC 屬性
... ;子程序體
子程序名 ENDP
- 子程序名:子程序入口的序號地址,子程序名應為合法的標識符,子程序名不能與同一源程序中的標號、變量名、其他子程序名等相同
- 屬性:類型屬性(NEAR(缺省),FAR)
-
段內調用與返回
-
段內直接調用
CALL 子程序名
;NEAR屬性操作:
- (SP)<-(SP)-2
- (SS:SP)<-(IP)
- (IP)<-子程序入口偏移地址
-
段內返回
RET
;按NEAR屬性返回操作:
- (IP)<-(SS:SP) ;從堆棧中取出返回地址
- (SP)<-(SP)+2
-
帶參數返回
RET n
;帶參數返回操作:
- (IP)<-(SS:SP) ;從堆棧中取出返回地址
- (SP)<-(SP)+2+n;調整棧頂位置,回到之前的值
-
-
段間調用與返回
-
段間調用
CALL 子程序名
操作:
- (SP)<-(SP)-2
- (SS:SP)<-(CS) ;入棧
- (SP)<-(SP)-2
- (SS:SP)<-(IP) ;入棧
- (IP)<-子程序入口的偏移地址
- (CS)<-子程序入口的段地址
-
段間返回
RET
;按FAR屬性返回- (IP)<-(SS:SP)
- (SP)<-(SP)+2
- (CS)<-(SS:SP)
- (SP)<-(SP)+2
-
ZEROBYTES PROC
PUSH AX
PUSH CX ;保護現場
XOR AX,AX ;AX清0
MOV CX,128 ;循環次數CX
ZEROLOOP: MOV [BX],AX ;將BX所對應的地址單元清0
ADD BX,2 ;修改地址
LOOP ZEROLOOP
POP CX ;恢復現場
POP AX
ZEROBYTES ENDP
中斷與中斷返回指令
中斷指令有三條:INT、IRET、INTO
8086CPU支持256個中斷,每個中斷用一個8位二進制編碼標識(即中斷類型碼,也稱中斷向量號)
中斷向量:中斷服務程序的入口地址(首地址),為含有段地址CS和偏移地址IP的32位邏輯地址。
中斷向量與中斷向量號的區別?
與子程序不同,中斷指令程序不能用中斷程序名標識中斷地址,因為中斷有隨機性。
中斷指令是統一管理的。
8086系統從物理地址0000H開始集中存放個中斷向量。
- 按照中斷類型碼從小到大的順序依次存放
- 每個中斷向量占4個字節(32位),采用小端方式存儲,其中高字為段地址,低字為偏移地址
- 256個中斷占1KB區域(256 * 4=210 字節)即中斷向量表
- 類型碼為N的中斷向量存放的物理地址為4N
中斷指令:INT n
執行操作:
(SP)<-(SP)-2
((SP)+1,(SP))<-(FLAGS)
(SP)<-(SP)-2
((SP)+1,(SP))<-(CS)
(SP)<-(SP)-2
((SP)+1,(SP))<-(IP)
(IP)<-(n*4)
(CS)<-(n*4+2)
中斷返回指令:IRET
執行操作:
(IP)<-((SP)+1,(SP))
(SP)<-(SP)+2
(CS)<-((SP)+1,(SP))
(SP)<-(SP)+2
(FLAGS)<-((SP)+1,(SP))
(SP)<-(SP)+2
注意:
- n(0~255)是中斷類型。由於類型碼為N的中斷向量存放的物理地址為4N,因而能找到它在中斷向量表對應的中斷向量,即段地址:偏移地址
- INT會清零IF和TF,但不影響其他標准位
- IRET影響標志位由堆棧中取出的值確定
一個指令:INT proc ;proc為23H
如何手動存儲CS:IP值?
XOR AX,AX ;AX清零 MOV DS,AX MOV SI,34H*4 ;DS:SI = 0:34H*4 該中斷類型的邏輯地址 MOV WORD PTR [SI],offset proc MOV WORD PTR [SI+2],SEG
溢出中斷指令INTO
功能: 檢測OF標志位
- OF=1時產生中斷類型為4的中斷
- OF=0時不起作用
指令完成操作(中斷類型碼為4):
- 標志寄存器入棧
- 斷點地址入棧,CS先入,然后IP入
- 從中斷向量表中獲取中斷服務程序入口地址(
IP<-(0:11H,0:10H) CS<-(0:12H,0:13H)
)
處理機控制指令
用於修改標志寄存器的標志位或控制CPU的動作
- 標志位操作指令完成標志位的復位,置位等操作
- 外部同步指令用於控制CPU,不影響標志位
標志位操作指令格式 | 操作 |
---|---|
STC | CF<-1 |
CLC | CF<-0 |
CMC | CF取反 |
STD | DF<-1 |
CLD | DF<-0 |
STI | IF<-1,開中斷 |
CLI | IF<-0,關中斷 |
外部同步指令:
- 處理器暫停指令HLT:使處理器處於暫停,只有復位信號(RESET)、外部中斷請求(NMI、INTR)可使其退出;常用於等待中斷或多處理機的同步操作
- 處理機等待指令WAIT:處理檢測\(\overline{\text{TEST}}\) 引腳信號。\(\overline{\text{TEST}}\) 為高電平時處理器空轉;\(\overline{\text{TEST}}\) 為低電平時,處理器退出中轉,執行后續操作
- 空操作NOP:占一個指令周期,用於調整延時