8086指令系统
8086指令系统
首先定义出要用的符号
OPRD | 泛指各种类型的操作数 |
---|---|
mem | 存储器操作数 |
acc | 累加器操作数 |
dest | 目标操作数 |
src | 源操作数 |
disp | 8位或16位偏移量,可用符号地址表示。 |
DATA | 8位或16位立即数 |
port | 输入输出端口 |
[ ] | 表示存储器操作数,方括号内表示数据的偏移地址 |
数据传送指令
数据传送指令按功能分为四小类:通用数据数据传送指令,目标地址传送指令,标志传送指令,输入输出指令。
通用传送指令
通用数据传送指令包括一般传送指令mov,堆栈操作指令push或pop,交换指令xchg,查表转化指令xlat和字位扩展指令。
一般传送指令MOV
指令格式及操作:mov dest,src
,这里,dest表示目标操作数,src表示源操作数。指令的功能是将一个操作数从源地址传送到目标地址,而源地址中的数据保持不变。
指令中的操作数可以是8位,也可以是16位,一次传送的数据到底是字节还是字取决于指令中涉及的寄存器是8位还是16位的。
(1)寄存器与寄存器或寄存器与段寄存器之间的传送,例如
mov bx,si ;将变址寄存器si中的内容送到基址寄存器bx
mov ds,ax ;将累加器ax中的内容送到段寄存器ds
mov al,cl ;将通用寄存器cl中的内容送到al
(2)寄存器与存储器之间的传送。mov指令可以在寄存器和存储器之间进行数据传送,若传送的是字操作符,那么 将对连续两个存储器进行存取,且寄存器的高8位对应存储器的高地址单元,寄存器的低8位对应存储器的低地址单元。
例如:若有DS=6000H,SS=8000H,AX=1234H,BX=1200H,DI=0383H,BP=1020H则有
mov [bx],ax ;将ax的内容送到内存单元,其中[61200H]=34H,[61201H]=12H
mov cl,[bp][di] ;将堆栈段中偏移地址为BP+DI=13A3H单元的内容送到CL,即物理地址为813A3H单元的内容送到CL
mov ax,[6000H] ;将DS段的6000H和6001H两个单元的内容送ax
(3)立即数到寄存器的传送
mov al,5 ;将立即数5送到累加器al
mov bx,3078h ;将立即数3078h送寄存器bx
(4)立即数到存储器的传送
mov byte ptr[bp+si],5 ;将5送到堆栈段中偏移地址为BP+SI所指的单元中。
mov word ptr[bx],1005h ;将1005h送数据段中偏移地址为BX和BX+1两单元。
(5)存储器与段寄存器之间的传送
mov ds,[1000h] ;将数据段中偏移地址为1000h字单元内容送到数据段寄存器ds
mov [bx],es ;将附加段寄存器es内容送到数据段中bx所指向的字单元
指令对操作数的要求
-
mov指令中两个操作数字长必须相同,两个操作数可同为字节数或同为字操作数。
-
两个操作数不能同时为存储器操作数,若要在两个存储器单元之间进行数据传送,需用两条mov指令实现。
-
不能用立即数直接给段寄存器赋值,要实现此功能,需使用两条mov指令。
-
两个操作数不能同时为段寄存器,同样,要实现段寄存器到段寄存器的数据传送,需要两条mov指令。
-
一般情况下,指令指针IP及代码段寄存器的内容不通过mov指令修改,即它们不能作为目标操作数,但可以作为源操作数。
-
虽然许多指令的执行都对状态寄存器FLAGS的标志位产生影响,但通常情况下,FLAGS整体不能作为操作数。
例如:把内存中首地址为MEM1的200个字节送到首地址为MEM2的区域中。
题目分析:两个内存单元中的数据传送需要两条MOV指令实现,通过循环实现。
mov si,offset mem1 ;源数据块首地址(偏移地址)送入SI
mov di,offset mem2 ;目标首地址送入DI
mov cx,200 ;数据库长度送入cx,即=循环次数cx
next: mov al,[si] ;源数据块中当前字节送入AL
mov [di],al ;AL内容送目标地址,完成一个字节的传送
inc si ;SI+1,修改原地址指针
inc di ;DI+1,修改目标地址指针
dec cx ;CX-1,修改循环次数
jnz next ;若循环次数CX不等于0,则转移到next处
hlt ;暂停
堆栈操作指令PUSH和POP
(1)堆栈的概念。堆栈是内存中一个特定的区域,用以存放寄存器或存储器中暂停不用又必须保存的数据。它在内存中所处的段称为堆栈段,其段地址放在堆栈寄存器SS中。可以将堆栈看作是一个小存储器,但不能任意存取,必须遵守以下规则:
- 堆栈的存取每次必须是一个字(16位),即堆栈指令中的操作数必须是16位,即堆栈指令中的操作数必须是16位,而且只能是寄存器或存储器操作数,不能是立即数。
- 向堆栈中存放数据时,总是从高地址向低地址方向增长,而从堆栈取数据时则方向正好相反。
- 堆栈段在内存中的位置由SS决定,堆栈指针SP总是指向栈顶指针,即SP的内容等于当前栈顶的偏移地址。所谓栈顶是指当前可用堆栈操作指令进行数据交换的存储单元。在压入操作数之前,SP先减2,每弹出一个字,SP+2。
- 对堆栈的操作遵循“后进先出”的原则。
在程序调用时,堆栈主要应用于子程序调用、中断响应等操作时的参数保护,也可用于实现参数传递。
(2)堆栈操作指令。堆栈操作指令共有两条:压入堆栈指令PUSH和弹出堆栈指令POP。其格式为:
PUSH src
POP dest
指令中的操作数src和dest必须是字操作数(16位),它们可以是: 16位的通用寄存器或段寄存器,存储器单元。
push ax ;通用寄存器内容压入堆栈
push word ptr[data+si] ;数据段中两个连续存储单元内容压入堆栈
pop ds ;从栈顶弹出一个字到段寄存器
pop word ptr[bx] ;从栈顶弹出一个字到数据段两个连续内存中。
(3)堆栈指令的执行过程
- 压栈指令PUSH OPRD。PUSH指令是将指令中指定的字操作数压入堆栈。指令执行的过程为
SP-2->SP
,OPRD高八位->[SP+1]
,OPRD低8位->[SP]
。 - 出栈指令POP OPRD。POP指令是将当前栈顶的一个字送到指令的目标地址,并紧接着修改堆栈指针,以使SP指向新的栈顶位置。指令的执行过程为:
[SP]->OPRD低8位
,[SP+1]->OPRD高8位
,SP+2->SP
。
在程序中,PUSH和POP指令一般成对出现,且执行顺序相反,以保持堆栈原有状态,当然,在必要时也可通过修改SP的值来恢复堆栈原有状态。
堆栈除在子程序调用和响应中断时用于保护断点地址外,还可在需要时对某些寄存器内容进行保存。例如用CX寄存器同时作为两重循环嵌套的寄存器,可先将外循环计数值送CX,当内循环开始时将CX中的外循环计数值压入堆栈保存,然后把内循环计数写入CX,内循环完成后再将外循环计数值从堆栈中弹出CX。
交换指令XCHG
指令格式及操作:xchg oprd1,oprd2
交换操作就是将源地址与目标地址中的内容进行互换,即将源操作数送到目标操作数,同时将目标操作数传送源操作数。
交换指令对操作数的要求:
- 源操作数和目标操作数可以是寄存器或存储器,但不能同时为存储器。
- 不能为段寄存器操作数,即段寄存器的内容不能参加交换
- 两个操作数字长必须相同,可以是字节交换,也可以是字交换。
例如:设DS=2000H,SI=0230H,DL=88H,[20230H]=44H,执行指令xchg [si],dl
,执行结果:[20230H]=88H,DL=44H。DL的内容与[20230H]的内容进行交换。
查表转换指令XLAT
XLAT是一条字节的查表转换指令,可以根据表中元素的序号查出表中相应元素的内容。
预先将要查找的代码排成一个表放在内存某区域中,指令要求将表的首地址(偏移地址)送寄存器BX,要查找的元素的序号送入AL(表中第一个元素的序号为0,然后依次为1,2,3)。执行XLAT指令后,表中指定序号的元素被存入AL。
指令格式:XLAT ;将偏移地址为BX+AL所指单元的内容送到AL中
,或XLAT src_table ;src_table表示要查找的表的首地址
。
例如:在内存的数据段中存放有一张数值为0~9的ASCII码转换表,首地址为Hex_table,现要把数值8转换为对应的ASCII码,可用以下几条指令实现
LEA BX,Hex_table ;BX<-表首偏移地址 LEA指令将存储器操作数mem的4位16进制偏移地址送到指定的寄存器。
MOV AL,8 ;AL<-8
XLAT ;查表转换
结果为AL=38H,为8所对应的ASCII码。由于要查找元素的序号放在AL中,所以表格的最大长度不超过256个字节。
输入输出指令
输入输出指令是专门面向输入输出端口进行读写的指令,共有两条:IN和OUT,输入指令用于从I/O端口读数据到AL或AX中,而输出指令则把AL或AX的内容写出到I/O。在8088指令系统中,允许用两种形式表示端口地址:直接寻址,寄存器间接寻址。
- 直接寻址:指令中的I/O端口地址为8位,此时允许寻址256个端口,端口地址范围为0~FFH。
- 寄存器间接寻址:端口地址为16位,由DX寄存器指定,可寻址64K个端口,地址范围为0~FFFFH。
(1)输入指令IN:指令格式为in acc,port ;直接寻址,port为用8位立即数表示的端口地址
或in acc,DX ;间接寻址,16位端口由DX给出
。
IN指令从端口输入一个字节到AL或输入一个字到AX中。
(2)输出指令OUT:指令格式为out port,acc ;直接寻址,port为8位立即数表示的端口地址
或out dx,acc ;间接寻址,16位端口地址由DX给出
。
OUT指令将AL或AX的内容输出指定端口。
注意;采用间接寻址的IN/OUT指令只能用DX寄存器作为间址寄存器。
取偏移地址指令
指令格式:lea reg16,mem
,lea指令将存储器操作数mem的16位偏移地址送到指定的寄存器。
lea bx,buffer ;将内存单元buffer的偏移地址送bx
mov al,[bx] ;取出buffer中的第一个数据送al
mov ah,[bx+1] ;取出buffer中的第二个数据送ah
例如:若设BX=1000H,DS=6000H,[61050H]=33H,[61051H]=44H。比较以下两条指令的执行结果。
lea bx,[bx+50H]
mov bx,[bx+50H]
第一条执行后BX=1050H,第二条指令执行后BX=4433H。
其他传送指令
指令类型 | 汇编格式 | 指令的操作 | 示例 |
---|---|---|---|
字位扩展指令 | CBW |
将AL中的字节数扩展为字,并存放在AX中,扩展的原则是:将符号位扩展到整个高位 |
MOV AL,8EH CBW ;AX=FF8EH |
字位扩展指令 | CWD |
将AX的字扩展为双字,扩展后高16位放在DX中,扩展的原则与CBW指令相同。 |
MOV AX,438H CBW ;AX=438EH.DX=0000H |
远地址传送指令 | LDS reg16,mem32 |
mem32为内存中连续4个单元的首地址,指令将[mem32]和[mem32+1]单元内容送入reg16,将[mem32+2]和[mem32+3]单元的内容送DS。 | 设1234H为首的4个单元内容分别为11H,22H,00H,90H,则执行完lds si,[1234H] ,SI=2211H,DS=9000H |
算术运算指令
算术运算涉及运算结果是否溢出,无符号数和有符号数的表示方法、数的可表示范围及溢出标志都不一样。有符号数的溢出是一种出错,而无符号数溢出则不能简单的认为是出错,也可看作是向更高位的进位。它们的判断标志分别为CF和OF。
加法指令
普通加法指令ADD
指令格式:ADD OPRD1,OPRD2
,将源操作数和目标操作数相加,结果送回目标地址中。
这里,源操作数OPRD2和目标操作数OPRD1均可以是8位或16位的寄存器或存储器操作数,源操作数可以是立即数,可以是无符号数,也可以是带符号数。
以下指令是合法的
add cl,20h
add dx,[bx+si]
以下指令是非法的
add [si],[bx]
add ds,ax
ADD指令的执行对全部6个状态标志位都会产生影响。
- AF=1 表示 D 3 D_3 D3向 D 4 D_4 D4有进位。
- CF=0 表示最高位向前无进位。
- OF=1 表示若为有符号数加法,其运算结果产生溢出。
- PF=0 表示8位的运算结果中,“1”的个数为奇数。
- SF=1 表示运算结果的最高位为“1”
- ZF=1 表示运算结果不为“0”
带进位的加法指令ADC
指令格式:ADC OPRD1,OPRD2
,ADC指令与ADD指令功能、格式及对标志位的影响上都基本相同。只是CF也要参与运算。
加1指令INC
指令格式:INC OPRD
,INC指令是将指定操作数的内容加1,再送回操作数。这里的操作数OPRD可以是寄存器或存储器数,可以是8位,也可以是16位数,但不能是段寄存器,也不能是立即数。INC指令不影响CF标志,但对其他5个标志位AF,OF,PF,SF,ZF会产生影响。
减法运算
8086/8088共有5条减法指令,不考虑借位的普通减法指令SUB,考虑借位的减法指令SBB,减1的指令DEC,求补指令NEG,比较指令CMP。
指令名 | 指令格式 | 指令功能 | 注意 |
---|---|---|---|
SUB |
SUB OPRD1,OPRD2 |
目标数减去源操作数,并将结果送入目标操作数的地址。不考虑借位。 | 对操作数和影响标志位与ADD相同。 |
SBB |
SBB OPRD1,OPRD2 |
目标操作数减去源操作数和CF的值,并将结果送目标操作数的地址。 | 其对标志位的影响与SUB相同。 |
DEC |
DEC OPRD |
将操作数的值减1,结果送回操作数地址。 | 其对标志位的影响与INC相同。 |
NEG |
NEG OPRD |
用0减去操作数OPRD,结果返回操作数地址。 | 执行后,一般CF=1,除非给定操作数为0,则CF=0 |
CMP |
CMP OPRD1,OPRD2 |
用目标操作数减去源操作数,改变标志位情况判断大小 | ZF=1,相等。ZF=0,不相等。 对两个无符号数,CF=0,则被减数大于减数。 对有符号数, O F ⊕ S F = 0 OF \oplus SF=0 OF⊕SF=0,被减数大于减数。 |
乘法指令
MUL OPRD
指令的操作
- 字节乘法 A X ← O P R D × A L AX \leftarrow OPRD \times AL AX←OPRD×AL
- 字乘法 D X : A X ← O P R D × A X DX:AX \leftarrow OPRD \times AX DX:AX←OPRD×AX
源操作数可以是8位或16位的寄存器或存储器,乘法指令要求操作数字长相等,且不能为立即数。
除法指令
DIV OPRD
指令的操作
-
字节除法 A L ← A X / O P R D , A H ← A X % O P R D AL \leftarrow AX/OPRD,AH \leftarrow AX \% OPRD AL←AX/OPRD,AH←AX%OPRD
-
字除法 A X ← D X : A X / O P R D , D X ← D X : A X % O P R D AX \leftarrow DX:AX/OPRD,DX \leftarrow DX:AX \% OPRD AX←DX:AX/OPRD,DX←DX:AX%OPRD
逻辑运算和移位指令
逻辑运算
指令名 | 指令格式 | 指令功能 |
---|---|---|
AND |
AND OPRD1,OPRD2 |
OPRD1 = OPRD1 & OPRD2 |
OR |
OR OPRD1,OPRD2 |
OPRD1 = OPRD1 | OPRD2 |
NOT |
NOT OPRD |
OPRD = !OPRD |
XOR |
XOR OPRD1,OPRD2 |
O P R D 1 = O P R D 1 ⊕ O P R D 2 OPRD1 = OPRD1 \oplus OPRD2 OPRD1=OPRD1⊕OPRD2 |
非循环移位指令
指令名 | 指令格式 | 指令功能 |
---|---|---|
SAL |
SAL OPRD,1 SAL OPRD,CL
|
SAL指令的操作将目的操作数的内容CL中所指定的位数。每左移一位,左边的值存入CF。 |
SAR |
SAR OPRD,1 SAR OPRD,CL
|
SAR是将目标操作数视为有符号数,最高位不是补零,而是保持不变。右边的值存入CF。 |
SHL |
SHL OPRD,1 SHL OPRD,CL
|
SHL指令的操作将目的操作数的内容CL中所指定的位数。每左移一位,左边的值存入CF。 |
SHR |
SHR OPRD,1 SHR OPRD,CL
|
SHR指令的操作将目的操作数的内容CL中所指定的位数。每右移一位,右边的值存入CF。 |
串操作指令
所有串操作指令都具有以下特点
- 源串默认为数据段,即段基地址在DS中,但允许重设,偏移地址用SI寄存器指定,即源串指针为DS:SI。
- 目标串默认在ES附加段中,不允许段重设。偏移地址用DI寄存器锁定,即目标指针为ES:DI。
- 串长度值放在CX寄存器中。
- 串操作指令本身可实现地址指针的自动修改。
指令名 | 指令格式 | 指令功能 |
---|---|---|
MOVS |
MOVS OPRD1,OPRD2 |
OPRD1为目标地址,OPRD2为源地址,指令将源地址字节或字传送给到目标地址中。 |
MOVSB |
MOVSB |
源串在数据段,偏移地址在SI中,目标串在附加段,偏移地址在DI中。一次完成一个字节的传送。 |
MOVSW |
MOVSW |
源串在数据段,偏移地址在SI中,目标串在附加段,偏移地址在DI中。一次完成一个字的传送。 |
CMPS |
CMPS OPRD1,OPRD2 |
将源串地址与目标串地址的数据按字节或字进行比较,结果反应到标志位。 |
CMPSB |
CMPSB |
一次完成一个字节比较 |
CMPSW |
CMPSW |
一次完成一个字比较 |
程序控制指令
无条件转移指令JMP
指令格式:JMP LABEL
,LABEL是一个标号,也称为符号地址,表示转移的目的地。
JMP指令的操作是无条件地使程序转移到指定的目标位置,并从该地址开始执行新的程序段。
条件转移指令JCC
JCC指令 | 中文含义 | 检查符号位 |
---|---|---|
JZ/JE |
若为0则跳转;若相等则跳转 | ZF=1 |
JNZ/JNE |
若不为0则跳转;若不相等则跳转 | ZF=0 |
JS |
若为负则跳转 | SF=1 |
JNS |
若为正则跳转 | SF=0 |
JP/JPE |
若1出现次数为偶数则跳转 | PF=1 |
JNP/JPO |
若1出现次数为奇数则跳转 | PF=0 |
JO |
若溢出则跳转 | OF=1 |
JNO |
若无溢出则跳转 | OF=0 |
JC/JB/JNAE |
若进位则跳转;若低于则跳转;若不高于等于则跳转 | CF=1 |
JNC/JNB/JAE |
若无进位则跳转;若不低于则跳转;若高于等于则跳转; | CF=0 |
JBE/JNA |
若低于等于则跳转;若不高于则跳转 | ZF=1或CF=1 |
JNBE/JA |
若不低于等于则跳转;若高于则跳转 | ZF=0或CF=0 |
JL/JNGE |
若小于则跳转;若不大于等于则跳转 | SF != OF |
JNL/JGE |
若不小于则跳转;若大于等于则跳转; | SF = OF |
JLE/JNG |
若小于等于则跳转;若不大于则跳转 | ZF != OF 或 ZF=1 |
JNLE/JG |
若不小于等于则跳转;若大于则跳转 | SF=0F 且 ZF=0 |
循环控制指令
LOOP指令
指令格式:LOOP LABEL
,指令的执行是先将CX减1,再判断CX是否为0,若CX不为0,则转至目标地址继续循环。
LOOPZ指令
指令格式:LOOPZ LABEL
,指令的执行先将CX减1,再根据CX的值及ZF的值判断是否继续循环。继续循环的条件是CX不为0,ZF为1。若CX=0或ZF=0,退出循环。
中断指令
INT指令
指令格式:INT n
,CPU根据n计算中断向量的地址,然后从该地址取出中断服务程序的入口地址,并转到中断服务子程序去执行。
IRET指令
IRET为中断返回指令,用于从中断服务子程序返回到被中断的程序继续执行。任何中断服务子程序无论是外部还是内部中断,其最后一条指令都是IRET指令。
处理器控制指令
CLC
:清进位标志位CF。
STC
:进位标志位置位。
CMC
:进位标志位取反。
CLD
:DF置0。
STD
:DF置1。
CLI
:IF置0。
STI
:IF置1。
上一篇: C++反汇编-函数指针分析
下一篇: PHP的Zlib跟gzhandle