?? 匯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 + -