8086汇编常用的指令,从功能上分,一般分为:
- 数据传送指令
- 算术指令
- 逻辑指令
- 控制转移指令
- 标志处理指令
- 串处理指令
这些指令书上网上都有很多介绍,我就不会全部详细介绍,只挑一些常用的、需要注意的重点说明。
数据传送指令
1. mov(传送)
|
|
有以下需要注意的地方:
dst
和src
类型必须匹配,无法确定类型时要显式指定类型。123456mov ax, 1 ; 正确!立即数会自动扩展类型mov ax, bl ; 错误!类型不匹配mov ax, [0] ; 可以运行,但不是预期结果,原因见 2mov ax, ds:[0] ; 正确!ax是字类型,ds:[0]也获取字类型mov ds:[0], 1 ; 错误!无法确定类型mov byte ptr ds:[0], 1 ; 正确!指定了访问的内存单元是一个字节单元形如
mov ax, [0]
这类指令Debug
加载运行 和masm
编译器对它们的解释不同,Debug
将[idata]
解释为一个内存单元,idata
是内存单元的偏移地址;而编译器将[idata]
解释为idata
,一个立即数。
所以,在汇编源程序中,要访问一个内存单元,并且[...]
里面是一个立即数,必须要用以下两种方法:将偏移地址放进
bx
寄存器(或si
,di
)中,然后用[bx]
来访问内存单元。(用bx
,si
,di
时,默认段寄存器在ds
中, 用bp
时,默认段寄存器在ss
中)12mov bx, 1mov ax, [bx]在 [] 前面显示指定段寄存器。
1mov ax, ds:[0]
dst
和src
不能同时为内存单元和段寄存器。不能将立即数传给段寄存器,段名也是立即数,但可以将内存单元数据传给段寄存器。
1234567891011121314151617cs:code, ds:datadataaddress dw 1234hdata endscodemain:mov ds, 1234h ; 错误!不能将立即数传给段寄存器mov ds, data ; 错误!段名也是一个立即数mov bx, 0mov ds, [bx] ; 可以mov ds, address ; 可以,address会被编译成一个地址,同上一条指令类似mov ax, 4c00hint 21hcode endsend main目的操作数
dst
不能为立即数或cs
(代码段寄存器)。mov
指令不影响标志位。
2. push(入栈) / pop(出栈)
|
|
push
和 pop
的操作数可以是16位寄存器、段寄存器或者字内存单元。注意:不能 pop
到 cs
(代码段寄存器)中。
以下操作都是合法的:
3. xchg(交换)
|
|
交换8/16位寄存器/内存单元的值。
注意:
- 类型必须匹配。
- 交换数必须是通用寄存器(
AX
,BX
,CX
,DX
,SI
,DI
)或内存单元。 - 两个交换数不能同时为内存单元。12345678xchg al, dl ; 可以xchg ax, bx ; 可以xchg ax, word ptr ds:[0] ; 可以xchg [bx], ax ; 可以xchg al, bx ; 错误!类型不匹配xchg ax, ds ; 错误!交换数不能为段寄存器xchg ds, ax ; 错误!交换数不能为段寄存器xchg byte ptr ds:[0], byte ptr ds:[1] ; 错误!两个都是内存单元
4. lea(传入有效地址 Load Effective Address)
|
|
注意:
- 目的操作数必须为16位通用寄存器,不能是段寄存器
- 传入寄存器的是有效地址,而不是内容
|
|
|
|
dx
中保存了ds:[0]
的偏移地址,若想得到ds:[0]
的值,要用:
以下两条指令功能相同:
算术指令
加法指令
1. add(加法)
|
|
作用:dst
= dst
+ src
注意:1) 两个操作数类型要匹配。 2)操作数不能同为内存单元。
2. adc(带进位加法)
|
|
作用:dst
= dst
+ src
+ cf
注意:同 add
。
3. inc(自增一)
|
|
减法指令
1. sub(减法)
|
|
作用:dst
= dst
- src
注意:同 add
。
2. sbb(带借位减法)
|
|
作用:dst
= dst
- src
- cf
注意:同 add
。
3. dec(自减一)
|
|
4. neg(求补)
|
|
作用:dst
= 0 - dst
(即求相反数)
5. cmp(比较)
|
|
作用:根据 dst
- src
的结果去影响标志位。
注意:同 add
。
乘法指令
1. mul(无符号乘法)
|
|
作用:1)当操作数为8位时,乘数默认保存在 al
中,结果保存在 ax
中,ax
= al
× src
。2)当操作数为16位时,乘数默认保存在 ax
中,结果的高16位保存在 dx
中,低16位保存在 dx
中,dx
: ax
= ax
× src
。
2. imul(带符号乘法)
同 mul
。
除法指令
1. div(无符号除法)
|
|
作用:1)当操作数为8位时,被除数默认保存在 ax
中,结果商保存在 al
中,余数保存在 ah
中。2)当操作数为16位时,被除数默认高16位保存在 dx
中,低16位保存在 ax
中,结果商保存在 ax
中,余数保存在 dx
中。
2. idiv(带符号除法)
同 div
。
注意:除法指令可能会发生溢出,产生0号中断。可参考 http://www.doc88.com/p-5836860600548.html 。
逻辑指令
逻辑运行指令
1. and(与)/ or(或)/ not(非)/ xor(异或)
|
|
注意:1) 两个操作数类型要匹配。 2)操作数不能同为内存单元。
2. test(测试)
|
|
作用:将两个操作数相与(and
)后的结果去影响标志位,若结果为0,则zf
=1,否则zf
=0。
注意:1) 两个操作数类型要匹配。 2)操作数不能同为内存单元。
常用用法:检查某位是否为1,e.g.:
检验
ax
是否为负数12test ax, 8000hjnz l ; 是负数则跳转检验
ax
是否为奇数12test ax, 1jnz l ; 是奇数则跳转判断大小写
123test ax, 00100000bjz label1 ; 大写则跳转jmp lable2 ; 小写则跳转
移位指令
shl(逻辑左移)/ shr(逻辑右移)/ sal(算术左移)/ sar(算术右移)
|
|
作用:将操作数各个二进制位向左(右)移动1(cl
)位,最高(低)位移出到 cf
,最低(高)位补0(sf
)。
注意:1)若移位数为1,可以直接写1,否则必须将移位数放入cl
中并调用。2)无论移动多少次,cf
等于最后移出位的值。
逻辑移位跟算术移位的区别:算术移位是将数据看成是有正有负的补码数的运算,逻辑移位是将数据看成是无符号数。左移时,算术移位和逻辑移位最右端都是用0补充,操作相同,所以指令等价。右移时,算术右移最右端补sf
(符号标志位),逻辑右移补0,所以指令不同。
循环移位指令
rol(循环左移)/ ror(循环右移)/ rcl(带进位循环左移)/ rcr(带进位循环右移)
|
|
作用:循环移位时,将操作数各个二进制位向左(右)移动1(cl
)位,最高(低)位同时移入cf
和最低(高)位。带进位循环移位时,将操作数各个二进制位向左(右)移动1(cl)位,最高(低)位移入cf
,原cf
移入最低(高)位。
注意:同移位指令。