汇编语言之8086/8088指令系统

Typist : Akame Qixisi / Excel Bloonow

在我学习汇编语言(基于8086)的过程中,遇到过一些想要某些操作却不知道指令的情况,所以在这里统一记录一下。如有错误或不同观点欢迎批评指出。

8086/8088指令系统

8086/8088指令系统的指令分为7类,即数据传送、算术运算、逻辑操作、程序控制、数据串操作、处理器控制、输入输出。在学习指令系统时,应该从4个方面掌握这个指令,如下:

  1. 掌握指令的功能:该指令能够实现何种操作,通常指令助记符就是指令功能的英文单词或器缩写形式。
  2. 分析指令支持的寻址方式:该指令中的操作数可以采用何种寻址方式。
  3. 清楚指令对标志位的影响:该指令执行后是否对各个标志位有影响,以及如何影响。
  4. 其他特征:如指令执行时的约定设置、必须预置的参数、隐含使用的寄存器等。

数据传送类指令

实现数据从一个位置到另一个位置的移动,如执行寄存器与寄存器之间、寄存器与主存单元之间的字或字节的多种传送操作。

1. 数据传送指令 mov

mov oprd1, oprd2	; oprd1 = oprd2
  • 该指令将一个8位或16位的源操作数(字或字节)送到目的操作数中。本指令不影响状态标志位。
  • oprd1,目的操纵数,可以是寄存器、存储器、累加器、标号。
  • oprd2,源操作数,可以是寄存器、存储器、累加器、立即数、标号。
  • 立即数只能作为源操作数,不能作为目标操作数,立即数也不能传送至段寄存器。
  • 存储器与存储器之间不能进行数据直接传送。若要实现存储单元之间的数据传送,可以借助于通用寄存器作为中介来进行。
  • 指令指针IP不参加数的传送;代码段寄存器CS可以作为源操作数参加传送,但不能作为目的操作数参加传送。
  • 源操作数和目的操纵数的类型应一致,可以使用byte ptrword ptr指定其后跟的是一个字节还是一个字,告诉编译程序按什么类型处理,生成相应的指令代码。如两侧都是内存单元时,或者使用标号label等无法确定具体位数时。其中ptr称为指针操作符,作用是将后跟的标号或者内存单元定义为新的变量类型,如byte或word,这个变量的起始地址没有改变。

2. 数据交换指令 xchg

xchg oprd1, oprd2
  • 该指令把操作数oprd1与操作数oprd2交换。本指令不影响状态标志位。

  • oprd1位目标操作数,oprd2为源操作数,可为通用寄存器、存储器。

  • xchg指令不支持两个存储器单元之间直接数据交换,但通过中间寄存器,可以很容易的实现两个存储器操作数的交换。

  • 段寄存器中的内容不能用xchg来交换。

3. 换码指令 xlat

xlat	; (AL) = (DS:[(BX)+(AL)])
  • 该指令把待查表格的一个字节内容送到AL中。执行该指令前,应先把TABLE表格的地址值送至BX寄存器中,然后将待查字节在表格中距离表格首地址的偏移地址送AL,然后使用xlat指令将对应地址上的值取到AL中。段地址是DS提供的。本指令不影响状态标志位。
  • 使用前首先在主存中建立一个字节表格(即DS中一段连续的存储空间),表格的内容是要转换成的目标代码。xlat指令中没有显示指明操作数,而是默认使用bx和al寄存器,这种采用默认操作数的方法称为隐含寻址方式。
  • 由于AL的内容实际上是距离表格首地址的移位量,只有8位,所以表格的最大长度为256;超过256的表格需要采用修改BX和AL的方法才能转换。
  • 换码指令常用于将一种代码转换为另一种代码,如扫描码转为ASCII码,数字0到9转换为七段显示码等。

4. 堆栈操作指令

push oprd
  • 该指令将16位(字)操作数oprd压栈,oprd可以是寄存器或者存储器操作数。本指令不影响状态标志位。
  • push的操作过程是:先修改堆栈指针SP(入栈时为自动减2h),然后将指定的操作数送入新的栈顶位置。随着入栈内容的增加,堆栈就扩展,SP值减少,但每次操作完,SP总是指向堆栈的顶部。
  • 实际上,诸如push ax压栈时,实际上是先SP减1,送AH,再SP减1,送AL。
pop oprd
  • 该指令将栈顶的16为(字)弹出到oprd操作数,oprd可以是寄存器或存储器操作数。本指令不影响状态标志位。
  • 它与入栈的操作相反,是先弹出栈顶的数据,然后再修改指针SP的内容。

5. 标志传送指令

lahf
  • 取FLAGS标志寄存器低8位至AH中。该指令不影响FLAGS的原来内容,AH只是复制了原FLAGS的低8位内容。
