8086指令系统

汇编语言 8086指令系统整理。

数据传送类指令

通用数据传送指令

传送指令 mov

1
2
3
4
mov reg/mem, imm        ; 立即数送寄存器或主存
mov reg/mem/seg, reg ; 寄存器送寄存器(包括段寄存器)或主存
mov reg/seg, mem ; 主存送寄存器(包括段寄存器)
mov reg/mem, seg ; 段寄存器送主存或寄存器

交换指令 xchg

1
xchg reg, reg/mem        ; 将寄存器与寄存器或主存的内容交换

换码指令 xlat

1
2
3
4
xlat                    ; al <- ds:[bx+al]
; 使用前,将表格的首地址存在BX寄存器中
; 将需要转换的代码(偏移量)存在AL寄存器中
; 执行换码指令后,将AL寄存器中的内容转换为目标代码

堆栈操作指令

堆栈是一个”先进后出”的主存区域,位于堆栈段中。

存储方式是:高位栈底,低位栈顶。

进栈指令 push

1
push r16/m16/seg        ; sp <- sp-2, ss:[sp] <- r16/m16/seg

出栈指令 pop

1
pop r16/m16/seg            ; r16/m16/reg, sp <- sp + 2

标志传送指令

标志送AH指令 lahf

1
lahf                    ; ah <- flags的低字节

AH送标志指令 sahf

1
sahf                    ; flags的低字节 <- ah

标志进栈指令 pushf

1
pushf                    ; sp <- sp-2, ss:[sp] <- flags

标志出栈指令 popf

1
popf                    ; flags <- ss:[sp], sp <- sp+2

标志位操作

1
2
3
4
5
6
7
8
clc                        ; CF <- 0
stc ; CF <- 1
cmc ; CF <- ~CF
cld ; DF <- 0
std ; DF <- 1
cli ; IF <- 0
sti ; IF <- 1
; 记忆:cl -> clear, st->set

地址传送指令

有效地址传送指令 lea

1
lea r16, mem            ; r16 <- mem的有效地址EA

指针传送指令 lds les

1
2
lds r16, mem            ; r16 <- mem, ds <- mem+2
les r16, mem ; r16 <- mem, es <- mem+2

算术运算类指令

首先了解几个状态标志,它们在算术运算中起着重要作用。

进位标志 CF(Carry Flag):
针对无符号整数运算设计。
当加减运算的结果的最高有效位有进位或借位时,设置CF = 1

溢出标志 OF(Overflow Flag):
针对有符号整数运算设计。
当有符号数进行加减运算的结果超出范围时,设置OF = 1

零标志 ZF(Zero Flag):
反映运算结果是否为 0,当运算结果为 0 时,设置ZF = 1

符号指令 SF(Sign Flag):
反映运算结果是正数还是负数,当运算结果最高位为 1 时,SF = 1

奇偶校验 PF(Parity Flag):
反映运算结果最低字节中 1 的个数时偶数还是奇数,为偶数时,PF = 1

调整标志 AF(Adjust Flag):
当加减运算时最低半字节有进位或借位时,AF = 1

加法指令 add

1
2
add reg, imm/reg/mem    ; reg <- res+imm/reg/mem
add mem, imm/reg ; mem <- mem+imm/reg

带进位加法指令 adc

1
2
adc reg, imm/reg/mem    ; reg <- res+imm/reg/mem+cf
adc mem, imm/reg ; mem <- mem+imm/reg+cf

增量指令 inc

1
2
inc reg/mem                ; reg/mem <- reg/mem+1
; 该指令不影响进位CF标志,对其他标志状态位的影响与add,adc一样

减法指令 sub

1
2
sub reg, imm/reg/mem    ; reg <- res-imm/reg/mem
sub mem, imm/reg ; mem <- mem-imm/reg

带借位减法指令 sbb

1
2
sbb reg, imm/reg/mem    ; reg <- res-imm/reg/mem-cf
sbb mem, imm/reg ; mem <- mem-imm/reg-cf

减量指令 dec

1
2
dec reg/mem                ; reg/mem <- reg/mem-1
; 同inc,不影响CF但影响其他标志位

求补指令 neg

1
2
neg reg/mem                ; reg/mem <- 0-reg/mem
; 对标志的影响与用0减去操作数相同

比较指令 cmp

1
2
3
cmp reg, imm/reg/mem    ; reg-imm/reg/mem
cmp mem, imm/reg ; mem-imm/reg
; 比较指令将目的操作数减去源操作数,但不回送给目的操作数,也就是只影响标志

无符号数乘法指令 mul,有符号数乘法指令 imul

