80x86的指令系统

80x86的指令系统可以分为以下6组:

数据传输指令传处理指令

算术指令控制转移指令

逻辑指令处理机控制指令

 

数据传送指令

负责把数据、地址或立即数送到寄存器或存储单元中。可以仔细分为以下5种:

1 通用数据传送指令

MOV传送

MOVSX带符号扩展传送

MOVZX带零扩展传送

PUSH进栈

POP 出栈

PUSHA所有寄存器进栈

POPA所有寄存器出栈

XCHG交换

 

MOV 传送指令

;标准:mov dst,src
;执行操作:(dst)<-(src)
;mov指令的机器语言允许有7种模式
mov mem/reg1,mem/reg2
;操作数必须至少有一个是寄存器
mov reg,data
mov ac,mem
mov mem,ac
;意思是只能通过寄存器和累加器来进行互相交互
mov segreg,mem/reg
;segreg指定段寄存器,但是不能用CS寄存器。因为CS和IP指令只能采用jmp来调用,也就是可以用立即数和普通寄存器给段寄存器赋值。

mov mem/reg,segreg
;mem表示立即数,reg为指定寄存器
mov mem/reg,data
;采用存储器寻址方式。


;data为立即数,reg为指定寄存器,segreg为段寄存器,mem表示存储器也可以说是内存。

说明MOV指令可以在CPU内或CPU和存储器之间传送字或字节。可以从寄存器到寄存器,立即数到寄存器,立即数到存储单元,从存储单元到寄存器等。

注意事项:

立即数不能之间送到段寄存器,需要将立即数送给reg再用reg送到segreg中。

MOV指令的目的操作数(dst)不允许使用立即数,也不允许使用CS寄存器。

除开源操作数是立即数的情况外,两个操作数必须有一个是寄存器,不允许用MOV指令在两个存储单元直接传送数据,也不允许在两个段寄存器间直接传送信息。

例子:

 

;例1
MOV AX,DATA_SEG
MOV DS,AX
;段地址必须通过寄存器传入,例1采用的是用ax来传入

;例2
MOV AL,'E'
;将立即数E的ASCII码送到寄存器AL中

;例3
MOV BX,OFFSET TABLE
;将TABLE的偏移地址送到BX中,如果为数组就是首地址,OFFSET是一个关键字,表示把后面的符号地址传递

;例四
MOV AX.Y[BP][SI]
;将EA(有效地址)=BP+SI+Y的存储内容送给AX寄存器

;例5
MOV EAX,[EBX+ECX*4]
;把有效地址EA=EBX+ECX*4的存储单元的32位内容送给EAX

 

MOVSX带符号扩展传送指令

格式为:MOVSX DST,SRC

执行操作:DST<-符号扩展(SRC)

本指令可以有两种格式:

MOVSX reg1,reg2

MOVSX reg,mem

注意事项:

;指令的操作数可以是8位或16位的寄存器或存储单元的内容而目的操作数必须是16或32位寄存器,传送时把源操作数符号扩展送入目的寄存器。可以是8位扩展到16或32位,也可以是16位符号扩展到32位。

同时MOVSX也不影响标志位的内容。

例子:

 

;例1:
MOVSX   EAX,CL
;把CL寄存器中的8位数,符号扩展为32位数送到EAX寄存器中

;例2:
MOVSX   EDX,[EDI]
;把DS:EDI指定地址的内容16位数符号扩展为32位后送到EDX寄存器中

 

MOVZX 带零扩展传送指令

格式为:MOVZXDST,SRC

执行操作:DST<-零扩展(SRC)

指令可以有两种格式:

MOVZX reg1,reg2

MOVZX reg,mem

注意事项

DST和SRC以及对于标志位的影响都和MOVSX相同,差别只是MOVSX是带符号做符号扩展,而MOVZX的无符号整数是作零扩展

MOVZX和MOVSX的标志是:SRC的操作长度一定要小于目的操作数长度。

例子:
;例1
MOVZX   EX,AL
;把AL中寄存器的八位数,零扩展为16位送到DS寄存器中。

;例2
MOVZX   EAX,DATA
;把DATA单元的16进制数扩展到32位送到EAX寄存器里