sahf
  • 将AH存至FLAGS标志寄存器的低8位。本指令将用AH的内容改写FLAGS中的SF、ZF、AF、PF和CF标志,从而改变原来的标志位。
pushf
  • 本指令可以把FLAGS的内容保存到堆栈中去。
  • 在子程序调用和中断服务程序中,往往用pushf指令保护FLAGS的内容,用popf指令恢复保护的FLAGS中的内容。
popf
  • 从堆栈中弹出一个数据字送至FLAGS中。

6. 地址传送指令

地址传送指令将存储器的逻辑地址送至指定的寄存器。

lea oprd1, oprd2	; mov oprd1, offset oprd2
  • 该指令将源操作数oprd2给出的有效地址(段内偏移量)传送到指定的寄存器中。本指令对标志寄存器无影响。
  • oprd1,目标操作数,可以位任意一个16位的通用寄存器。
  • oprd2,源操作数,可为变量名、标号、地址表达式。
  • 如果要将一个存储器变量的地址取至某一个寄存器中,也可以通过offset label来获取一个标号label的段内偏移量。
lds oprd1, oprd2
les oprd1, oprd2
  • 从存储器取出段地址和偏移地址放到oprd1所指定的16位寄存器中。本指令不影响标志寄存器。
  • oprd1,目标操作数,可以为任意一个16为寄存器。
  • oprd2,源操作数。可以为一个内存单元地址变量,该地址指定了主存的连续4个字节作为逻辑地址,低2个字节存放到oprd1中,高2各字节存放到DS或ES中(由指令确定)。可以为一个label标号,使用的是由DS:label指定的地址处的4个连续的4个字节作为逻辑地址。
offset label
seg label
  • 分别取标号的偏移地址和段地址。

算术运算类指令

算术运算类指令用来执行二进制及十进制的算术运算,主要包括加减乘除指令。二进制数运算分为带符号数运算和不带符号数运算。十进制数用BCD码表示,又分为非压缩的BCD码和压缩的BCD码两种形式。

算术运算类指令会根据运算结果影响状态标志位,有时要利用某些标志才能得到正确的结果。该类指令主要影响6个标志位,即CF、AF、SF、ZF、PF、OF。

1. 加法指令

add oprd1, oprd2	; oprd1 = oprd1 + oprd2
  • 该指令实现字或字节的加法运算,适用于无符号数及带符号数的8位或16位加法运算。对CF、AF、SF、ZF、PF、OF结果标志都有影响。
  • oprd1,目标操作数,可以是任意一个通用寄存器,也可以是任意一个存储器操作数。在执行add之前,oprd1中的内容为一个加数,待add指令执行后,oprd1中为加法运算的结果即和。
  • oprd2,源操作数,可以是任意一个通用寄存器或存储器操作数,也可以是立即数。
  • oprd1和oprd2均为寄存器是允许的,一个为寄存器另一个为存储器也是允许的,但不允许两个都是存储器操作数。
adc oprd1, oprd2	; oprd1 = oprd1 + oprd2 + CF
  • 带进位的加法指令,适用于无符号数及带符号数的8位或16位加法运算。对标志位的影响同add指令。
  • oprd1和oprd2两个操作数与指令add中的含义一样。
inc oprd	; oprd = oprd + 1
  • 加一指令,对给定的寄存器或存储单元内容加1后,再送回该操作数,可以实现字节加1或字加1。该指令不影响CF标志位,影响其他标志位。
  • oprd为寄存器或存储器操作数,寄存器不能是段寄存器。
  • 在循环程序中,常用该指令对地址指针和循环计数值进行修改。

2. 减法指令

sub oprd1, oprd2	; oprd1 = oprd1 - oprd2
  • 该指令实现两个操作数的减法操作,操作数可为8位或16位的无符号数或带符号数。对标志位的影响同add指令。
  • 注意立即数不能用于目的操作数,两个存储器操作数之间不能直接相减。
sbb oprd1, oprd2	; oprd1 = oprd1 - oprd2 - CF
  • 带进位的减法指令,操作数可为8位或16位的无符号数或带符号数。对标志位的影响同sub指令。
dec oprd	; oprd = oprd - 1
  • 减一指令,对给定的寄存器或存储单元内容减1后,再送回该操作数,可以实现字节减1或字减1。该指令不影响CF标志位,影响其他标志位。
  • oprd为寄存器或存储器操作数,寄存器不能是段寄存器。
  • 在循环程序中,常用该指令对地址指针和循环计数值进行修改。
neg oprd
  • 取补指令,该指令对操作数执行求补运算,即用basen减去操作数,然后将结果返回操作数。二进制的求补运算也可以表达成,将操作数按位取反后加1。
  • oprd为任意通用寄存器或存储器操作数。
  • neg指令对标志状态位的影响与用0(如果当前位不够减,在最高位的前一位补1,则用basen减就相当于用0减)做减法的sub指令一样。