1
2
3
4
5
6
7
8
mul r8/m8                ; 无符号字节乘:  ax <- al·r8/m8
mul r16/m16 ; 无符号字乘: dx.ax <- ax·r16/m16
imul r8/m8 ; 有符号字节乘: ax <- al·r8/m8
imul r16/m16 ; 有符号字乘: dx.ax <- ax·r16/m16
; OF和CF的结果展示相乘结果高一半是否有有效数值
; 对 mul,高一半为 0 时,OF = CF = 0,否则 OF = CF = 1
; 对 imul,高一半是低一半的符号拓展时,OF = CF = 0,否则 OF = CF = 1
; 乘法指令对其他状态标志未定义,不可预测。

无符号二进制数除法指令 div,有符号二进制数除法指令 idiv

1
2
3
4
5
6
7
8
9
10
11
div r8/m8                ; 无符号数字节除: al <- ax除以r8/m8的商
; ah <- ax除以r8/m8的余数
div r16/m16 ; 无符号数字节除: ax <- dx.ax除以r16/m16的商
; dx <- dx.ax除以r16/m16的余数
idiv r8/m8 ; 有符号数字节除: al <- ax除以r8/m8的商
; ah <- ax除以r8/m8的余数
idiv r16/m16 ; 有符号数字节除: ax <- dx.ax除以r16/m16的商
; dx <- dx.ax除以r16/m16的余数
; 除法指令对标志的影响没有定义, 发生除法溢出时,8086 CPU 产生编号为 0 的内部中断
; 对 div,除数为0,或结果溢出,发生除法溢出
; 对 idiv,除数为0,或字节除时商不在-128~127,或字除时商不在-32768~32767,发生除法溢出

符号扩展指令 cbw cwd

1
2
cbw                        ; al符号扩展到ax
cwd ; ax符号扩展到dx.ax

位操作类指令

逻辑与指令 and

1
2
3
and dest, src            ; dest <- dest&src
; 双操作数逻辑指令所支持的操作组合与加减法一致,后面不再给出。
; 所有双操作数的逻辑指令均设置 CF = OF = 1,根据结果设置SF ZF PF状态,对AF未定义

逻辑或指令 or

1
or dest, src            ; dest <- dest|src

逻辑异或指令 xor

1
xor dest, src            ; dest <- dest^src

逻辑非指令 not

1
2
not reg/mem                ; reg/mem <- ~reg/mem
; not指令不影响标志位

测试指令 test

1
2
test dest, src            ; dest&src
; 执行的操作与and相同,但不返回结果,只是根据结果设置标志位

移位指令 shl shr sal sar

1
2
3
4
5
6
7
shl reg/mem, 1/cl        ; 逻辑左移: reg/mem左移1/cl位,最低位补0,最高位进入CF
shr reg/mem, 1/cl ; 逻辑右移: reg/mem右移1/cl位,最高位补0,最低位进入CF
sal reg/mem, 1/cl ; 算数左移: 与shl功能相同
sar reg/mem, 1/cl ; 算数右移: reg/mem右移1/cl位,最高位不变,最低位进入CF
; 移位指令根据移入的位设置CF,根据移位结果设置SF ZF PF,对AF无定义
; 如果进行1位移动,设置OF:如果移位前操作数最高位与移位后操作数最高位不同,OF = 1
; 如果移位次数大于1,OF不确定

循环移位指令 rol ror rcl rcr

1
2
3
4
5
6
rol reg/mem, 1/cl        ; 不带进位循环左移
ror reg/mem, 1/cl ; 不带进位循环右移
rcl reg/mem, 1/cl ; 带进位循环左移
rcr reg/mem, 1/cl ; 带进位循环右移
; 前两条指令不将进位CF纳入循环位中,后两条指令将CF纳入循环位中,与操作数一起构成9/17位的二进制数一起移位
; 循环移位指令按指令功能设置进位标志CF,不影响SF ZF PF AF,对OF标志的影响同移位指令

控制转移类指令

段内转移是指在当前代码段 64KB 范围内转移,因此不需要改变 CS 段地址,只需更改 IP 偏移地址。
如果转移范围可以用一个 8 位数(-128~127)表达,则形成短转移(short jump)
如果转移范围可以用一个 16 位数表达,则形成近转移(near jump)

段间转移是指从当前代码段跳转到另一个代码段,此时需要更改 CS 段地址和 IP 偏移地址。
这种转移也称为远转移(far jump),转移的目标地址用一个 32 位数表达,叫做 32 位远指针,即逻辑地址。

无条件转移指令 jmp,分为四种格式。

1
2
jmp label                ; ip <- ip+位移量
; 段内转移,相对寻址
1
2
jmp r16/m16                ; ip <- r16/m16
; 段内转移,间接寻址
1
2
jmp far ptr label        ; ip <- label的偏移地址, cs <- label的段地址
; 段间转移,直接寻址
1
2
jmp far ptr mem            ; ip <- [mem], cs <- [mem + 2]
; 段间转移,间接寻址

条件转移指令,具体指令如下表给出。