PUSH入栈指令

格式为:PUSH SRC

执行操作为:

16位:SP<-SP-2

((SP)+1,(SP))<-(SRC)

;简单来说就是偏移地址往上移2个单位,然后写入一个字给对应的内存单元

 

32位:(ESP)<-(ESP)-4

((ESP)+3,(ESP)+2,(ESP)+1,(ESP))<-(SRC)

;同上,只是把两个字节改为了四个

 

 

POP出栈指令

格式为:POPDST

执行操作:

16位指令:(DST)<-((SP)+1,(SP))

(SP)<-(SP)+2

其实也就是将sp指向的地址和往下一个地址的两个字节的内容整合为字送给16位DST。然后SP段偏移地址再往下移动2个内存单元

32位指令:(ESP)<-(ESP)-4

((ESP)+3,(ESP)+2,(ESP)+1,(ESP))<-(SRC)

同上就是扩大了两倍。

 

PUSH与POP指令综合

格式:

PUSH    reg
PUSH    mem
PUSH    data
PUSH    segreg

POP     reg
POP     mem
POP     segreg

;reg表示指定寄存器,mem为内存,data为立即数,segreg为段寄存器

进出栈的内容可以为字也可以为双字。

 

操作数长度

地址长度

执行的操作

16

16

sp<-sp+_2 字出栈或者进栈

16

32

ESP<-ESP+-2 字出栈或者进栈

32

16

SP<-SP+-4 双字出栈或者进栈

32

32

ESP<-ESP+-4双字出栈或者进栈

PUSH和POP的例子:
PUSH AX;

内存拷贝 java 服务器内存之间 把内存中的数据传送_操作数

 

 

POP AX;

内存拷贝 java 服务器内存之间 把内存中的数据传送_寄存器_02

 

 

 

PUSHA/PUSHAD所有寄存器进栈指令

格式为:PUSHA

或PUSHAD

 

执行操作:

PUSHA:16位通用寄存器依次进栈,进栈次序为:AX,CX,DX,BX指令执行前的SP,BP,SI,DI。指令执行后(SP)<-(sp)-16依然指向栈顶。

PUSHAD:32位通用寄存器依次进栈,进栈顺序为:EAX,ECX,EDX,EBX以及指令执行前的ESP,EBP,ESI和EDI。指令结束后(SP)<-(SP)-32

 

POPA/POPAD所有寄存器出栈指令

格式为:POPA

POPAD

执行操作:

注意事项

POPA:16位通用寄存器依次出栈,出栈次序为:DI,SI,BP,SP,BX.DX.CX.AX。指令执行后(SP)<-(SP)+16 SP指向栈顶。SP的出栈只是修改了指针使其后面的BX能出栈,而堆栈中原先PUSHA指令存入的SP的原始内容被丢掉,并没有真正的送到SP寄存器中。

POPAD:32位寄存器依次出栈,次序为EDI,ESI,EBP。。。。同上。(ESP)<-(ESP)+32和POPA一样。

例子:
PUSHAD

内存拷贝 java 服务器内存之间 把内存中的数据传送_出栈_03

 

 

 

XCHGEAX,EBX

就是EAX和EBX寄存器的内容互换

 

2 累加器专用传送指令

IN输入

OUT输出

XLAT换码

这一组指令只能用于累加器EAX,AX或AL来传送信息

IN指令

长格式:
IN  AL,PORT(字节)

IN  AX,PORT(字节)

IN  EAX,PORT(字节)
短格式:
IN  AL,DX
IN  AX,DX
IN  EAX,DX
执行的操作:

(AL)<-(DX))

(AX)<-(DX+1,DX)

(EAX)<-(DX+3,DX+2,DX+1,DX)

OUT指令

长格式:
OUT PORT,AL
OUT PORT,AX
OUT PORT,EAX

 

短格式:

OUT DX,AL
OUT DX,AX
OUT DX,EAX
执行的操作:

同上就是反着而已

####

综述IN指令和OUT指令

在80x86里,所有的I/O端口和CPU之间的通信都由IN和OUT来完成,其中IN完成从I/O到CPU的信息传送,而OUT则完成从CPU到I/O的信息传送。