cmp oprd1, oprd2
  • 比较指令,该指令该指令用于改变标志位,它对标志位的影响同sub指令,完成的操作与sub指令类似,唯一的区别是不将oprd1-oprd2的结果送回oprd1中,而只是比较。
  • oprd1和oprd2可以为任意通用寄存器或存储器操作数,但两者不同时为存储器操作数,立即数可用于做源操作数oprd2。

3. 乘法指令

相同的二进制数看作无符号数还是有符号数相乘,采用mul或imul指令,其运算结果时不相同的。

mul oprd	; 16位 = 8位 * 8位:(AX) = (AL) * oprd
			; 32位 = 16位 * 16位:(DX)(AX) = (AX) * oprd
  • 无符号数乘法指令,该指令可用于无符号数的8位乘法或16位乘法。该指令影响CF、OF标志位。
  • oprd,源操作数,即乘数。可以为通用寄存器或存储器操作数,根据它的位数确定是8位乘法还是16位乘法。
  • 目的操作数是隐含的,即被乘数总是指定为累加器AX或AL的内容。
    • 8位字节乘法时,AL为被乘数,16位积存放于AX中;当结果的高位字节(AH)≠0时,则CF=OF=1。
    • 16位字乘法时,AX为被乘数,32位积存于DX和AX中;当结果的高位字(DX)≠0时,则CF=OF=1。
imul oprd
  • 带符号数乘法指令,该指令的功能是完成两个带符号数的相乘。该指令影响CF、OF标志位。
  • oprd,源操作数,即乘数。可以为通用寄存器或存储器操作数。
  • 隐含操作数的定义于mul指令相同。

4. 除法指令

除法指令div和idiv不产生有效的标志位,但是却可能产生溢出。当被除数远大于除数时,或除数位0时,所得的商就有可能超出它所能表达的范围。

符号扩展是用一个操作数的符号位(即最高位)形成另一个高位操作数,它的各位全是0(正数)或全是1(负数)。符号扩展指令可用来将字节转换为字,字转换为双字;有符号数通过符号扩展加长了位数,但数据的大小没有改变。符号扩展指令常用来获得有符号数除法指令所需的被除数;对于无符号数应该采用直接使用高8位或高16位清0的方法,获得被长的被除数,即0位扩展。

div oprd	; 8位 = 16位 / 8位:(AL) = (AX) / oprd, (AH) = (AX) % oprd
			; 16位 = 32位 / 16位:(AX) = (DX)(AX) / oprd, (DX) = (DX)(AX) % oprd
  • 无符号数除法指令,该指令的功能时实现两个8位或16位无符号数二进制除法运算。
  • oprd,源操作数,存放的是除数。可以为通用寄存器或存储器操作数,根据它的位数确定是16位除法还是32位除法。
  • 目的操作数是隐含的,即被除数总是指定为AX或DX的内容。
    • 16位字除法时,AX为被除数,8位商存放于AL中,8位余数存放于AH中。
    • 32位双字除法时,DX和AX为被除数,16位商存放于AX中,16位余数存放于DX中。
idiv oprd
  • 带符号数的除法指令,该指令的功能是实现两个带符号数的二进制除法运算,余数的符号与被除数符号相同。
  • oprd,源操作数,可以为通用寄存器或存储器操作数。
  • 隐含操作数的定义与div指令相同。
cbw
  • 有符号数的字节扩展指令,该指令的功能是将字节扩展为字,即把AL寄存器的符号位扩展到AH中。两个字节相除时,先使用本指令形成一个两字节的被除数。该指令不影响标志位。
cwd
  • 有符号数的字扩展指令,该指令的功能是将字扩展为双字长,即把AX寄存器的符号位扩展到DX中。两个字相除时,先使用本指令形成一个两字长的被除数。

5. 十进制调整指令

十进制数在计算机中也要用二进制编码表示即BCD码,8086/8088支持压缩BCD码和非压缩BCD码。

  • 压缩BCD码是通常的8421码,它用4个二进制位表示一个进制数,一个字节可以表示两位十进制数,即00~99。
  • 非压缩BCD码用8个二进制位表示一个十进制数,一个字节可以表示一位十进制数,即0~9。非压缩BCD码的高4位通常默认为0。ASCII码中0~9的编码是30H~39H,所以0~9的ASCII码(高4位变为0)就可以认为是非压缩的BCD码。由于只要在调整后的结果中加上30H就成为十进制数位的ASCII码,因此这组针对非压缩BCD调整的指令实际上也是针对ASCII码的调整指令。

在进行十进制数的算术运算时,应该分为两步进行:先按二进制数运算规则进行运算,得到中间结果;再用十进制调整指令对中间结果进行修正,得到正确结果。

