§ 3.3.4 逻辑运算、移位、循环指令
1、 逻辑运算指令
逻辑运算有"与(AND)"、"或(OR)"、"非(NOT)"、"异或(XOR)"、"测试(TEST)"。
(1) 逻辑"与"AND
AND dst ,src
功能:dst←dst ∧ src,目的操作数dst与源操作数src对应位相"与",结果放在dst中。
(2) 逻辑"或"指令
OR dst ,src
功能:dst←dst ∨ src,目的操作数dst与源操作数src对应位相"或",结果放在dst中。
(3) 逻辑"异或"指令
XOR dst ,src
功能:dst←dst ⊕ src,目的操作数dst与源操作数src对应位相"异或",结果放在dst中。(异或:不同的数异或为1;相同的数异或为0)。
(4) 逻辑"非"指令
NOT dst
功能:dst←,目的操作数dst每一位取反后,放在dst中。
(5)"测试"指令
TEST dst,src
功能:测试dst中某些位是否为1,当要测试dst中某些位时,在src中对应位置1。该指令使用"与"运算进行测试,但"与"运算的结果不送给dst,而只反映在标志ZF中。当对应位为1时,ZF=1;当对应位为0时,ZF=0。
2、 移位指令
移位操作如图3-17所示。
SAL,SHL,SAR,SHR指令的格式相同,以SAL为例:
SAL DX,1 ; DX的值左移一位,最低位补0
SAL AX,CL ;AX的值左移CL位,最低位补0,
;CL=0,1,2,....,255
算术移位(SAL、SAR)把操作数看成有符号数。SAR指令在移位过程中保持符号位不变。SAL指令不保持符号位,但当符号位发生变化时(最高位与CF不同),用 OF标志置1表示出来。
逻辑左移SHL把操作数看成无符号数。
将一操作数左移一位,相当于将其乘2。将一操作数右移一位,相当于将其除以2。因此,可以用移位操作代替部分乘除操作,只要不产生溢出,这种代替是正确的。(用CF标志判别无符号数运算是否溢出,CF=1,表示溢出。用 OF标志判别有符号数运算是否溢出,OF=1,表示溢出)。
操作数B7H(1011 0111B)连续左移时的变化
操作数B7H(1011 0111B)连续右移时的变化
3、 循环指令
循环操作如图3-18所示。
ROL,RCL,ROR,RCR指令的格式相同,以ROL为例:
ROL BX,1 ; BX的值循环左移一位
ROL WORD PTR [DI],CL ;内存单元的值循环左移CL位 ;CL=0,1,2,....,255
§3.3.5 控制转移指令
8086程序中的指令存放在内存中的一个或几个段中,这些段称为代码段,CPU执行的下一条指令的地址由CS(代码段基地址寄存器)和IP(指令指针)指定。CPU正在执行的指令所在的代码段称为"当前代码段",其基地址为CS的值。代码段的容量可达64K,IP的值为0000H~FFFFH。
一般情况下,CPU按顺序执行指令,每执行一条指令,IP增加一个值(该值等于这条指令的长度,指指令的机器码长度),当IP到达一段的末尾时,改变CS的值并重新设定IP指向新段的开始。
若CPU正在执行的指令为控制转移指令,CPU改变执行顺序,转移到另一处执行。此时,IP 和/或 CS的值发生改变。
转移指令包括:
子程序调用指令(CALL)和子程序返回指令(RET)。
无条件转移指令(JMP)和条件转移指令(JZ,JNZ等)。
重复(循环)控制指令(LOOP,LOOPNZ等)。
中断指令(INT n)和中断返回指令(IRET)。
如果转移指令只改变IP的值,不改变CS的值,即目标指令仍在当前代码段中,称为"段内转移"。
如果转移指令改变IP和CS的值,即目标指令不在当前代码段中,而在另一代码段内,称为"段间转移"。(转移后的代码段成为新的当前代码段)。
1、 无条件控制转移
(1) JMP指令
JMP 目标地址
功能:无条件转移到目标地址。
在程序设计中,目标地址通常用一个指令标号来表示。
(2) 调用指令(CALL)和返回指令(RET)
CALL 目标地址
RET [n];n为0~FFFFH之间的一个偶数
在大型程序中,有时,一段相同的程序多次被使用,可以把这段程序单独提出来编写,称为"子程序",需要该段程序时,用CALL指令调用子程序,这种编程处理方法,称为"子程序结构",如图19所示。
相对于子程序,调用程序称为主程序如图1所示。 CALL指令用在主程序中调用子程序,它使CPU转入子程序执行。RET用在子程序中控制CPU返回主程序,如图20所示。
为了使CPU在执行完子程序后,能正确地返回CALL指令的下一条指令,CALL指令必须把"返回地址"存入堆栈。RET从堆栈中取
出该返回地址,从而返回到主程序的正确位置。
如果子程序P与主程序M在同一个代码段,称为段内调用,该子程序称为NEAR型子程序;如果子程序P与主程序M不在同一个代码段,称为段间调用,该子程序称为FAR型子程序。
段间调用与返回时,CALL/RET指令的操作(如图21所示):
CALL:
① SP减2,把返回地址的段值(CS)推入堆栈。
② SP减2,把返回地址的偏移量(IP)推入堆栈。 ①、②两步使RET正确返回。
③ 把子程序地址的偏移量送给IP,把子程序地址的段值送给CS。从而使CPU转入子程序运行。
RET:
① 从堆栈中取出返回地址的偏移量送给IP,SP加2。
② 从堆栈中取出返回地址的段值送给CS,SP加2。 从而使CPU执行CALL指令后面的那条指令。
段内调用与返回时,CALL/RET指令的操作:
CALL:(如图22)
① SP减2,把返回地址的偏移量(IP)推入堆栈。以便RET正确返回。(不保存返回地址的段值)。
② 把子程序地址的偏移量送给IP。从而使CPU转入子程序运行。
RET:从堆栈中取出返回地址的偏移量,送给IP,SP加2。
从而使CPU执行CALL指令后面的那条指令。
"RET n"(n为偶数)指令,除完成一般RET指令的动作外,还使SP加n。"RET n"用于有入口参数的子程序中,清除主程在执行CALL指令之前推入堆栈的入口参数。
2、 条件控制转移指令
条件控制转移指令,以一个或几个标志位作为条件,或以CX的值作为条件,当条件满足时,转移到目标地址,否则,执行下一条指令。
条件转移指令的一般格式是:
JX 短目标地址
其中,X是表示条件的1~3个字母。"短目标地址"是指,JX指令与目标地址之间的距离范围为-128~+127。(区别:无条件转移指令JMP可以跳转到任何位置)。
条件转移指令的中,相当一部分指令的条件,是CMP、SUB等指令比较两个数后,在标志寄存器中设置的标志位。以CMP指令为例,无符号数和有符号数比较后,设置的标志位不同,如下表所示
"CMP dst,src"指令执行后设置的标志
条件转移指令使用大于(Greater)、小于(Less)来反应有符号数比较后设置的标志位。使用高于(Above)、低于(Below)来反应无符号数比较后设置的标志位,如下表所示。
3、 重复控制指令(循环指令)
重复控制指令属于条件转移指令,当条件满足时,转移到目标地址,从而使重复控制指令与目标地址之间的程序(称为循环体)被重复执行(循环)。
(1) LOOP指令
LOOP 短目标地址
功能:使CX的值减1后,若CX≠0,转移到目标地址。
注意,LOOP指令使CX减1时,不会引起标志位的变化。
LOOP指令相当于以下两条指令:
DEC CX
JNZ 短目标地址 LOOP指令使循环体执行CX次如图3-23所示。
当CX被赋初值0时,循环体被执行65536次。
(2) LOOPZ(或LOOPE)
格式:LOOPZ 短目标地址
功能:使CX减1后,当CX≠0且ZF=1时,转移到目标地址。
LOOPZ/LOOPE指令使循环体最多执行CX次,在循环过程中,若不满足ZF=1,将提前结束循环。
(3) LOOPNZ(或LOOPNE)
格式:LOOPNZ 短目标地址
功能:使CX减1后,当CX≠0且ZF=0时,转移到目标地址。
LOOPNZ/LOOPNE指令使循环体最多执行CX次,在循环过程中,若不满足ZF=0,将提前结束循环。
§ 3.3.6 串操作指令
(一) 串的概念
在汇编语言程序设计中,"串"可以是任意一段连续的内存(1~N字节)。串中的每一个值可以是字符(字符串)或数据(数据串)。 串在内存中的地址以串的第一字节的地址表示,如,设字符串'ABCDEF'在内存中按如下存放,则称该串的地址为 0724H。
(二) 串操作的特点
在汇编语言程序设计中,可对串进行如下操作:
(S=STRING ,B=BYTE, W= WORD)
串的传送 MOVS/MOVSB/MOVSW(MOVE)
串的比较 CMPS/CMPSB/CMPSW(COMPARE)
串的检索 SCAS/SCASB/SCASW(SCAN)
存串 STOS/STOSB/STOSW(STORE)
取串 LODS/LODSB/LODSW(LOAD)
这些操作有如下特点:
(1) 可对字节串(如MOVSB)或字串操作(如MOVSW)。
(2) 源操作数(称为源串): 段地址DS,偏移量SI
目的操作数(称为目的串):段地址ES,偏移量DI
串操作指令是唯一的一组源操作数和目的操作数均在内存的指令。
(3) 串操作指令执行时,每执行一次,自动修改源串和目的串的地址偏移量SI和DI。SI和DI的修改方式与标志寄存器的方向标志
DF有关:STD指令:置DF=1 (Set DF)
CLD指令:置DF=0 (Clear DF)
(4) 串操作指令可以加重复前缀。
1、 字符串的传送指令
把源字符串中DS:SI处的元素(字节或字)复制到目的字符串中ES:DI处,且自动修改SI、DI。
MOVS 目的字串,源字串 ;每次复制一字。
MOVSW ;每次复制一字
MOVSB ;每次复制一字节。
执行字符串的传送指令,有以下五个步骤:
(1) 用CLD指令使DF=0或用STD指令使DF=1,以指顶字符串的传送指令执行后,SI、DI是增加(DF=0)或减少(DF=1)。
(2) 源字符串的地址送DS、SI。
(3) 目的字符串的地址送ES、DI。(当源字符串和目的字符串在同一数据段时,ES=DS,且一般在程序的起始处设置)。
(4) 将字节或字数送入CX。
(5) 执行字符串传送指令。
字符串传送中,DF标志位的影响。
DF标志位影响字符串指令执行后SI、DI是增加(DF=0)或减少(DF=1),如图3-24所示。
2、 字符串的比较指令
两个字符串对应位置的元素(字节或字)进行比较(DS:SI处元素与ES:DI处元素比较),比较结果反应在标志寄存器的标志位。且自动修改SI、DI。
CMPS 目的字串,源字串;DS:SI处与ES:DI处比较一字。
CMPSW ;DS:SI处与ES:DI处比较一字。
CMPSB ;DS:SI处与ES:DI处比较一字节。
CMPSxx指令使用"源串中DS:SI处元素-目的串ES:DI处元素"的算法进行比较。(区分:"CMP dst,src"指令使用"dst-src"的算法进行比较)。
3、 字符串的扫描指令
AL或AX与目的字符串中ES:DI处的元素(字节或字)进行比较,比较结果反应在标志寄存器的标志位。且自动修改DI。(该指令不使用SI,因此,该指令执行时SI不变)。即,查找(称为扫描)字符串中是否含有与AL/AX相同的元素。
SCAS 目的字串 ;AX与ES:DI处比较。
SCASW ;AX与ES:DI处比较。
SCASB ;AL与ES:DI处比较。
SCASxx指令使用"AL/AX-目的串中ES:DI处元素"的算法进行比较。
4、 字符串的装入指令
把源字符串中DS:SI处的元素(字节或字)装入AL或AX中。且自动修改SI。(该指令不使用DI,因此,该指令执行时DI不变)。LODS 源字串 ;DS:SI处的元素(字)→AX。
LODSW ;DS:SI处的元素(字)→AX。
LODSB ;DS:SI处的元素(字节)→AL。
5、 字符串的存储指令
把AL或AX中的值存入目的字符串中ES:DI处。且自动修改SI。(该指令不使用SI,因此,该指令执行时SI不变)。
STOS 源字串 ;AX →ES:DI处。
STOSW ;AX→ES:DI处。
STOSB ; AL→ES:DI处。