80x86指令系统和寻址方式
指令的基本组成
这里我们用数据传达指令(Mov)来作为例子来了解指令的组成和一些常见的错误类型。
数据传输示意图:
例如:
指令常见错误类型:
例如:
- 第五个中如果中括号中是寄存器说明这是寄存器间接寻址,而寄存器间接寻址的寄存器只能是BX,BP,SI,DI之一。
- 第六个中有两个中括号说明是基址+变址寻址。基址为BX,BP。变址为SI,DI。
- 第十个中当存储器和立即数同时都为操作数的时候应该指明存储器数据类型,因为这决定立即数是否要补0存储。这里可改为Mov Btye Ptr[BX] , 1或者Mov Word Ptr[BX] , 1
练习:
常用指令
-
交换指令XCHE
将指定的连个操作数的值交换
注意:
XCHG后的操作数不可为立即数,因为无法对立即数赋值。 -
进栈指令PUSH
eg:
注意:
<1> 入栈是往上堆叠的,所以SP的值是减小的。
<2> 因为每次SP的值都减2,所以每次入栈都应是两个字节,不足补0。
<3> 注意高地址在下面,低地址在上面。
出栈指令POP
注意:
<1> 出栈指针向下移动两个字节所以SP+2
<2> 这里只是指针移动,并不代表栈里的值被消除
栈的特点是先进后出
eg:
堆栈指令注意事项
- PUSH指令后跟的操作数是源操作数
- POP指令后跟的操作数是目的操作数
- 16位系统中PUSH指令的操作数不可为立即数
地址传送指令LEA
把源操作数的有效地址送给指定的目的寄存器
MOV与LEA的区别:
MOV是将源操作数的值传给目的寄存器
LEA是将源操作数的有效地址送给指定的目的寄存器
eg:
这里的OFFSET是求之后变量和标号的偏移地址,故2跟3的效果是一样的。
加法指令ADD,ADC,INC
- ADD是不带进位的加法
- ADC是带进位的加法,除了两个数相加还需加上CF(进位标志符)
- INC是自加的意思,相当于其他语言中的++
eg:
加法指令对标志符的影响:
<1> ADD 与 ADC 影响CF,OF,ZF,SF
<2> INC不影响CF,影响OF,ZF,SF
eg:
减法指令SUB,SBB,NGE
- SUB是不带借位的减法
- SBB是带借位的减法
- NEG是取相反数(各位取反,末尾加1)
- CMP做减法改变标志位但不保存计算结果
eg:
减法指令对标志符的影响:
<1> SUB,SBB,CMP正常影响标志位
<2> DEC不影响CF标志位
<3> NEG中当操作数为0时,CF = 0(因为0-0不借位),其他情况CF = 1
<4> NEG中当操作数只有首位为1、其他位为0时,OF= 1(各位取法末尾加一后溢出),其他情况OF = 0
eg:
注意:
当有NEG时CF切记不可用各位取法末尾加1来计算,这个只是简单的计算方法会忽略了0 - 操作数的借位过程。
乘法指令MUL,IMUL
- 当操作数为8位时,AL * 操作数 = AX
- 当操作数为16位时,AX * 操作数 = DX:AX
- 无符号数相乘补前导0,有符号数相乘补符号位
eg:
当乘积的高半部分为0或符号位扩展时,CF = OF = 0
当乘积的高半部分不为0或符号位扩展时,CF = OF = 1
除法指令DIV,IDIV
- 当操作数为8位时:AX / 操作数 ,商 → \rightarrow → AL,余数 → \rightarrow → AH
- 当操作数为16位时:DX:AX / 操作数 ,商 → \rightarrow → AX,余数 → \rightarrow → DX
注意:
对于IDIV指令,余数与被除数符号相同。
除法对标志位无定义
符号扩展指令CBW,CWD
- CBW就是Byte → \rightarrow → Word(8位的比特扩展为16位的字)。故 AL → \rightarrow → AX
- CWD就是Word → \rightarrow → Double Word(16位的字扩展为32位的双字)。故 AX → \rightarrow → DX:AX
无符号数扩展补0,有符号数扩展补最高位。
eg:
符号扩展指令不影响标志位
例:
注意:
最后一个SUB BH,-9有许多坑。
<1> 如果只在意运算结果的话,我们可以用BH+9来等价。但如果涉及到标志位的话还是老老实实的用减法来走整个过程。
<2> -9不能简单的把9的首位变成1.而应该用NEG 9(各位取反末尾加一)。
所以应该为 1111 0100 - 1111 0111 = 1111 1101 有借位。
练习:
用汇编语言实现(C-120+A*B)/ C将商和余数分别存入X和Y中,其中A,B,C,X,Y都是有符号字变量。
解析
A*B得32位积,存在DX:AX中。
C是16位数故应该用CWD来扩展成双字节,但扩展后的值也是存在DX:AX中,所以我们要先用其他寄存器来把原来DX:AX中的值存起来。
这里我们将扩展后的C跟A*B这两个32位数进行相加,注意低位不加标志位,高位要加上标志位,因为低位可能会有进位。减法同理。
除以C,系统默认商存在AX中,余数存在DX中。
逻辑运算指令
- 逻辑非:NOT(1 → \rightarrow → 0,0 → \rightarrow → 1)
- 逻辑与:AND(全1为1,有0则0)
- 测试指令:TEST(取AND运算但只改变标志位不返回结果)
- 逻辑或:OR(有1则1,全0则0)
- 逻辑异或:XOR(相同为0,相异为1)
对标志位的影响
<1> NOT 指令对标志位没有影响。
<2> 其他指令置CF = OF = 0,正常影响SF和ZF。
移位指令
逻辑移位指令:
逻辑移位只补0就好了,不用管原来的符号位。逻辑左移相当于无符号数乘2,逻辑右移相当于无符号数除2.
算术移位指令:
算术右移是补的符号位。其中算术左移相当于有符号数乘以2,算术右移相当于有符号数除以2.
逻辑、算术移位指令对标志位的影响
<1> 移出位即CF
<2> SF和ZF根据移位后的结果判断
<3> 当移位次数不为1时OF无定义,当移位次数为1时若符号位发生了变化则OF = 1,若最高位未发生变化则OF = 0.
例:
循环移位指令:
带进位的循环逻辑指令:
这两个的区别在于带进位的循环逻辑指令中CF加入循环,而不带进位的循环逻辑指令CF只是存储移位过来的数但不参与循环。
循环移位指令对标志位的影响
<1> 移出位即CF
<2> SF和ZF根据移位后的结果判断
<3> 当移位次数不为1时OF无定义,当移位次数为1时若符号位发生了变化则OF = 1,若最高位未发生变化则OF = 0.
例:
练习1:
这里的重点是如何把AX的最高位移位到DX中,我们可以用CF来存储一下。
SHL AX,1
RCL DX,1
此操作如图:
练习2:
无条件转移指令
条件转移指令:
无符号数比较的转移指令
无符号数比较的转移指令
单个标志位测试的转移指令
循环控制指令:
LOOP
LOOPZ/LOOPE
即当为0且循环次数未减到0时进行循环。
LOONZ/LOOPNE
即当不为0且循环次数未减到0时进行循环。