需要修正的原因是,按照二进制进行运算没有错误,但如用4位二进制按照压缩BCD码表示十进制,十进制实际上是逢十进一,而4位二进制数是逢0AH进一。这就会出现问题,即目标结果BCD码的二进制串,与直接按二进制数运算得来的二进制串不一致,需要进行调整。需要用到AF标志位。

结论:加法运算后,低4位大于9时,需要做加06H处理;高4位大于9时,需要做加60H处理;减法则反之减去。

daa
  • 对压缩BCD码加法运算进行校正。一般在add指令把两个压缩BCD相加之后,紧接着用一条daa指令对AL内容加以校正,在AL中可以得到正确的结果。
das
  • 对压缩BCD码减法运算进行校正。一般在sub指令把两个压缩BCD相减之后,紧接着用一条das指令对AL内容加以校正,在AL中可以得到正确的结果。
aaa
  • 对非压缩BCD码加法运算进行校正。一般在add指令把两个非压缩BCD相加之后,紧接着用一条aaa指令对AL中的内容加以校正,在AX中可以得到正确结果。
aas
  • 对非压缩BCD码减法运算进行校正。一般在sub指令把两个非压缩BCD相减之后,紧接着用一条aas指令对AL中的内容加以校正,在AX中可以得到正确结果。
aam
  • 对非压缩BCD码乘法运算进行校正。一般在mul指令把两个非压缩BCD(要求高4位为0)相乘之后,紧接着用一条aam指令对AL中的内容加以校正,在AX中可以得到正确结果,商放在AH中,余数放在AL中。
aad
  • 对非压缩BCD码除法运算进行校正。它与其他校正指令不同,如果被除数是存放在AH和AL中的两位非压缩BCD(要求高4位为0),除数是一个非压缩BCD数(高4位为0),要先用aad指令把AX中的被除数调整为二进制数,并存放在AL寄存器中。之后才能调用div指令。

逻辑操作类指令

逻辑操作类指令是按位操作指令,可以对8位或16位的寄存器或存储器单元的内容按位操作。

1. 逻辑运算指令

and oprd1, oprd2
  • 该指令实现对两个操作数按位进行逻辑与的运算,结果送至目的操作数,可进行字节或字的与运算。该指令影响标志位PF、SF、ZF,是CF=0,OF=0。
  • oprd1,目的操作数,可以为任意通用寄存器或存储器操作数。两个操作数不能同时位存储器寻址方式。
  • oprd2,源操作数,可以为任意通用寄存器或存储器操作数,也可以是立即数。
  • 本指令主要用于修改操作数或置某些位为0。
or oprd1, oprd2
  • 该指令实现对两个操作数按位进行逻辑或的运算,结果送至目的操作数,可进行字节或字的或运算。对标志位的影响同and指令。
  • oprd1,目的操作数,可以为任意通用寄存器或存储器操作数。两个操作数不能同时位存储器寻址方式。
  • oprd2,源操作数,可以为任意通用寄存器或存储器操作数,也可以是立即数。
  • 本指令主要用于置位某些位为1,而不影响其他位,只需要将要置位的位同1相或,保存不变的位同0相或。
not oprd
  • 该指令实现对操作数的按位求反运算,结果送回原操作数,可进行字节或字的求反运算。不影响标志位。
  • oprd可为任意通用寄存器或存储器操作数。
xor oprd1, oprd2
  • 该指令实现两个操作数进行按位异或运算,结果送至目的操作数,可进行字节或字的或运算。对标志位的影响同and指令。
  • oprd1,目的操作数,可以为任意通用寄存器或存储器操作数。两个操作数不能同时位存储器寻址方式。
  • oprd2,源操作数,可以为任意通用寄存器或存储器操作数,也可以是立即数。
  • 本指令主要用于求反某些位,而不影响其他位,要求反的位同1异或,维持不变的位同0异或。
test oprd1, oprd2
  • 也是对oprd1和oprd2进行按位逻辑与运算,操作数的含义也同and,对标志位的影响也同and。
  • 唯一不同的是该指令不会把结果写回oprd1目的操作数,仅是为了在逻辑与操作后,对标志位进行重置。
  • 该指令通常用于检测一些条件是否满足,但又不希望改变原操作数的情况。这条指令之后,一般都是条件转移指令,目的是利用测试条件转向不同的程序段。

2. 逻辑移位指令

shl oprd1, count
  • 逻辑左移指令,该指令的功能是对8位或16位目的操作数左移count次,每次一位,每次移位时最高移位入标志位CF中,最低位补0。该指令对OF、PF、SF、ZF、CF有影响。
  • oprd1,目的操作数,可以是任意通用寄存器或存储器操作数。
  • count,代表移位的次数(或位数),移位一次,count=1,移位多于一次时,CL=count指定移位次数。
