📄 汇005.txt
字号:
相等或为零循环指令的一般格式:
LOOPE/LOOPZ 标号
LOOPEW/LOOPZW 标号 ;CX作为循环计数器,80386+
LOOPED/LOOPZD 标号 ;ECX作为循环计数器,80386+
这是一组有条件循环指令,它们除了要受CX或ECX的影响外,还要受标志位ZF的影响。其具体规定如下:
(1)、(CX)=(CX)-1或(ECX)=(ECX)-1; (不改变任何标志位)
(2)、如果循环计数器≠0且ZF=1,则程序转到循环体的第一条指令,否则,程序将执行该循环指令下面的指令。
图5.13 循环指令LOOPE的功能示意图
3、不等或不为零循环指令(Loop While Not Equal or Loop While Not Zero)
不等或不为零循环指令的一般格式:
LOOPNE/LOOPNZ 标号
LOOPNEW/LOOPNZW 标号 ;CX作为循环计数器,80386+
LOOPNED/LOOPNZD 标号 ;ECX作为循环计数器,80386+
这也是一组有条件循环指令,它们与相等或为零循环指令在循环结束条件上有点不同。其具体规定如下:
(1)、(CX)=(CX)-1或(ECX)=(ECX)-1; (不改变任何标志位)
(2)、如果循环计数器≠0且ZF=0,则程序转到循环体的第一条指令,否则,程序将执行该循环指令下面的指令。
图5.14 循环指令LOOPNE的功能示意图
4、循环计数器为零转指令(Jump if CX/ECX is Zero)
在前面的各类循环指令中,不管循环计数器的初值为何,循环体至少会被执行一次。当循环计数器的初值为0时,通常的理解应是循环体被循环0次,即循环体一次也不被执行。其实不然,循环体不是不被执行,而是会被执行65536次(用CX计数)或4294967296次(几乎是死循环,用ECX计数)。
为了解决指令的执行和常规思维之间差异,指令系统又提供了一条与循环计数器有关的指令——循环计数器为零转指令。该指令一般用于循环的开始处,其指令格式如下:
JCXZ 标号 ;当CX=0时,则程序转移标号处执行
JECXZ 标号 ;当ECX=0时,则程序转移标号处执行,80386+
例5.14 编写一段程序,求1+2+…+k(K≥0)之和,并把结果存入AX中。
解:
…
K DB ? ;变量定义
…
XOR AX, AX
MOV CX, K
JCXZ next
again: ADD AX, CX ;计算过程: K+(K-1)+…+2+1
LOOP again
next: …
思考题:假设变量K的值为0,并且在循环体的前面没有写指令“JCXZ next”,这时求出的“和”AX的值是什么?
5.2.9 转移指令
转移指令是汇编语言程序员经常使用的一组指令。在高级语言中,时常有“尽量不要使用转移语句”的劝告,但如果在汇编语言的程序中也尽量不用转移语句,那么该程序要么无法编写,要么没有多少功能,所以,在汇编语言中,不但要使用转移指令,而且还要灵活运用,因为指令系统中有大量的转移指令。
转移指令分无条件转移指令和有条件转移指令两大类。
1、无条件转移指令(Transfer Unconditionally)
无条件转移指令包括:JMP、子程序的调用和返回指令、中断的调用和返回指令等。
下面只介绍无条件转移指令JMP(Unconditional Jump)。
JMP指令的一般形式:
JMP 标号/Reg/Mem
JMP指令是从程序当前执行的地方无条件转移到另一个地方执行。这种转移可以是一个短(short)转移(偏移量在[-128, 127]范围内),近(near)转移(偏移量在[-32K, 32K]范围内)或远(far)转移(在不同的代码段之间转移)。
短和近转移是段内转移,JMP指令只把目标指令位置的偏移量赋值指令指针寄存器IP,从而实现转移功能。但远转移是段间转移,JMP指令不仅会改变指令指针寄存器IP的值,而且还会改变代码段寄存器CS的值。
该转移指令的执行不影响任何标志位。
例如:
…
next1: …
JMP next1 ;向前转移,偏移量之差为负数
…
JMP next2 ;向后转移,偏移量之差为正数
…
next2: …
在目前流行的汇编系统中,当段内转移时,有些软件把该转移指令默认为近转移,从而使指令的偏移量用一个字来表示,于是生成3个字节的指令代码,但如果程序员自己清楚转移的幅度在一个短转移的范围之内,那么,可用前置short的办法来告诉汇编程序,让它产生2个字节的指令代码。
比如:如果程序员知道在上例中的标号next2离“JMP next2”指令的偏移量不会超过127,那么,可用下面的转移方式来省掉一个字节的指令代码。
next2: …
JMP short next2 ;生成2个字节的转移指令,从而节省一个字节
…
2、条件转移指令(Transfer Conditionally)
条件转移指令是一组极其重要的转移指令,它根据标志寄存器中的一个(或多个)标志位来决定是否需要转移,这就为实现多功能程序提供了必要的手段。微机的指令系统提供了丰富的条件转移指令来满足各种不同的转移需要,在编程序时,要对它们灵活运用。
条件转移指令又分三大类:基于无符号数的条件转移指令、基于有符号数的条件转移指令和基于特殊算术标志位的条件转移指令。
、无符号数的条件转移指令(Jumps Based on Unsigned (Logic) Data)
指令的助忆符
检测的转移条件 功能描述
JE/JZ
ZF=1 Jump Equal or Jump Zero
JNE/JNZ
ZF=0 Jump Not Equal or Jump Not Zero
JA/JNBE
CF=0 and ZF=0 Jump Above or Jump Not Below or Equal
JAE/JNB
CF=0 Jump Above or Equal or Jump Not Below
JB/JNAE
CF=1 Jump Below or Jump Not Above or Equal
JBE/JNA
CF=1 or AF=1 Jump Below or Equal or Jump Not Above
、有符号数的条件转移指令(Jumps Based on Signed (Arithmetic) Data)
指令的助忆符
检测的转移条件 功能描述
JE/JZ
ZF=1 Jump Equal or Jump Zero
JNE/JNZ
ZF=0 Jump Not Equal or Jump Not Zero
JG/JNLE
ZF=0 and SF=OF Jump Greater or Jump Not Less or Equal
JGE/JNL
SF=OF Jump Greater or Equal or Jump Not Less
JL/JNGE
SF≠OF Jump Less or Jump Not Greater or Equal
JLE/JNG
ZF=1 or SF≠OF Jump Less or Equal or Jump Not Greater
、特殊算术标志位的条件转移指令(Jumps Based on Special Arithmetic Tests)
指令的助忆符
检测的转移条件 功能描述
JC
CF=1 Jump Carry
JNC
CF=0 Jump Not Carry
JO
OF=1 Jump Overflow
JNO
OF=0 Jump Not Overflow
JP/JPE
PF=1 Jump Parity or Jump Parity Even
JNP/JPO
PF=0 Jump Not Parity or Jump Parity Odd
JS
SF=1 Jump Sign (negative)
JNS
SF=0 Jump No Sign (positive)
例5.15 编写一程序段,它把寄存器AX-BX的绝对值存入BX中。
解:
next: …
SUB BX, AX
JNS next
NEG BX
…
例5.16 已知一个字节变量char,试编写一程序段,把其所存的大写字母变成小写字母。
解:
next: …
char DB 'F' ;变量说明
…
MOV AL, char
CMP AL, 'A'
JB next ;注意:字符是无符号数,不要使用指令JL
CMP AL, 'Z'
JA next
ADD char, 20H ;小写字母比大写字母的ASCII码大20H
…
如果不知道(或忘了)大小写字母ASCII码之间的关系,那么,可用数值表达式'a'-'A'、'b'-'B'、…、'z'-'Z'等来代替具体的数值20H。
例5.17 编写一段程序,完成下面计算公式,其中:变量X和Y都是字类型。
解:
…
X DW ? ;变量说明
Y DW ?
…
MOV AX, X
MOV BX, AX ;用BX来临时存放计算结果
CMP AX, 0
JLE setdata
CMP AX, 500
JG case3
ADD BX, 100D ;BX=X+100
JMP setdata
next: SUB BX, 50D ;BX=X-50
setdata: MOV Y, BX ;把计算结果赋给变量Y
…
例5.18 下面循环体的指令代码字节数超过128,试改写该循环。
…
MOV CX, COUNT ;给循环计数器赋初值(>0)
again: 循环体指令序列 ;循环体的首地址偏移量大于128
LOOP again
解:
…
MOV CX, COUNT
again: 循环体指令序列
DEC CX
JNZ again ;把LOOP指令改为条件转移指令
5.2.10 条件设置字节指令
条件设置字节指令(Set Byte Conditionally)是80386及其以后CPU所具有的一组指令。它们在测试条件方面与条件转移是一致的,但在功能方面,它们不是转移,而是根据测试条件的值来设置其字节操作数的内容为1或0。
条件设置字节指令的一般格式如下:
SETnn Reg/Mem ;80386+
其中:nn是表示测试条件的(见表5.4),操作数只能是8位寄存器或一个字节单元。
这组指令的执行不影响任何标志位。
表5.4 条件设置字节指令列表
指令的助忆符
操作数和检测条件之间的关系
SETZ/SETE
Reg/Mem = ZF
SETNZSETNE
Reg/Mem = not ZF
SETS
Reg/Mem = SF
SETNS
Reg/Mem = not SF
SETO
Reg/Mem = OF
SETNO
Reg/Mem = not OF
SETP/SETPE
Reg/Mem = PF
SETNP/SETPO
Reg/Mem = not PF
SETC/SETB/SETNAE
Reg/Mem = CF
SETNC/SETB/SETAE
Reg/Mem = not CF
SETNA/SETBE
Reg/Mem = (CF or ZF)
SETA/SETNBE
Reg/Mem = not (CF or ZF)
SETL/SETNGE
Reg/Mem = (SF xor OF)
SETNL/SETGE
Reg/Mem = not (SF xor OF)
SETLE/SETNG
Reg/Mem = (SF xor OF) or ZF
SETNLE/SETG
Reg/Mem = not ((SF xor OF) or ZF)
例5.19 编写程序段:检测寄存器EAX的8个16进制中有几个0H,并把统计结果存入BH中。
解:
方法1:用条件转移指令来实现
XOR BH, BH
MOV CX, 8 ;测试寄存器EAX——8次
again: TEST AL, 0FH ;测试低四位二进制是否为0H
JNZ next
INC BH
next: ROR EAX, 4 ;循环向右移四位,为测试高四位作准备
LOOP again
方法2:用条件设置字节指令来实现
XOR BH, BH
MOV CX, 8 ;测试寄存器EAX——8次
again: TEST AL, 0FH ;测试低四位二进制是否为0H
SETZ BL ;如果AL的低四位是0,则BL置为1,否则,BL为0
ADD BH, BL
ROR EAX, 4
LOOP again
5.2.11 字符串操作指令
字符串操作指令的实质是对一片连续存储单元进行处理,这片存储单元是由隐含指针DS:SI或ES:DI来指定的。字符串操作指令可对内存单元按字节、字或双字进行处理,并能根据操作对象的字节数使变址寄存器SI(和DI)增减1、2或4。具体规定如下:
(1)、当DF=0时,变址寄存器SI(和DI)增加1、2或4;
(2)、当DF=1时,变址寄存器SI(和DI)减少1、2或4。
在后面各指令中,有关变址寄存器都按上述规定进行增减,不再一一说明。
1、取字符串数据指令(Load String Instruction)
从由指针DS:SI所指向的内存单元开始,取一个字节、字或双字进入AL、AX或EAX中,并根据标志位DF对寄存器SI作相应增减。该指令的执行不影响任何标志位。
指令的格式:LODS 地址表达式
LODSB/LODSW
LODSD ;80386+
在指令LODS中,它会根据其地址表达式的属性来决定读取一个字节、字或双字。即:当该地址表达式的属性为字节、字或双字时,将从指针DS:SI处读一个字节到AL中,或读一个字到AX,或读一个双字到EAX中,与此同时,SI还将分别增减1,2或4。
图5.15 取字符串数据指令的功能示意图
其它字符串指令中的“地址表达式”作用与此类似,将不再说明。
2、置字符串数据指令(Store String Instruction)
该指令是把寄存器AL、AX或EAX中的值存于以指针ES:DI所指向内存单元为起始的一片存储单元里,并根据标志位DF对寄存器DI作相应增减。该指令不影响任何标志位。
指令的格式:STOS 地址表达式
STOSB/STOSW
STOSD ;80386+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -