本文是主要基于钱晓捷的《汇编语言程序》第五版做出的易错知识,核心知识点总结。
8086指令系统:
一,数据传送类:
易错点:
段寄存器之间不能传值,存储器之间不能传值,立即数不能直接传给段寄存器,立即数传给存储器需要显示指明存储器单元类型。
数据传送类指令除标志寄存器传送指令(lahf,sahl,pushf,popf)外均不影响标志位
MOV指令:
mov reg/men, imm
mov reg/men/seg, mem
mov reg/seg, mem
mov reg/men, seg
XCHG指令:
XCHG reg,reg/mem
XCHG reg/mem,reg
XLAT转码指令:
xlat ;alds:[bx+al]该指令默认使用BX,AL寄存器
PUSH堆栈操作指令:操作对象只能式字操作数
push r16/m16/seg ;spsp - 2, ss:[sp]r16/m16/seg
POP堆栈操作指令:操作对象只能式字操作数
pop r16/m16/seg ; r16/m16/segss:[sp], spsp + 2
8086处理器堆栈操作
堆栈的应用:
标志传送指令:
1. 标志送AH指令 LAHF(LOAD AH FROM FLAGS)
2.AH送标志指令 SAHF(SAVE AH TO FLAGS)
3.标志进栈指令PUSHF
4.标志出栈指令POPF
算数运算类:
状态标志:进位标志(针对无符号)CF=1,进位或借位,如何理解:比如字节数据相加减,结果不在0~255范围内,则CF=1。
溢出标志(针对有符号)OF=1,溢出。如何理解溢出:有符号正数相加,得到了负数,就说明溢出了 0110 0001 + 0100 0010 = 1010 0011。总结起来就是:只有当两个相同符号数相加(包含两个不同符号数相减)而运算结果的符号与原数据符号相反,才产生溢出。因为此时运算结果显然不对。两个正数相加怎么可能是负数?正数减负数怎么可能得负数?因为溢出了呀!
其他标志位如零标志ZF,运算结果为零时ZF=1;符号标志SF,运算结果为负数是SF = 1;奇偶标志PF,运算结果在1的个数为偶数时AF =1。
提醒一句:之前说到的数据传送类指令除了标志寄存器传送指令(lahf,sahl,pushf,popf)外均不影响标志位
现在开始介绍算术指令(按照+ - * / 的顺序):
add加法指令,add reg, imm/reg/mem ;regreg+imm/reg/mem
add mem,imm/reg
adc带进位加,即运结果还要加上CF的值
inc增量指令(加一运算),如:inc ax,设计目的是用于对计算器和地址指针的调用,不影响CF
sub减法指令,格式同add
sbb带借位减法指令,运算结果还要减去OF的值
dec减量指令,类似inc
neg求补指令,可以表示成:将操作数按位取反+1。对标志位的影响同add。
eg:neg reg/mem; reg/mem0 - reg/mem
cmp比较指令,同sub一样执行同样的操作,影响标志位,但是结果不送入目的操作数
乘法指令
除法指令
提醒:乘法指令利用对OF,CF的影响可以判断相乘的结果的高一半是否含有有效数据,如果有OF=CF=1,如果没有,即高位为0,则OF=CF=0;对其他标志位没有定义,即为任意,但不代表不影响,可能在8086中没有定义的必要。除法指令类比理解。
符号扩展指令(针对有符号数设计,正数补1,负数补0)cbw将al符号扩展到ax,cwd将ax符号扩展到dx和ax寄存器对。
逻辑运算指令:(所有双操作数的逻辑指令均设置CF=OF=0,根据结果设置SF,ZF,PF的状态,而对AF没有定义),对两个操作数执行逻辑运算,结果送目的操作数
AND逻辑与指令,两个操作数不能同时为存储器寻址,源操作数可以是任意寻址方式,目的操作数只能是立即数外的其他寻址方式。
OR逻辑或指令
XOR逻辑异或指令。xor ax,ax;将ax设置为0
NOT逻辑非指令,不影响标志位
TEST测试指令,执行操作和AND一样,不保存结果,目的操作数不变,根据结果来影响标志位
移位指令:
shl reg/mem , 1/cl;逻辑左移,最低位补0,最高位进入CF,如下图所示
shr reg/mem , 1/cl
sal reg/mem , 1/cl;同shl
sar reg/mem , 1/cl;算数右移,最高位不变,最低位进去CF
移位指令按照移入的位设置进位标志CF,根据移位后的结果影响SF,ZF,PF对AF没有定义。如果进行1位移动,按照操作数的最高符号位是否改变,相应设置溢出标志OF,最高位改变OF=1,否则OF = 0;如果移位次数大于1时,OF不确定。
循环移位指令:
rol reg/mem , 1/cl;不带进位循环左移
ror reg/mem , 1/cl
rcl reg/mem , 1/cl;带进位循环左移,具体操作见下图。
rcr reg/mem , 1/cl
前两条指令不降进位CF纳入循环位中。后两条纳入,即9位或者17位二进制数一起移动。循环移位指令按照功能设置进位CF,不影响其他标志位。
控制转移类
1.无条件转移指令
段内转移,相对寻址:JMP lable;ipip+位移量
段间转移,间接寻址:JMP r16/m16;ipr16/m16
段间转移,直接寻址:JMP far ptr lable;iplabel的偏移地址,cslabel的段地址
段间转移,间接寻址:JMP far ptr mem;ip[mem],cs [mem+2]
2. 条件转移指令jcc(指令集)
JCC label;条件满足,发送转移,ipip+8位位移量,否则顺序执行ipip+2
根据标志位状态
针对无符号数高低的比较
针对无符号数大小的比较
循环指令(loop,loope/loopz,jcxz,loopne/loopnz)
提醒:循环指令不影响标志位。
loop指令首先将CX值减1,如何判断CX是否为0,CX不为0,则继续执行循环体内的指令;CX为0,表示循环结束,于是程序退出循环,顺序执行后面的程序。
使用loop的三要点:
1.必须在CX中存放循环次数;
2.loop指令的标号一般应在前面,要执行的循环程序段应写在标号和LOOP指令之前
3.为防止CX初值为0导致循环次数出错,可以在循环之前使用JCXZ指令进行判断。
子程序指令(call,ret)
程序调用和返回堆栈示意图
远调用时注意cs先入栈,ip后入栈。ip先赋新值,cs后赋新值
远调用时注意ip先出栈,cs后出栈 ;
二 , 寻址方式:
三类七种
立即数寻址 eg:mov ax, 0102h
寄存器寻址 eg: mov ax, 1234h
存储器寻址(五种):
1. 直接寻址: mov ax, [2000h];指令中直接包含有效地址
2. 寄存器间接寻址:有效地址存放在寄存器中,8086中寄存器只能是基址寄存器BX或者变质寄存器SI,DI。其默认的段地址在DS段寄存器中,可以使用段超越改变前缀。eg:mov ax,[si]
3. 寄存器相对寻址方式:有效地址是寄存器的内容与有符号8位或16位位移量之和,寄存器可以是BX,BP,SI,DI。操作数的EA = BX/BP/SI/DI+8/16位位移量。BP默认堆栈段SS,其他默认DS
eg:mov ax,[di + 06h]。采用BP相对寻址时如果偏移量为0,也可以不写,形式上与寄存器间接寻址一样。eg:mov ax,[bp] ; mov ax, [bp+0]
4. 基址变址寻址: 有效地址EA= BX/BP+SI/DI。BX默认段DS,BP默认段SS。
5. 相对基址变址寻址:EA = BX/BP+SI/DI+8/18位偏移量。
同一寻址方式可以写成不同形式:
mov ax, [bx][si] ;也可写成:mov ax ,[bx+si]
mov ax count[si] ;也可以写成 mov ax, [si+count],count为变量或常量,若为变量此处count取偏移地址地址,而不是取count表示的值。
mov ax wnum[bx][si];也可写成mov ax, [bx+si+wnum]或者mov ax,wnum[bx+si]