shr oprd1, count
  • 逻辑右移指令,该指令的功能是对8位或16位目的操作数右移count次,每次一位,每次移位时最低移位入标志位CF中,最高位补0。
  • oprd1和count的含义同shl指令。
sal oprd1, count
  • 算术左移指令,该指令的功能是对8位或16位目的操作数左移count次,每次一位,每次移位时最高移位入标志位CF中,最低位补0,这些功能同指令shl一样。而且,如果sal将oprd1的最高移位至CF时改变了CF原来的值,则溢出标志位OF=1,表示移位前后的操作数不再是倍增关系。因而sal可用于带符号数的倍增运算,shl只能用于无符号数的倍增运算。
  • oprd1和count的含义同指令shl中的含义。
sar oprd1, count
  • 算术右移指令,该指令的功能是对8位或16位目的操作数右移count次,每次一位,每次移位时最低移位入标志位CF中,最高位(符号位)保持不变。
  • oprd1和count中的含义同指令shl中的含义。
  • 该指令通常用于对带符号数的减半运算中。

3. 循环移位指令

循环移位指令实现的是操作数首尾相连的移位操作,要求从一端移除出的数据返回到另一端形成循环。这类指令只影响CF和OF。按进位标志CF是否参加循环移位,又可分为带CF的和不带CF的,每类都有可左移或右移。OF取决于位移一次后符号位是否改变,如果改变则OF=1。由于是循环移位,对字节连续移动8次,对字连续移动16次就会变为原操作数。

rol oprd1, count
ror oprd1, count
  • 不带进位CF的循环移位指令。左移时移出的最高位,右移时移出的最低位,会放入CF中。
rcl oprd1, count
rcr oprd1, count
  • 带进位CF的循环移位指令。左移时移出的最高位放入CF中,CF放入最低位中;右移时移出的最低位放入CF中,CF放入最高位中。

程序控制类指令

利用程序控制指令,可以实现分支、循环、子程序等程序结构。

1. 无条件转移指令

jmp oprd
  • 无条件转移指令,默认是段内转移。
  • oprd,源操作数,可以为通用寄存器。它的功能是用寄存器的内容修改IP,即(IP) = (16位寄存器),它是段内转移。使用寄存器在程序中是可变的,更灵活。值得注意的是,jmp 2000:0000之类用立即数给出的形式,只能够用在debug环境下,如果出现在源程序中,编译器是无法识别和编译的。
jmp short label
jmp near ptr label
jmp far ptr label
  • 如果使用jmp label,有以上几种。在段内转移的机器指令中,包含的是跳转到目标指令的相对位置,而不是转移的目标地址。位移=目标地址-jmp指令的下条指令的起始地址,在编译时算出。
  • jmp short label,段内短转移,IP修改范围为-128~127一个字节。功能是(IP) = (IP) + 8位位移,关键字short用来指明位移是8位,用补码表示。
  • jmp near ptr label,段内近转移,IP修改范围为-32768~32767两个字节。功能是(IP) = (IP) + 16位位移,关键字near ptr用来指明位移是16位,用补码表示。
  • jmp far ptr label,段间转移(远转移),同时修改CS和IP。在它的机器指令中包含的直接是目标指令的段地址CS和偏移地址IP。
jmp word ptr oprd
jmp dword ptr oprd
  • 如果使用内存地址单元上的值来给出转移地址,有以上几种。内存单元的地址可以由多种寻址方式给出。
  • jmp word ptr oprd,段内转移,从内存单元地址上取一个字,作为转移的偏移地址。
  • jmp dword ptr oprd,段间转移,从内存单元地址上取两个字,高地址的字表示要转移目标的段地址,低地址的字表示偏移地址。

2. 条件转移指令

通常在转移之前先调用如cmp oper1, oper2之类的可以影响PSW的指令,然后调用以j开头的jxxx类指令。需要知道的是:j = Jump、e = Equal、n = Not、b = Below、a = Above、l = Less、g = Greater、s = Sign、c = Carry、p = Parity、o = Overflow、z = Zero。它们都可以跟在 j 之后,也可以一起组合跟在 j 之后。需要注意的是,a 和 b 是对整个机器位比较,即无符号数;而 l 和 g 是将整个机器数看作有符号数,进行比较;它们的测试条件是不同的。

jxxx oprd
  • 条件转移指令的操作数必须是一个短标号,也就是说所有的条件转移指令都是两字节指令,转移指令的下一条指令到目标指令之间的距离必须为-128~127之间。如果指令规定的条件满足,则将这个位移量加到IP寄存器上,即条件转移本质上是修改IP的值。
jcxz oprd
  • 当(cx) = 0时,则转移到标号处执行;否则cx不为0,则什么也不做,程序向下执行。使用jcxz不仅仅可以处理循环。

