本来想上午搞定,但今天在外面逛了一天买东西。。。
#相对昨天做了一些补充————2010/2/15#
#修改了有符号数使用CMP指令后标志CF和OF的值和两个操作数的大小关系——2010/2/23#
这次总结一下8086/8088汇编语言的指令系统
一.数据传送指令
1.传送指令
这个可以说指令系统中使用最频繁的语句,其格式为:MOV DST,SRC
主要用途是将源操作数SRC送至目的操作数DST,但不会改变源操作数,只改变目的操作数。
其中SRC可以是通用寄存器、段寄存器、存储器和立即数;当然,除此之外还有一些特殊要求:DST可以是DST可以是通用寄存器、段寄存器和存储器,同时,DST和SRC不能同时是段寄存器或存储器(若要在两个段寄存器或存储器之间传送数据,可以使用寄存器过度的方法)代码寄存器CS不能作为SRC,而且要特别注意,这些特殊要求不仅应用于传送指令,其他指令也适用。当然,对于传送指令还有一些要求:
1)立即数不能直接传送到段寄存器,而且立即数永远不能作为DST。
2)DST和SRC的类型要一致,即同时为字或字节。
(以上两个要求也适用于有目的操作数和源操作数的指令。)
同时前面介绍的各种寻址方式也可以在这里使用,可能很多教材在讲解寻址方式的时候都是用MOV做例子,但要注意,不是只有传送指令适用这些寻址方式,其他的一些指令也适用,当然,有些指令对寻址方式有特殊需求,例如加法指令只能用存储器寻址方式。
2.交换指令
格式为:XCHG OPRD1,OPRD2
其中的两个操作数只可以是通用寄存器或存储器,但不能同时是存储器。那七种寻址方式也可以在这里使用。
3.地址传送指令
一共有三条地址传送指令:LEA、LDS、LES。
其中LEA是传送有效地址指令,格式为:LEA REG,OPRD。
此指令将一个存储器操作数的有效地址传送到一个16位的通用寄存器中。注意这个指令与MOV的区别,MOV是传送操作数的值,而这个指令是传送操作数的有效地址,即偏移值。另两条指令与LEA类似,但不同的是,它们传送的是一个32位的地址指针OPRD,并将其段值部分送到DS或ES中(LDS送到DS中,LES送到ES中),偏移部分则送到通用寄存器REG中。
二.堆栈操作指令
首先汇编语言中规定地址较大的一端为栈底,地址较小的一端为栈顶,堆栈的段值存储在SS中,SP则始终指向栈顶,并且进出堆栈的数据均以字为单位,即16位。
1.进栈指令
格式为:PUSH OPRD
用于将数据压入堆栈,并遵守高高低低原则,即高地址存储高位,低地址存储低位。其中OPRD可以是通用寄存器或段寄存器,也可以是字存储单元。
2.出栈指令
格式为:POP OPRD
此指令与PUSH正好相反,其它和PUSH基本一样,只是OPRD不能是代码段寄存器CS。
三.标志操作指令
1.标志传送指令
这些指令用于将标志寄存器中部分位(包括符号标志SF、零标志ZF、扶助进位标志AF、奇偶标志PF、进位标志CF。)传送到某个寄存器或从某个寄存器读取操作数传送到标志寄存器。
1)LAHF指令
格式为:LAHF
它将标志寄存器的低8位(也就是SF、ZF、AF、PF、CF所在区间)传送到AH的对应位,但这条指令并不会影响编址寄存器中的值。
2)SAHF指令
格式为:SAHF
这条指令与LAHF相反,它是将AH中的数据传送到标志寄存器中。但它不会影响其他四个标志(OF、DF、IF、TF)。
3)PUSHF指令
此指令将标志寄存器的全部内容压入堆栈,但不改变寄存器内容。
4)POPF指令
此指令与PUSHF相反,它读取堆栈顶部的一个字并传送到标志寄存器中,寄存器中的各位都会发生变化。
其中3、4条指令也是改变追中标志TF的一种途径(注意:第1、2条无法对标志寄存器的高8位进行修改,所以无法改变TF标志,而且在8086/8088指令系统中也没有专门修改TF的指令)
2.标志位操作指令
这些标志只对进位标志CF、方向标志DF和中断允许标志进行操作。
其中有清进位标志指令CLC(将进位标志清0)、置进位标志指令STC(将进位标志置为1)、进位标志取反指令CMC(取反应该都知道干嘛的。。。)、清方向标志CLD、置方向标志STD、清中断允许标志CLI、置中断允许标志STI。
四.加减法运算指令
这一块东西较多,也不是很难,就不细说了,个人感觉主要要注意一下指令的两个操作数的来源和搭配问题,而且这些指令只适用5种存储器寻址方式,即立即寻址方式、寄存器间接寻址方式、寄存器相对寻址方式、基址加变址寻址方式、相对基址加变址寻址方式。同时,加减法指令不分有无符号之分,这点与后面的乘除法指令不同。
1)加减法运算中,关于对标志寄存器的影响,对有符号数和无符号数是一样的,也就是他们的运算都会影响到标志寄存器中CF、AF、OF、SF、ZF、PF(有些例外如INC,这个运算不影响CF)
2)参与加减运算的只能是存储器+通用寄存器、通用寄存器+通用寄存器、通用寄存器+立即数,结果存储在通用寄存器中。或者是立即数+存储器、通用寄存器+存储器,结果存储在存储器中。
3)个人总结了一下比较指令CMP的结果与两个操作数大小的关系,注意:我自己总结的,仅供参考,不保证全对这条指令进行OPRD1-OPRD2,但结果不传送到OPRD1中,只影响标志寄存器
根据ZF判断是否相等:
若ZF = 1,则两个操作数相等
若为无符号数,则根据CF判断大小:
若CF = 1,则OPRD1 < OPRD2
若CF = 0,则OPRD1 >= OPRD2
若为有符号数,则根据SF和OF判断大小:
若SF = 1, OF = 1,则OPRD1 > OPRD2
若SF = 1, OF = 0,则OPRD1 < OPRD2
若SF = 0, OF = 1,则OPRD1 < OPRD2
若SF = 0, OF = 0,则OPRD1 > OPRD2
五.乘除法运算指令
也不多说了。。。太多了。。。乘除法指令与加减法区别挺多的,首先,乘除法指令分为有符号和无符号,例如无符号乘法指令MUL,有符号乘法指令IMUL;另外,乘除法指令对于标志位的影响与加减法指令不同,这点要注意一下;同时,乘除法指令只给出一个操作数,另一个操作数是存在某寄存器中,不像加减法指令那样同时给出两个操作数。
1)乘法指令中,一个操作数总是隐含在寄存器AL(若另一个操作数为8位)或者AX(另一个操作数16位),另一个操作数可以使用除立即寻址方式以外的任何寻址方式。
2)无符号乘法指令MUL、有符号乘法指令IMUL只影响CF和OF;除法指令和符号扩展指令对标志位均无影响。
3)除法指令中被除数总是隐藏在AX(若除数是8位)或者DX和AX(除数是16位),除数可以使用除立即寻址方式以外的任何寻址方式。
4)注意字节转换为字指令CBW会将原AH中的数据覆盖掉,字转换为双字指令CWD则会覆盖DX
六.逻辑运算和移位指令
好吧。。。我承认我有点懒。。。逻辑运算指令和移位指令主要就是指令对标志位的影响比较乱,这个需要注意一下。再有就是移位指令对于移位之后空位的补充规则。其他的就没什么困难的。
1)若有两个操作数,则结合方式与加法指令中的一样,若只有一个操作数,则该操作数既是源又是目的。
2)某个操作数自己与自己进行“与”、“或”运算时,操作数值不变,若进行“异或”,则结果为0。
3)“或”、“与”、“异或”运算进行后,CF = 0,OF = 0,PF、ZF、SF反映运算结果,AF不受影响。
4)算数左移指令和逻辑左移指令格式不一样,但实质是一样的。
5)一般移位指令运行后,PF、SF、ZF反映运算结果,OF也受影响,但AF不受影响。
七.转移指令
唉。。。我真是太懒了。。。— —!
这些指令主要是用来控制程序流程的,和C++中的循环语句、条件语句很相似(当然,这个用起来要麻烦得多。。。)。主要就是条件转移指令有很多条,需要多记记。
1)转移指令其实和C++中的goto语句极为相似。。。就是设立个标志,然后跳过去,然后花样多一点。
2)循环指令其实和转移指令差不多,只是使用起来可能方便一些。