8086/8088 指令系统的指令按操作数地址个数可分为三种类型:
(1)双操作数指令: OPR DEST,SRC
(2)单操作数指令: OPR DEST
(3)无操作数指令: OPR
在8086/8088 指令系统中,除串操作指令外,其余所有指令最多只能有一个操作数存放在存储器中。对于双操作数而言,两个操作数不能同时是存储器操作数。
8086/8088 指令系统的指令按功能可分为六大类:
(1)传送类指令
(2)算术运算类指令
(3)位操作类指令
(4)串操作类指令
(5)程序转移类指令
(6)处理器控制类指令
下面就分别介绍这几类指令的汇编格式描述。
一、 传送类指令
这类指令又分为四种:数据传送指令、交换指令、标志位传送指令、地址传送指令。
指令名 | 指令格式 | 指令功能 | 标志位 | 备注 |
数据传送指令 | MOV DEST,SRC | DEST←(SRC) | 无 | 目的操作数不能是立即数 |
压栈指令 | PUSH AX | SP→(SP) - 2 | 无 | AX可为任何通用寄存器使用 |
出栈指令 | POP AX | AX←(栈顶字单元) | 无 | AX可为任何通用寄存器使用 |
交换指令 | XCHG DEST,SRC | (DEST)Û(SRC) | 无 | 目的操作数不能是立即数 |
取标志指令 | LAHF | AH Ü(FR)7~0 | 无 | 标志寄存器FR低8位传到AH寄存器中 |
存标志指令 | SAHF | FR7~0 Ü(AH) | SF/ZF/AF/PF/CF | 将AH的内容传到FR低8位中 |
标志压栈 | PUSHF | SP→(SP) - 2 | 无 |
|
标志出栈 | POPF | FR←(栈顶字单元) | 所有标志位 |
|
装入 | LEA DEST,SRC | DEST←SRC的EA | 无 | 源操作数必须是存储器操作数 |
装入 | LDS DEST,SRC | DEST ← (SRC) , | 无 | 源操作数必须是存储器 |
输入输出指令 | OUT DEST,SRC | 完成CPU与I/O端口之间的数据传送. | 无 | IBM PC支持64k个8位端口地址 |
1. MOV 指令
功能: 把源操作数送给目的操作数
语法: MOV 目的操作数,源操作数
格式: MOV r1,r2
MOV r,m
MOV m,r
MOV r,data
这是最基本的通用数据传输指令,用于寄存器之间、寄存器和存储器之间以及立即数到寄存器或存储单元。必须注意的是:第一,两个段寄存器之间不能直接传送数据;第二,两个存储单元之间不能直接传送数据,二操作数中必须有一个是寄存器或立即数;第三,立即数和段寄存器CS不能作为目的操作数,并且立即数也不能直接传送到段寄存器;第四,操作数的类型和长度必须一致,并且不允许溢出。
第三点,立即数和段寄存器CS不能作为目的操作数。这里还要强调一下,立即数不能作为目的操作数,这很好理解,因为没有存放目的的位置。而CS不能作为目的操作数,这个很重要,因为可以防止黑客篡改代码,所以当CPU启动或复位,CS的值都是定值,始终未变。
2. XCHG 指令
功能: 交换两个操作数的数据
语法: XCHG
格式: XCHG r1,r2
XCHG m,r
XCHG r,m
XGHG指令是一条数据交换指令。虽然这也是一种通用的数据传送指令,但它不像MOV指令那样,而是在源和目的之间交换。所以,这种指令的两个操作数都不能是段寄存器或立即数,也不能同时为存储器操作数。
3. PUSH和POP指令
功能: 把操作数压入或取出堆栈
语法: PUSH 操作数 POP 操作数
格式: PUSH r
PUSH M
PUSH data
POP r
POP m
这两条是堆栈操作指令,是在操作数和堆栈之间传送数据,其中PUSH是将寄存器、存储单元或立即数压入栈(ss:sp),先sp-2->sp,然后将操作数传送到sp所指向的那个内存单元(所谓“栈顶”);POP正好相反,先将一个数据从现在sp指向的那个单元传输到目的操作数中,然后执行sp+2->2,完成所谓的出栈。
针对这两条堆栈指令我还要多说一句。为什么sp是加2或者减2,在8086/8088体系中,堆栈操作针对的是字,而不是字节,这两个指令只能操作16位操作数,一定要注意。
4. XLAT(XLATB) 指令
功能: 查表指令
语法: XLAT
XLAT m
这条指令专门用于AL和字节表中某一存储单元之间执行数据传送的指令。表的首地址在BX中,根据AL设置的偏移地址,可将该单元内容传送到AL累加器,从而达到将一种代码翻译成另一种代码的目的。
5. LEA指令
功能: 取地址至寄存器
语法: LEA r,m
接下来的三条指令也是很重要的,LEA主要用来将源操作数的偏移地址传送到通用寄存器、指针或变址寄存器中。注意,由于是偏移地址,所以目的操作数必须是一个16位寄存器,而且源操作数一定是一个存储器地址。
还是举个例子吧:
MOV BX,0100H
LEA SI,[BX]
执行这两个指令后,SI寄存器中的内容是0100H。大家可以比较一下LEA和MOV的区别,好好体会一下,如果是MOV SI,[BX],那么SI存放的就是偏移0100H对应的那个存储单元中存放的内容。
6. LDS指令
功能: 取地址指针至寄存器
语法: LDS r,m
LDS用来把源操作数指定的连续4个存储单元中存放的32位数据当做地址指针。什么意思?就是说,源操作数一定是连续4个存储单元,而这4个单元32位的数据包含了一个段地址和一个地址偏移量,正好组成一个地址指针。那么LDS的作用就是把这个地址指针传送到指定的16位通用寄存器,而两个高位字节作为段地址送到DS中。例如:
SRC DD 12345678H
LDS SI,SRC
运行上述指令后,SI的内容为5678H,DS中的内容为1234H。
7. LES指令
功能: 取地址指针至寄存器
语法: LES r,m
LES跟LDS做一样的事,只是段寄存器换成了ES,指令不在赘述具体过程了。
8. LAHF指令
功能: 取标志指令,将标志寄存器FR低8位传到AH寄存器中
格式: LAHF
9. SAHF指令
功能: 存标志指令,将AH的内容传到FR低8位中
格式: SAHF
10. PUSHF指令
功能: 标志压栈指令,SP→(SP) - 2,栈顶字单元存放16位FR的值
格式: PUSHF
11. POPF指令
功能: 标志出栈指令,用栈顶字单元的16位值更新FR的值,SP←(SP)+2
格式: POPF
12. IN指令
功能: I/O端口输入指令
语法: IN 累加器, {端口号│DX}
格式: IN AL/AX, data/DX
13. OUT指令
功能: I/O端口输出指令
语法: OUT {端口号│DX},累加器
格式: OUT data/DX, AL/AX
注意:输入输出端口由立即方式指定时,其范围是 0-255;由寄存器 DX 指定时,其范围是 0-65535。