CPU只能采用累加器(AL,AX,EAX)来接受和发送信息。

外部设备最多可有65536个I/O端口,端口号为0000-FFFFH,其中前256个端口(0-FFH)可以在指令中直接设定,也就是采用长格式的PORT,这时的机器指令用两个字节表示,第二个字节就是端口号,所以在使用长格式时可以直接在指令中设置端口号,但是只能作用与外设的前256个端口。

当端口号≥256时,只能使用短格式,此时必须先把端口号放到DX寄存器中(端口号可以从0000-FFFFH)然后再用IN或OUT指令来传送信息。这里的端口号和DX的内容都是地址,而且在短格式的时候DX内容就是端口号本身,不需要用任何段寄存器来修改它的值。

IN和OUT指令提供了双字,字和字节三种使用方式,选择那一种取决于外设端口宽度,如果端口宽度只有8位,则只能用字节指令传送信息。

例子:
;例1
IN  AX,28H
MOV DATA_WORD,AX
;把端口28的内容经过ax送到存储单元DATA_WORD中

;例2
MOV DX,3FCH
IN  EAX,DX
;从端口3FCH送一个双字到EAX中

;例3
OUT 5,AL
;将AL寄存器输入一个字节到端口5中

 

XLAT换码指令

格式
XLAT    OPR 
;或
XLAT
执行的操作:

16位指令:(AL)<-((BX)+(AL))

32位指令:(AL)<-((EBX)+(AL))

内容:

经常需要把一种代码转换为另一种代码。例如,把字符的扫描码转换为ASCII码。

在使用XLAT前需要建立一个字节表格,表格的首地址提前存入BX或EBX寄存器,需要转换的代码应该是相对于表格首地址的位移量也提前存放在AL寄存器,表格的内容则是需要转换的代码,执行指令后就可以在AL中得到转换后的代码。指令采用XLAT或者XLAT OPR任何一种都可以。在使用XLAT OPR的时候OPR为表格是首地址,但是OPR只是为了提高可读性,指令执行时就会使用预先存入BX或EBX中的表格 首地址。

相当于就是将首地址BX然后再加上偏移地址AL的值再加上段寄存器的值然后将内存单元的值替换给AL中

也就是MOV AL,[address]

内存拷贝 java 服务器内存之间 把内存中的数据传送_操作数_04

 

 

 

 

3地址传送指令

LEA(load effective address)有效地址传送寄存器

LDS(load DS with pointer) 指针送寄存器和DS

LES(load ES with Pointer)指针送寄存器和ES

LFS(load FS with Pointer)指针送寄存器和FS

LGS(load GS with Pointer)指针送寄存器和GS

LSS(load SS whth Pointer)指针送寄存器和SS

这一套指令把地址送到指定寄存器

 

LEA有效地址送寄存器指令

格式:
LEA REG,SRC
执行的操作:

(REG)<-SRC也就是把源操作数的有效地址送到指定的寄存器中

;reg为指定寄存器

指令的目的操作数可以使用16/32位寄存器但是不可以使用段寄存器。src操作数可使用除立即数和寄存器外的任一种存储器寻址方式。

由于存在操作数长度和地址长度的不同,该指令执行的操作如下(该指令不影响标志位)

操作数长度

地址长度

执行的操作

16

16

计算的16位有效地址存入16位目的寄存器

16

32

计算的32有效地址,截取低16位存入16位目的寄存器

32

16

计算的16有效地址,零扩展后存入32位目的寄存器

32

32

计算的32位有效地址存入32位目的寄存器

例子:
;例1
;假设(BX)= 0400H,(SI)=003CH
LEA BX,[BX+SI+0F62]
;执行后BX=0400+003C+0F62=139EH
;这里的BX得到的是有效地址,而不是该存储单元的内容
MOV BX,[BX+SI+0F62]
;这个指令就是将偏移地址位139E单元的内容而不是偏移地址

 

