在接下來的四篇里將介紹80386的匯編指令及用法,并和8086的指令進(jìn)行比較。
80386的指令集包含了8086/8088,80186,80286的指令集,可以分為幾個大類:數(shù)據(jù)傳送指令,算術(shù)運(yùn)算/邏輯運(yùn)算指令,移位指令,控制轉(zhuǎn)移指令,串操作指令,高級語言支持的指令,條件字節(jié)設(shè)置指令,位操作指令,處理器控制指令和保護(hù)方式指令。高級語言支持指令始于80186,保護(hù)方式指令始于80286,條件字節(jié)設(shè)置指令和位操作指令是80386新增的。
本篇主要介紹數(shù)據(jù)傳送指令,數(shù)據(jù)傳送指令可以分為:通用數(shù)據(jù)傳送,累加器專用傳送,地址傳送,標(biāo)志傳送,分別介紹如下:
A.數(shù)值傳送指令MOV,MOVZX,MOVSX,XCHG,PUSH,PUSHA,PUSHAD,POPA,POPAD,
a.MOV,指令和8086相似,不過它支持32位操作。
b.MOVZX,零擴(kuò)展傳送,格式--MOVZX DST,SRC,表示將源操作送給目的操作數(shù),目的操作數(shù)空出的部分用0填補(bǔ)。
c.MOVSX,符號擴(kuò)展傳送,格式--MOVSX DST,SRC,表示將源操作送給目的操作數(shù),目的操作數(shù)空出的部分用SRC的符號位來填補(bǔ),舉個簡單的例子來演示:
MOV DL,90H;
MOVSX AX,DL;AX=FF90H
MOVZX AX,DL;AX=0090H
MOVSX ESI,DL;ESI=FFFFFF90H
MOVZX ESI,DL;ESI=00000090H
事實(shí)上在8086中也有兩條指令CBW,CWD可以對操作數(shù)進(jìn)行擴(kuò)展。MOVSX可以對有符號數(shù)進(jìn)行擴(kuò)展,MOVZX可以對無符號數(shù)進(jìn)行擴(kuò)展,看看CBW,CWD的用法:
CBW將字節(jié)數(shù)據(jù)擴(kuò)展成字,符號位擴(kuò)展到AH中
CWD將字?jǐn)?shù)據(jù)擴(kuò)展成雙字,符號位放到DX中
MOV AL,70H;
CBW;//AX=0070
CWD;//DX=0000,AX=0070
d.XCHG,功能和8080相同,不過它支持8位,16位,32位操作,下面的語句均是合法的。
XCHG AH,AL
XCHG AX,AL
XCHG ESI,EDI
XCHG ESI,[EBX+EDI+1000H]
e.PUSH,和8086不同的是,它支持立即數(shù)入棧,8位入棧,當(dāng)然還有32位入棧,下面的語句均是合法的。
PUSH AL
PUSH BH
PUSH 100H
PUSH EAX
PUSH EBX
PUSH DWORD PTR [EAX]
f.POP,功能和用法和8086一樣。
g.PUSHA,將8個通用寄存器全部進(jìn)棧,進(jìn)棧順序為:AX,CX,DX,BX,SP,BP,SI,DI,然后SP指針寄存減16,不過SP入棧的內(nèi)容是PUSHA指令執(zhí)行前的內(nèi)容。
h.POPA,8個通用寄存器全部出棧,堆棧指針寄存器不是堆棧中彈出的內(nèi)容,而是加16而得到的,雖然這樣得到的值和從堆棧中彈出來的內(nèi)容一樣,但物理意義不一樣。
i.PUSHAD,將8個32位通用寄存器全部入棧,入棧順序EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI,ESP的內(nèi)容是執(zhí)行指令PUSHAD之前的內(nèi)容
j.POPAD,8個32位通寄存器全部出棧,ESP的內(nèi)容參見h
B.地址傳送指令LEA,LDS,LES,LFS,LGS,LSS
a.LEA,取有效地址,功能,用法與8086相同,不過它支持32位操作。規(guī)則:目的操作必須是16位或32位通用寄存器,當(dāng)目的操作數(shù)是16位時,那么只裝入有效地址的低16位。事實(shí)上LEA指令相當(dāng)于偽指令OFFSET,看例子:
MOV EAX,12345678H
MOV EBX,56784321H
LEA ECX,[EAX+EBX];ECX=99999999H
b.LDS,裝入指針,功能,用法與8086相同,不過它支持32位操作。格式:LDS REG,OPRD。規(guī)則,目的寄存器必須是16位或32位的通用寄存器,OPRD必須是內(nèi)存單元,不可以是立即數(shù)。如果目的寄存器是16位,那么源操作數(shù)OPRD含32位指針;如果目的寄存器是32位,那么源操作數(shù)有48位指針。該指令將目的操作數(shù)OPRD所指向的內(nèi)存單存的4個或6個連續(xù)字節(jié)的內(nèi)容送給助記符指令中指定的DS段寄存器和指令中目的寄存器。比如:
LDS EAX,[1000H];這表明將偏移地址為1000,1001H這兩個字節(jié)單元的內(nèi)容送給段寄存器DS,將偏移地址1002,1003,1004,1005四個字節(jié)單元的內(nèi)容送往EAX。
LDS AX,[1000H];這表明將偏移地址為1000,1001H這兩個字節(jié)單元的內(nèi)容送給段寄存器DS,將偏移地址1002,1003H兩個字節(jié)單元的內(nèi)容送往EAX。
c.LES,同LDS,不過段寄存器是ES。
d.LFS,同LDS,不過段寄存器是FS。
e.LGS,同LDS,不過段寄存器是GS。
h.LSS,同LDS,不過段寄存器是SS。
C.標(biāo)志傳送指令LAHF,SAHF,PUSHF,PUSHFD,POPF,POPFD
a.LAHF,將標(biāo)志寄存器的低8位送至AH中,包括SF,ZF,ZF,PF,CF。
b.SAHF,與i的過程恰好相反
c.PUSHF,將標(biāo)志寄存器的EFLAGS低16位內(nèi)容入棧,和8086相同
d.PUSHFD,將標(biāo)志寄存器EFLAGS的內(nèi)容入棧
e.POPF,將棧頂?shù)囊粋€字彈出,并將它送到標(biāo)志寄存器EFLAGS的低16位
f.POPFD,將棧頂?shù)膬蓚€字彈出,并將它送到標(biāo)志寄存器EFLAGS
D.累加器傳送指令I(lǐng)N,OUT,XLAT
a.IN,和8086相同,但可以輸入一個雙字節(jié),同樣如果端口的范圍位于00H-FFH,可以直接用,如果超出這個范圍,則先要將端口號送至DX,下面的語句是合法的:
IN AL,20H;從20H端口讀入一個字節(jié)
IN AX,20H;從20H端口讀入一個字
MOV DX,0378H
IN EAX,DX;從20H端口讀兩個字節(jié)
b.OUT,和8086相同,但可以輸出一個雙字節(jié),同樣如果端口的范圍位于00H-FFH,可以直接用,如果超出這個范圍,則先要將端口號送至DX,下面的語句是合法的:
OUT 20H,AL;從20H端口輸出一個字節(jié)
IN 20H,AX;從20H端口輸出一個字
MOV DX,0378H
IN EAX,DX;從20H端口輸出兩個字
c.XLAT,查表指令,功能和用法與8086相同,不過基址寄存器用的是EBX,來看看XLAT的實(shí)現(xiàn)過程:XLAT以BX作為基址寄存器,以AL作為變址寄存進(jìn)器對指定的緩沖區(qū)進(jìn)行查表,將AL指定位置的內(nèi)容送往AL,比如說我們在MS-DOS方式寫一個小程序:
C:\>Debug
-A100
MOV BX,0120
SUB AL,AL
MOV DL,AL
MOV AH,2
INT 21
MOV AH,4C
INT 21
INT 20
-E120 ‘ABCDEFGHIJKLLMMDDKDJDK‘
=G100
屏幕上會顯示A,如果AL=3,那么屏幕會顯示D
以上所有的指令均不影響EFLAGS的各標(biāo)志位。