根据单个标志位状态判断的条件转移指令,如下表:

助记符指令名称测试条件
je、jz等于、零转移ZF=1
jne、jnz不等于、非零转移ZF=0
js负转移SF=1
jns正转移SF=0
jp、jpe偶数个1转移PF=1
jnp、jpo奇数个1转移PF=0
jo溢出转移OF=1
jno不溢出转移OF=0
jc进位转移CF=1
jnc不进位转移CF=0

用于无符号数的比较跳转指令,如下表:

助记符指令名称测试条件
jb、jnae低于、不高于等于CF=1
jnb、jae不低于、高于等于CF=0
ja、jnbe高于、不低于等于CF=1 且 ZF=0
jna、jbe不高于、低于等于CF=0 或 ZF=1

用于有符号数的比较跳转指令,如下表:

助记符指令名称测试条件
jg、jnle大于、不小于等于SF=OF 且 ZF=0
jng、jle不大于、小于等于SF != OF 或 ZF=1
jl 、 jnge小于、不大于等于SF != OF 且ZF=0
jnl 、 jge不小于、大于等于SF = OF

3. 循环控制指令

循环流程的条件一般时循环计算,指令约定用CX寄存器作为计数器,它的循环体至少执行一次。这类指令属于段内短转移,目标地址必须在距本指令-128~127个字节的范围内。

loop label
  • 先将(CX)减一,再判断(CX)是否为0,如果(CX)≠0时,则转移到标号处执行;直到(CX)=0,跳出循环继续执行后续程序。该指令不影响标志位。
loopz label
loope label
  • 先将(CX)减一,再判断(CX)是否为0,如果(CX)≠0且ZF=1时,则转移到标号处执行;直到(CX)=0或ZF≠1时,跳出循环继续执行后续程序。该指令不影响标志位。
loopnz label
loopne label
  • 先将(CX)减一,再判断(CX)是否为0,如果(CX)≠0且ZF=0时,则转移到标号处执行;直到(CX)=0或ZF≠0时,跳出循环继续执行后续程序。该指令不影响标志位。

4. 过程调用和返回指令

相当于子程序或者说函数的调用与转移,实质上是修改 IP 寄存器甚至 CS 寄存器的值。不要忘了为call和ret指定栈段。call和ret指令不影响标志位。

call oprd
  • 段内间接调用,过程与调用指令同处在一个代码段内。oprd为16为通用寄存器或存储器操作数或label。
  • 本指令执行时,先将IP的内容入栈保护(SP减2),然后从由oprd指定的寄存器或存储器中取出一个字,即目的地址在段内偏移量,送入IP中,从而实现过程调用。
call near ptr label
  • 段内直接调用,过程与调用指令同处在一个代码段内。
  • 本指令执行时,先将IP的内容入栈保护(SP减2),然后将指令代码中给出的目标地址的段内偏移量送入IP,从而实现过程调用,将程序转至过程入口。
call word ptr oprd
  • 段内调用,也可以使用存储器操作数指定目标地址。
  • 本指令执行时,先将IP的内容入栈保护。然后从由oprd指定的存储器中取出一个字,即目的地址在段内偏移量,送入IP中,从而实现过程调用。
call far ptr label
  • 段间调用,过程与调用指令可以在不同的代码段中。
  • 本指令执行时,应先将CS压栈,再将IP压栈(SP减4),然后将far类型的过程名所在的段地址和段内偏移地址送入CS及IP,从而实现过程调用。
call dword ptr oprd
  • 段间调用,也可以使用存储器操作数指定目标地址。
  • 本指令执行时,先将SP再将IP的内容入栈保护。然后从由oprd指定的存储器中取出两个字,高地址字作为段地址送入CS,低地址的字作为段内偏移量送入IP,从而实现过程调用。
ret
  • 段内返回指令,当调用的过程结束后实现从过程返回至原调用程序的下一条指令。
  • 本指令执行时,实际上是从栈中取栈顶的数据,恢复IP,因而可以没有与它匹配的call指令,但也要注意是否对栈进行了操作导致栈顶不是IP从而返回错误。
retf
  • 段间返回指令,本指令执行时,实际上是先从栈顶取一个字送入IP、再取一个字送入CS。

5. 中断指令

处理器终止当前程序的运行,转去执行中断处理程序的情况称为“中断”,中断子程序执行完后返回原来程序的断点。8086/8088具有很强的中断系统,可以处理256个不同方式的中断,每一个中断赋予一个中断向量码,CPU根据中断向量码来识别不同的中断源。

8086/8088内部中断源有除法错中断、单步中断、断点中断、溢出中断、用户自定义的软中断5中类型;外部中断是指来自CPU之外的原因引起的程序中断,分为可屏蔽中断和非屏蔽中断2种类型。