;例2
LEA BX,LIST
MOV BX,OFFSET LIST
;这两条指令都是把LIST的地址送到BX中
;而MOV执行的指令会比LEA的执行速度快,
;但是OFFSET指令只能与简单的符号地址相连
;不能和诸如LIST[SI]或[SI]等复杂操作数相连
;所以虽然mov BX,OFFSET LIST比LEA快,但是使用LEA还是有必要

 

LDS、LES、LFS、LGS和LSS指针送寄存器和段寄存器指令

格式以LDS为例为:
LDS REG,SRC
    ;其它指令格式与LDS指令格式相同
执行的操作:
(REG)<-(SRC)
(SREG)<-(SRC+2) 或   (SREG)<-(SREG+4)
;SREG表示为指定的段寄存器

 

这套指令的SRC只能采用存储器寻址方式,根据任一种存储器寻址方式找到一个存储单元。当指令指定的是16位寄存器时,把该存储单元中存放的16位偏移地址装入该寄存器中,然后把(SRC+2)中的16位数装入指定的段寄存器中。

当指定的是32位寄存器时,把该存储单元中存放的32位偏移地址装入该寄存器,然后把(SRC+4)中的16位数装入指令指定的段寄存器中。

这套指令的目的寄存器不能使用段寄存器,LFS、LGS和LSS只能用于386和后续的。

比如LDS指定的寄存器就是DS。

例子:
;例1
LES DI,[BX]
;假设 (DS)=B000H,(BX)=080AH,(0B080AH)=05AEH,(0B080CH)=4000H
;则执行指令后(DI)=05AEH,(ES)=4000

 

 

标志寄存器传送指令

LAHF(load AH with flags)标志送AH

SAHF(storeAHinto flags)AH送标志寄存器

PUSHF/PUSHFD(push the flags or eflags)标志进栈

POPF/POPFD(pop the flags or eflags)标志出栈

 

LAHF 标志寄存器送AH指令

格式为:

LAHF

执行的操作:

(AH)<-(FLAGS的低字节)

SAHFAH送标志寄存器指令

格式:

SAHF

执行的操作:

(FLAGS的低字节)<-(AH)

PUSHF/PUSHFD标志进栈指令

格式:

PUSHF/PUSHFD

操作:

PUSHF:

(sp)<-(sp)-2

((sp+1),(sp))<-(flags)

PUSHFD:

(ESP) <-(ESP)-4

((ESP+4)....,(ESP))<- (EFLAGS AND 0FCFFFFH)

 

POPF/POPFD标志出栈指令

格式:

POPF

POPFD

操作:

POPF:

(FLAGS)<-((SP)+1,(SP))

(SP)<-(SP)+2

POPFD:

(EFLAGS)<-((ESP)+3,...,(ESP))

(ESP)<-(ESP)+4

总结:

这一套指令中的LAHF和PUSHF/PUSHFD不影响标志位,SAHF和POPF/POPFD则由装入的值来确定标志位的值,但POPFD指令不影响VM,RF,IOPL,VIF和VIP的值。

 

 

类型转换指令

CBW(convert byte to word)字节转换为字

CWD/CWDE(convert word to double word)字转换为双字

CDQ(convert double to quad)双字转换为4字

BSWAP(byte swap)字节交换

CBW字节转换为字

格式:
CBW 
;就是一个单指令
执行操作:

AL的内容符号扩展到AH形成AX中的字。

如果AL中的最高有效位位0则(AH)=0;

如果(AL)的最高有效位为1,则(AH)=0FFH

;也就是加起来要让首位为1表示负数就好。

CWD/CWDE字转换为双字指令

格式:
CWD
执行的操作:

将AX的内容符号扩展到DX,形成DX:AX中的双字。

如果AX的最高有效位为0,则(DX)=0

如果AX的最高有效位为1,则(DX)=0FFFFH

格式2:
CWDE
执行的操作:

AX的内容符号扩展到EAX,形成EAX中的双字

CDQ双字转换到4字节

格式:

CDQ

执行的操作:

EAX的内容符号扩展到EDC,形成EDX:EAX中的4字。

BSWAP 字节交换指令

格式:

BSWAPr32

该指令只能针对486和后继机型,r32指32位寄存器

执行的操作:

使指令指定的32位寄存器的字节次序变反。

1、4字节互换,2、3字节互换。