Intel汇编语言程序设计学习-第六章 条件处理-中
6.3 ?條件跳轉(zhuǎn)
6.3.1 ?條件結(jié)構(gòu)
? ? 在IA-32指令集中沒有高級的邏輯結(jié)構(gòu),但無論多么復(fù)雜的結(jié)構(gòu),都可以使用比較和跳轉(zhuǎn)指令組合來實(shí)現(xiàn)。執(zhí)行條件語句包括兩個步驟:首先,使用CMP,AND,SUB之類的指令修改CPU標(biāo)志六七次,使用條件跳轉(zhuǎn)指令測試并導(dǎo)致向新地址的分支轉(zhuǎn)移。
? ? 例子1:使用CMP指令比較AL和0,如果CPU指令設(shè)置了零標(biāo)志,那么JZ(為0則跳轉(zhuǎn))指令就跳轉(zhuǎn)到標(biāo)號L1處:
cmp al ,0
jz L1
.
.
L1:
?
6.3.2 ?條件跳轉(zhuǎn)(Jcond)指令
? ? 條件跳轉(zhuǎn)指令在標(biāo)志條件為真時分支跳轉(zhuǎn)到新的目的標(biāo)號處,如果條件標(biāo)志為假,那么執(zhí)行緊跟在跳轉(zhuǎn)跳轉(zhuǎn)指令之后的指令。格式如下:
? ? ? ? jcond 目標(biāo)地址
? ? 格式中的cond指的是一個標(biāo)志條件,用來表示一個或多個標(biāo)志的狀態(tài)。例如:
? ? ? jc ???如果進(jìn)位則跳轉(zhuǎn)
? ? ? jnc ??如果無進(jìn)位則跳轉(zhuǎn)
? ? ? jz ???如果為零則跳轉(zhuǎn)
? ? ? jnz ??如果不為零則跳轉(zhuǎn)
? ? 我們已經(jīng)知道算數(shù)指令。比較指令和布爾指令幾乎重視會設(shè)置標(biāo)志位、條件跳轉(zhuǎn)指令檢查標(biāo)志位的狀態(tài)并且根據(jù)標(biāo)志位的狀態(tài)決定是否跳轉(zhuǎn)。
? ? 限制:MASM在默認(rèn)情況下要求跳轉(zhuǎn)的目的地址在當(dāng)前的過程之內(nèi),為了突破這種限制,可以聲明一個全局標(biāo)號(標(biāo)號后面跟”::”):
jc MyLabel
.
.
MyLabel::
通常,應(yīng)盡量避免跳轉(zhuǎn)到當(dāng)前的過程之外,否則調(diào)試程序時會比較困難。
? ? 在Intel386之前,跳轉(zhuǎn)的目標(biāo)地址被限制在跳轉(zhuǎn)指令后的第一條指令+128~-127個字節(jié)范圍之內(nèi)。IA-32處理器可跳轉(zhuǎn)到當(dāng)前段內(nèi)的任何地址。
? ? 使用CMP指令:假設(shè)我們想在AX等于5時跳轉(zhuǎn)到位置L1處。假設(shè)AX等于5,CMP指令設(shè)置了零標(biāo)志,由于零標(biāo)志置位了,執(zhí)行JE指令就會發(fā)生跳轉(zhuǎn):
? ? cmp ax,5
? ? je ?L1 ??????;相等則跳轉(zhuǎn)
? ? 如果AX不等于5,CMP就會清楚零標(biāo)志,執(zhí)行JE指令就不會發(fā)生跳轉(zhuǎn),在下面的例子中,由于AX小于6而發(fā)生了跳轉(zhuǎn):
? ? mov ?ax ,5
? ? cmp ?ax,6
? ? jl ????L1 ???;如果小于則跳轉(zhuǎn)大于是(jg)
6.3.3 ?條件跳轉(zhuǎn)指令的類型
? ? ?IA-32指令集中跳轉(zhuǎn)中的數(shù)目驚人地多,支持根據(jù)有符號、無符號整數(shù)的比較以及對CPU狀態(tài)標(biāo)志的檢查進(jìn)行跳轉(zhuǎn)的一系列指令,跳轉(zhuǎn)跳轉(zhuǎn)指令可分成下面四類:
1.基于特定的標(biāo)志值。
2.根據(jù)兩個操作數(shù)是否相等,或根據(jù)(E)CX的值的。
3.基于無符號操作數(shù)的比較結(jié)果的。
4.基于有符號操作數(shù)的比較結(jié)果的。
下表列出了基于特定CPU標(biāo)志:零標(biāo)志、進(jìn)位標(biāo)志、溢出標(biāo)志、奇偶標(biāo)志和符號標(biāo)志的跳轉(zhuǎn)指令。
基于恒等性比較的跳轉(zhuǎn)指令
????下表列出了基于兩個操作數(shù)是否相等或CX,EXC值是否為零的跳轉(zhuǎn)指令。
CMP leftOp ,rightOp
JE指令和JZ指令是等價的,JNZ指令和JNE指令時等價的。
基于無符號數(shù)比較的跳轉(zhuǎn)指令
?
基于有符號數(shù)比較的跳轉(zhuǎn)指令
?
6.3.4 ?條件跳轉(zhuǎn)的應(yīng)用
測試狀態(tài)位
? ? AND,OR,CMP,NOT和TEST指令后面常跟能夠改變程序流程的條件跳轉(zhuǎn)指令,條件跳轉(zhuǎn)指令通常要測試CPU狀態(tài)標(biāo)志位的值。例如,假設(shè)8位的內(nèi)存操作數(shù)status中存放著同計算機(jī)相連的外部設(shè)備信息,下面的指令在位5置位時跳轉(zhuǎn)到某標(biāo)號處,表示機(jī)器處于脫機(jī)狀態(tài):
mov ?al ,status
test ?al,00100000b ?;測試位5
jnz ??EquipOffline
? ? 下面的語句在位0位1位4中的任何一位置位時跳轉(zhuǎn)到另一個標(biāo)號處:
mov ?al ,status
test ?al ,00010011b ??;測試位0,1,4
jnz ??InputDataByte
? ? 如果想在2,3,7全部置位時跳轉(zhuǎn)某標(biāo)號處,需要使用AND和CMP兩條指令:
mov ??al ,status
and ??al ,10001100b
cmp ??al ,10001100b
je ????ResetMachine
? ? 取兩個整數(shù)中的較大的值:下面的指令比較AX和BX中的無符號整數(shù)并把其中的較大者送DX寄存器:
mov ?dx ,ax ???;假設(shè)AX較大
cmp ?ax ,bx
jae ??L1 ??????;如果A>=B 就直接跳轉(zhuǎn)到L1,否則就把較大的值B放到結(jié)果dx
mov ?dx ,bx
L1:
? ? 取三個整數(shù)中的較小值:下面的指令比較V1,V2和V3三個無符號變量的值,并把其中的最小者送至AX寄存器:
.data
V1 WORD ?
V2 WORD ?
V3 WORD ?
.code
??mov ?ax ,V1 ?;假設(shè)V1是最小的
??cmp ?ax ,V2
??jbe ??L1 ????;小于等于則跳轉(zhuǎn)
??mov ?ax ,V2
L1: cmp ax ,V3
??jbe ??L2 ??
??mov ?ax ,V3
L2:
? ? 應(yīng)用:數(shù)組的順序查找
? ? 在數(shù)組中找到第一個非零值。
?
應(yīng)用:字符串加密(XOR)
TITLE Ecnryption Program ???(Encrypt.asm)
INCLUDE Irvine32.inc
KEY = 239
BUFMAX = 128
.data
sPrompt ?BYTE ?"Enter the plain text:" ,0
sEncrypt BYTE ?"Cipher text: ????????" ,0
sDecrypt BYTE ?"Decrypted: ??????????" ,0
buffer ??BYTE ?BUFMAX+1 DUP(0)
bufSize ?DWORD ?
.code
main PROC
????call ?InputTheString
call ?TranslateBuffer
mov ??edx ,OFFSET sEncrypt
call ?DisplayMessage
call ?TranslateBuffer
mov ??edx ,OFFSET sDecrypt
call ?DisplayMessage
exit
main ENDP
?
;-----------------------------------
InputTheString PROC
;
;Prompts user for a plaintext string.Saves the string
;and its length
;Receives:nothing
;Returns: nothing
;-----------------------------------
????pushad
mov ???edx ,OFFSET sPrompt
call ??WriteString
mov ???ecx ,BUFMAX
????mov ???edx ,OFFSET buffer
call ??ReadString
mov ???bufSize ,eax
call ??Crlf
popad
ret
InputTheString ENDP
?
;-----------------------------------
DisplayMessage PROC
;
;Display the ecnrypted or decrypted message.
;Receives :EDX points to the message
;Returns ?:nothing
;-----------------------------------
????pushad
call ?WriteString
mov ??edx ,OFFSET buffer
call ?WriteString
call ?Crlf
call ?Crlf
popad
ret
DisplayMessage ENDP
?
;-----------------------------------
TranslateBuffer ?PROC
;
;Translates the string by exclusive-ORing each
;byte with the encryption key buye.
;Receives :nothing
;Returns ?:nothing
????pushad
mov ecx ,bufSize
mov esi ,0
L1:
????xor ?buffer[esi] ,KEY
inc ?esi
loop L1
popad
ret
TranslateBuffer ENDP
END main
6.3.5 ?位測試指令
BT ,BTC ,BTR和BTS指令統(tǒng)稱為位測試(bit testing)指令,這些指令很重要,因?yàn)樗麄兛梢栽趩翁粼鹤又噶顑?nèi)執(zhí)行很多個步驟。為測試指令對多線程程序非常有用,對多線程程序而言,在不冒被其他線程中斷的危險的情況下對重要的標(biāo)志(稱為信號量)進(jìn)行測試、清除、設(shè)置或求反是非常重要的。
BT指令
BT(位測試,bit test)指令選擇第一個操作數(shù)位n并把它復(fù)制到進(jìn)位標(biāo)志中:
BT bitBase,n
第一個操作數(shù)成為位基(bitBase),它不會被指令所修改。BT指令允許以下類型操作數(shù):
BT ?r/m16 ,r16
BT ?r/m32 ,r32
BT ?r/m16 ,imm8
BT ?r/m32 ,imm8
在下例中,進(jìn)位標(biāo)志等于變量semaphone第七位的值:
.data
semaphone WORD 10001000b
.code
BT ?semaphone ,7 ?????;CF = 1
在Intel指令集引入BT指令之前,我們不得不把變量復(fù)制到寄存器中,然后再通過移位把第7位送到進(jìn)位標(biāo)志中:
mov ?ax ,semaphone
shr ??ax ,8 ????????;CF = 1
BTC指令
BTC(位測試并取反,bit test and complement)指令選擇第一個操作數(shù)的位n并把它復(fù)制到標(biāo)志位中,同時對位n取反。
BTR指令
BTR(位測試并復(fù)位,bit test and reset)指令選擇第一個操作數(shù)位n并把它復(fù)制到進(jìn)位標(biāo)志中,同時位n清零。
BTS指令
BTS指令(位測試并置位,bit test and set)指令選擇第一個操作數(shù)的位n并把它復(fù)制到進(jìn)位標(biāo)志中,同時位n置位。
6.4 ?條件循環(huán)指令
? ? LOOPZ和LOOPE指令:ecx大于0,并且零標(biāo)志位置位則循環(huán)。
? ? LOOPNZ和LOOPNE指令:ecx大于0,并且零標(biāo)志位復(fù)位則循環(huán)。
6.5 ?條件結(jié)構(gòu)
? ? 條件結(jié)構(gòu)可認(rèn)為是在不同的邏輯分支之間引發(fā)選擇的一個或多個條件表達(dá)式,每個分支都會執(zhí)行不同的指令序列。
6.5.1 ?IF塊結(jié)構(gòu)語句
? ? 這節(jié)不想細(xì)總結(jié)了,書上很大的篇幅就是為了解釋用cmp和j*來對應(yīng)解釋高級語言里那些IF語句什么的。沒什么新東西。
6.5.2 ?復(fù)合表達(dá)式
? ? 這節(jié)是說在高級語言中的類似if(A And B) [A&&B] if(A OR B) [A||B]等在匯編里怎么對應(yīng)翻譯,其實(shí)比較簡單,比如A&&B 可以判斷A滿足然后跳轉(zhuǎn)到B繼續(xù)判斷,有一個不滿足那么直接jmp到其他地方,A||B的話就是先判斷A,如果滿足 那么jmp到滿足,否則判斷B如果滿足那么jmp到滿足,否則jmp到不滿足,這樣也就明白了為什么在高級語言中 a = 0 ,b = 0 ?if(++a || ++b)..之后b沒有被自加的原因(a = 1 ,b = 0)。比較簡單,這一節(jié)也不細(xì)總結(jié)了。
6.5.3 ?WHILE循環(huán)
????額...這節(jié)是說高級語言中的while怎么解析成匯編,比較簡單,我們直接mark一個地方,然后滿足條件就直接往上跳回去就行了,如果不滿足那么就不跳,這樣就自動往下執(zhí)行,相當(dāng)于while完了,當(dāng)然也可以增加其他cmp,j*指令實(shí)現(xiàn)break等。
?
6.5.4 ?以表格驅(qū)動的分支選擇
? ? 原理是對于多層條件語句嵌套那種,翻譯成匯編會很亂,很麻煩,同時如果我們用匯編開發(fā)過程中出現(xiàn)了太多層的條件嵌套寫著也麻煩,有一種方法是我們把每個條件和執(zhí)行地址看成一個”結(jié)構(gòu)體”,然后在創(chuàng)建一個”結(jié)構(gòu)體數(shù)組”,例如
?
? ? 條件A執(zhí)行00000120處的函數(shù),或者跳轉(zhuǎn)到那里,條件B則是00000130...這樣我們每次只要線性掃描這個表就行了,這個姿勢叫做以表格驅(qū)動的分支選擇。
例子程序:用戶從鍵盤輸入一個字符,程序使用一個循環(huán)將該字符同表中每個項(xiàng)比較,對于找到的第一個匹配項(xiàng),緊跟在待查找值其后存儲的過程將被調(diào)用。每個過程使用EDX來裝入不同的字符串偏移,然后在循環(huán)中顯示該字符串:
TITLE Table of Procedure Offsets (ProcTable.asm)
;This program contains a table with offsets of procedures.
;It uses the table to execute indirect procedure calls.
INCLUDE Irvine32.inc
.data
CaseTable BYTE ??'A'
??????????DWORD ?Process_A
EntrySize = ($ - CaseTable)
??BYTE ??'B'
??????????DWORD ?Process_B
??BYTE ??'C'
??????????DWORD ?Process_C
??BYTE ??'D'
??????????DWORD ?Process_D
NumberOfEntries = ($ - CaseTable) / EntrySize
prompt ???BYTE ??"Press capital A,B,Cor D:" ,0
msgA ?????BYTE ??"Process_A" ,0
msgB ?????BYTE ??"Process_B" ,0
msgC ?????BYTE ??"Process_C" ,0
msgD ?????BYTE ??"Process_D" ,0
.code
main PROC
????mov ??edx ,OFFSET prompt
call ?WriteString
call ?ReadChar
mov ??ebx ,OFFSET CaseTable
mov ??ecx ,NumberOfEntries
L1:
????cmp ??al ,[ebx]
jne ??L2
call ?NEAR PTR [ebx + 1]
call ?WriteString
call ?Crlf
jmp ??L3
L2:
????add ??ebx ,EntrySize
loop ?L1
L3:
?????exit
main ENDP
?
Process_A PROC
????mov ?edx ,OFFSET msgA
ret
Process_A ENDP
Process_B PROC
????mov ?edx ,OFFSET msgB
ret
Process_B ENDP
Process_C PROC
????mov ?edx ,OFFSET msgC
ret
Process_C ENDP
Process_D PROC
????mov ?edx ,OFFSET msgD
ret
Process_D ENDP
END main
?
?
同時上面有幾個個地方需要注意一下:
1.一個是函數(shù)名字直接可以當(dāng)變量用了:
?
2.A=B不占用.data定義東西的時候的地址空間(不然的話,上面那么寫代碼就算錯了)
?
3.CALL指令調(diào)用存儲在EBX+1內(nèi)存地質(zhì)處的過程地址,這種間接調(diào)用格式要使用NEAR PTR運(yùn)算符。
?
?
總結(jié)
以上是生活随笔為你收集整理的Intel汇编语言程序设计学习-第六章 条件处理-中的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Intel汇编语言程序设计学习-第六章
- 下一篇: Intel汇编语言程序设计学习-第六章