into
  • 溢出中断指令,该指令检测OF标志位,当OF=1发生溢出时,立即产生一个中断类型4的中断;当OF=0时,本指令不起作用。
int n
  • 软中断指令,本指令将产生一个软中断,把控制转向一个类型号为n的软中断,该中断处理程序的入口地址在中断向量表的n*4的地址处的两个存储字(4个字节单元)中。
iret
  • 中断返回指令,用于中断处理程序中,从中断程序的断点处返回,继续执行原程序。本指令影响所有标志位。
  • 无论是软中断,还是硬中断,本指令均可使其返回到中断程序的断点处继续执行原程序。

串操作类指令

数据串可以时字节串,也可以是字串,数据串只能放在存储器中。对数据串进行处理时,可以只操作一个串也可以操作两个串,根据数据串中数据流动的方向,可以分为源数据串和目的数据串。

在串操作指令中,源数据串用寄存器SI寻址,默认在数据段DS中,允许段超越;目的数据串用寄存器DI寻址,默认在附加段ES中,不允许段超越。每执行一次串操作指令,地址指针SI、DI都会自动修改:对于字节串会±1,对于字串会±2;增加还是减少取决于方向标志DF。

cld
  • 清楚标志位,使DF=0(默认),此时地址指针向高地址变化,即增加。
std
  • 设置标志位,使DF=1,此时地址指针向低地址变化,即减少。

1. 串传送指令

movs oprd1, oprd2
movsb	; byte, ES:[DI] = DS:[SI], (SI) = (SI) ± 1, (DI) = (DI) ± 1
movsw	; word, ES:[DI] = DS:[SI], (SI) = (SI) ± 2, (DI) = (DI) ± 2
  • 串传送指令movs,将数据段主存单元的1个字节或字,传送到附加段的主存单元中。定义数据串时,要求原串和目的串类型一致,并以其区别是字节或字操作。该指令不影响标志位。
  • 指令movsb和movsw,分别对字节串和字串操作。若DF=0,则从当前位置向后;若DF=1,则从当前位置向前。

2. 串比较指令

cmps oprd1, oprd2
cmpsb
cmpsw
  • 串比较指令cmps,对一个字节或字进行比较,比较结果送至标志位,而不改变操作数本身。该指令影响标志位AF、CF、OF、SF、PF、ZF。
  • 指令cmps,可用来检查两个字符串是否相同,可以使用循环控制方法对整个字符串进行比较。
  • 指令cmpsb和cmpsw,分别比较一个字节或一个字。要比较的字符将由SI和DI指定,同时DI、SI将根据DF自动调整。

3. 串扫描指令

scas oprd
scasb
scasw
  • 串扫描指令scas,将AL或AX中的内容与oprd指定的存储器单元中的数据进行比较,根据比较结果设置标志位,但不改变操作数本身。该指令影响标志位AF、CF、OF、SF、PF、ZF。
  • 指令scas,可查找字符串中一个关键字,只需要在本指令执行前,把关键字放入AL或AX中,用重复前缀可在整串中查找。
  • 指令scasw和scasw,分别将ES:[DI]指定的一个字节或字的数据,与AL或AX寄存器中的数据比较,同时DI将根据DF自动调整。

4. 串读取指令

lods oprd
lodsb
lodsw
  • 串读取指令lods,把由oprd指定的存储器单元中的数据读入到AL或AX中。该指令不影响标志位。
  • 指令lodsb和lodsw,分别将DS:[SI]指定的一个字节或一个字的存储器单元数据,送入到AL或AX寄存器中,同时SI将根据DF自动调整。

5. 字符串存储指令

stos oprd
stosb
stosw
  • 字符串存储指令stos,把用AL或AX中的数据内容送入由oprd指定的存储器单元中。该指令不影响标志位。
  • 指令stosb和stosw,分别将AL或AX中的数据内容,送入到DS:[DI]指定的存储器单元数据中,同时DI将根据DF自动调整。

6. 重复前缀指令

rep	command						; cx≠0,重复执行command
repz command	repe command	; cx≠0 且 ZF=1,重复执行command
repnz command	repne command	; cx≠0 且 ZF=0,重复执行command
  • 在串操作指令前加上重复前缀,可以对数据串进行重复执行command指令,重复的次数存放在cx寄存器中。
  • 指令rep与movs或stos串操作指令结合使用,完成一组数据的传送或建立一组相同数据的字符串。
  • 指令repz/repe与cmps串操作指令结合使用,完成两组数据串的比较。当两数据相同且串未结束时,重复执行串操作指令。它可以用来判断两数据串是否相同或查找第一个不相同的位置。
  • 指令repnz/repne与cmps串操作指令结合使用,当两数据不相同且串未结束时,重复执行串操作指令。它可以在两数据串中查找第一个相同数据的位置。
  • 指令repz/repe与scas串操作指令结合使用,完成在一个字符串中扫描一个关键字。当数据串中与关键字相同且串未结束时,重复执行串操作指令。它可以用于在一个数据串中找出第一个与关键字不匹配的位置。
  • 指令repnz/repne与scas串操作指令结合使用,完成在一个字符串中匹配一个关键字。当数据串中与关键字不相同且串未结束时,重复执行串操作指令。它用于在一个数据串中找出第一个与关键字匹配的位置。