1
2
jcc label                ; 条件满足,发生转移: ip <- ip+8位位移量
; 否则,顺序执行: ip <- ip+2根据单个条件标志的设置情况转移
  1. 根据单个条件标志的设置情况转移
指令 英文 含义 格式 测试条件
JZ/JE jump if zero/equal 结果为零/相等则转移 JZ/JE OPR ZF=1
JNZ/JNE jump if not zero/equal 结果不为零/不相等则转移 JNZ/JNE OPR ZF=0
JS jump if sign 结果为负则转移 JS OPR SF=1
JNS jump if not sign 结果为正则转移 JNS OPR SF=0
JO jump if overflow 溢出则转移 JO OPR OF=1
JNO jump if not overflow 不溢出则转移 JNO OPR OF=0
JP/JPE jump if parity/parity even 奇偶位为1则转移 JP/JPE OPR PF=1
JNP/JNPE jump if not parity/parity even 奇偶位为0则转移 JNP/JNPE OPR PF=0
JB/JNAE/JC jump if below/not above、not equal/carry 低于/不高于或不等于/进位为1则转移 JB/JNAE/JC OPR CF=1
JNB/JAE/JNC jump if not below/ above、equal/not carry 不低于/高于或等于/进位为零则转移 JNB/JAE/JNC OPR CF=0
  1. 比较两个无符号数,并根据比较的结果转移
指令 英文 含义 格式 测试条件 等价于
JB/JNAE/JC jump if below/not above、not equal/carry 低于/不高于或不等于/进位为1则转移 JB/JNAE/JC OPR CF=1 <
JNB/JAE/JNC jump if not below/ above、equal/not carry 不低于/高于或等于/进位为零则转移 JNB/JAE/JNC OPR CF=0
JBE/JNA jump if below/equal、not above 低于/等于、不高于则转移 JBE/JNA OPR CF并ZF=1
JNBE/JA jump if not below/not equal、above 不低于/不等于、高于则转移 JNBE/JA OPR CF并ZF=0 >

 3. 比较两个带符号数,并根据比较的结果转移

指令 英文 含义 格式 测试条件 等价于
JL/JNGE jump if less、not greater/equal 小于、不大于/不等于则转移 JL/JNGE OPR SF异或CF=1 <
JNL/JGE jump if not less、greater/equal 不小于、大于/等于则转移 JNL/JGE OPR SF异或CF=0
JLE/JNG jump if less/equal、not greater 小于/等于、不大于则转移 JLE/JNG OPR (SF异或CF)并ZF=1
JNLE/JG jump if not less/not equal、 greater 不小于/不等于、大于则转移 JNLE/JG OPR (SF异或CF)并ZF=0 >

循环指令。(实际上循环流程可以由前面的转移指令实现)

1
2
3
4
jcxz label                ; cx = 0 则转移,否则顺序执行
loop label ; cx <- cx-1,若cx≠0,循环:ip <- ip+位移量,否则顺序执行
loopz/loope label ; cx <- cx-1,若cx≠0且zf=1,循环:ip <- ip+位移量,否则顺序执行
loopnz/loopne label ; cx <- cx-1,若cx≠0且zf=0,循环:ip <- ip+位移量,否则顺序执行

子程序调用指令 call,分为四种格式。

1
2
call label                ; 段内调用,相对寻址: sp <- sp-2, ss:[sp] <- ip
; ip <- ip + 16位位移量
1
call r16/m16            ; 段内调用,间接寻址: sp <- sp-2, ss:[sp] <- ip, ip <- r16/m16
1
2
3
call far ptr label        ; 段间调用,直接寻址: sp <- sp-2, ss:[sp] <- cs
; sp <- sp-2, ss:[sp] <- ip
; ip <- label偏移地址, cs <- label短地址
1
2
3
call far ptr mem        ; 段间调用,间接寻址: sp <- sp-2, ss:[sp] <- cs
; sp <- sp-2, ss:[sp] <- ip
; ip <- [mem], cs <- [mem+2]

子程序返回指令 ret,分为四种格式。

1
ret                        ; 无参数段内返回: ip <- ss:[sp], sp <- sp+2
1
ret i16                    ; 有参数段内返回: ip <- ss:[sp], sp <- sp+2, sp <- sp+i16
1
2
ret                        ; 无参数段间返回: ip <- ss:[sp], sp <- sp+2
; cs <- ss:[sp], sp <- sp+2
1
2
ret i16                    ; 有参数段间返回: ip <- ss:[sp], sp <- sp+2
; cs <- ss:[sp], sp <- sp+2, sp <- sp+i16

中断指令

1
2
3
int    i8					; 中断调用指令,产生 i8 号中断
iret ; 中断返回指令
into ; 溢出中断指令:溢出标志OF=1,则产生4号中断,否则顺序执行