处理器控制类指令

处理器控制指令用于控制CPU的动作,修改标志寄存器的状态等,实现对CPU的控制。

1. 标志位操作指令

标志位操作指令有7条,可以直接设置或清除CF、DF、IF、标志位,这些指令仅对有关的状态标志位执行操作,而对其他状态标志位则没有影响。

clc		; CF=0
stc		; CF=1
cmc		; CF求反
cld		; DF=0
std		; DF=1
cli		; IF=0,使CPU禁止响应外部的可屏蔽的中断请求
sti		; IF=1,使CPU允许响应外部的可屏蔽的中断请求

2. CPU控制指令

hlt
  • 处理器暂停指令hlt,使CPU进入暂停状态,这时CPU不进行任何操作。该指令不影响标志位。
  • 当CPU发生复位(RESET)或来自外部的中断(NMI或INTR)时,CPU脱离暂停状态。
  • 该hlt指令可用于程序中等待中断,当程序必须等待中断时,可用hlt,而不必用软件死循环。然后中断使CPU脱离暂停状态,返回执行hlt指令的下一条指令。
  • 注意:该指令在PC中将引起所谓的”死机“,一般的应用程序不要使用。
wait
  • 处理器等待指令wait,在8086/8088的测试引入脚为高电平无效时,使CPU进入等待状态,这时CPU并不做任何操作;测试为低电平有效时,CPU脱离等待状态,继续执行wait指令后面的指令。该指令不影响标志位。
  • 浮点指令经由8086/8088CPU处理发往8087,并与8086/8088本身的整数指令在同一个指令序列;而8087执行浮点数指令较慢,所以8086/8088必须与8087保持同步。8086/8088就是利用wait指令和测试引脚实现与8087同步运行的。
esc extoprd, oprd
  • 处理器交权指令esc,把浮点指令交给浮点处理器执行。为了提高系统的浮点运算能力,8086/8088系统中可加入浮点运算协处理器8087。但是8087的浮点指令是和8086/8088的整数指令组合在一起的,8086/8088主存中存储8087的操作码及其所需的操作数。当8086/8088发现是一条浮点指令时,就利用esc指令将浮点指令交给8087执行。该指令不影响标志位。
  • exroprd,外部操作码(浮点指令的操作码),是一个6位立即数。
  • oprd,源操作数,可以是寄存器或存储器单元。当oprd为寄存器时,它的编码也为操作码;如果oprd为存储器操作数,CPU读出这个操作数送给协处理器。
nop
  • 空操作指令nop不执行任何有意义的操作,但占用一字节存储单元,空耗一个指令执行周期。实际上,nop指令就是xchg ax, ax,它们的机器代码一样。该指令不影响标志位。
  • 在需要预留指令空间时用nop填充,代码空间多余时也可以用nop填充,还可以用nop指令实现软件延时。
lock command
  • 封锁总线前缀指令lock,它是一个指令前缀用于放在指令的前面。这个前缀使得当前指令执行时间内,8086/8088处理器的封锁输出引脚有效,即把总线封锁,使别的控制器不能控制总线,直到该指令执行完后,总线封锁解除。
  • 当CPU与其他处理器协同工作时,lock指令可用于避免破坏有用的信息。
CS: or SS: or DS: or ES:
  • 段超越前缀指令,在允许段超越的存储器操作数之前,使用段超越前缀指令,将不采用默认的寄存器,而是采用指定的段寄存器寻址操作数。

输入输出指令

输入输出指令有两条,,输入指令in用于从外设端口接收数据,输出指令out则向端口发送数据。无论是接收到的数据还是准备发送的数据,都必须先在寄存器AL或AX中。端口的寻址方式有两种,一是直接使用8位立即数n寻址256个端口(0~255),二是间接使用DX寄存器指定16位的地址寻址64K个端口(0~65535)。

1. 输入指令

in al, n	; (AL) = (n)
in ax, n	; (AX) = (n+1),(n)
in al, dx	; (AL) = seg:[(DX)]
in ax, dx	; (AX) = seg:[(DX+1)],seg:[(DX)]

2. 输出指令

out n, al	; (n) = (AL)
out n, ax	; (n+1),(n) = (AX)
out dx, al	; seg:[(DX)] = (AL)
out dx, ax	; seg:[(DX+1)],seg:[(DX)] = (AX)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值