Intel汇编语言程序设计学习-第六章 条件处理-中
6.3 ?條件跳轉
6.3.1 ?條件結構
? ? 在IA-32指令集中沒有高級的邏輯結構,但無論多么復雜的結構,都可以使用比較和跳轉指令組合來實現。執行條件語句包括兩個步驟:首先,使用CMP,AND,SUB之類的指令修改CPU標志六七次,使用條件跳轉指令測試并導致向新地址的分支轉移。
? ? 例子1:使用CMP指令比較AL和0,如果CPU指令設置了零標志,那么JZ(為0則跳轉)指令就跳轉到標號L1處:
cmp al ,0
jz L1
.
.
L1:
?
6.3.2 ?條件跳轉(Jcond)指令
? ? 條件跳轉指令在標志條件為真時分支跳轉到新的目的標號處,如果條件標志為假,那么執行緊跟在跳轉跳轉指令之后的指令。格式如下:
? ? ? ? jcond 目標地址
? ? 格式中的cond指的是一個標志條件,用來表示一個或多個標志的狀態。例如:
? ? ? jc ???如果進位則跳轉
? ? ? jnc ??如果無進位則跳轉
? ? ? jz ???如果為零則跳轉
? ? ? jnz ??如果不為零則跳轉
? ? 我們已經知道算數指令。比較指令和布爾指令幾乎重視會設置標志位、條件跳轉指令檢查標志位的狀態并且根據標志位的狀態決定是否跳轉。
? ? 限制:MASM在默認情況下要求跳轉的目的地址在當前的過程之內,為了突破這種限制,可以聲明一個全局標號(標號后面跟”::”):
jc MyLabel
.
.
MyLabel::
通常,應盡量避免跳轉到當前的過程之外,否則調試程序時會比較困難。
? ? 在Intel386之前,跳轉的目標地址被限制在跳轉指令后的第一條指令+128~-127個字節范圍之內。IA-32處理器可跳轉到當前段內的任何地址。
? ? 使用CMP指令:假設我們想在AX等于5時跳轉到位置L1處。假設AX等于5,CMP指令設置了零標志,由于零標志置位了,執行JE指令就會發生跳轉:
? ? cmp ax,5
? ? je ?L1 ??????;相等則跳轉
? ? 如果AX不等于5,CMP就會清楚零標志,執行JE指令就不會發生跳轉,在下面的例子中,由于AX小于6而發生了跳轉:
? ? mov ?ax ,5
? ? cmp ?ax,6
? ? jl ????L1 ???;如果小于則跳轉大于是(jg)
6.3.3 ?條件跳轉指令的類型
? ? ?IA-32指令集中跳轉中的數目驚人地多,支持根據有符號、無符號整數的比較以及對CPU狀態標志的檢查進行跳轉的一系列指令,跳轉跳轉指令可分成下面四類:
1.基于特定的標志值。
2.根據兩個操作數是否相等,或根據(E)CX的值的。
3.基于無符號操作數的比較結果的。
4.基于有符號操作數的比較結果的。
下表列出了基于特定CPU標志:零標志、進位標志、溢出標志、奇偶標志和符號標志的跳轉指令。
基于恒等性比較的跳轉指令
????下表列出了基于兩個操作數是否相等或CX,EXC值是否為零的跳轉指令。
CMP leftOp ,rightOp
JE指令和JZ指令是等價的,JNZ指令和JNE指令時等價的。
基于無符號數比較的跳轉指令
?
基于有符號數比較的跳轉指令
?
6.3.4 ?條件跳轉的應用
測試狀態位
? ? AND,OR,CMP,NOT和TEST指令后面常跟能夠改變程序流程的條件跳轉指令,條件跳轉指令通常要測試CPU狀態標志位的值。例如,假設8位的內存操作數status中存放著同計算機相連的外部設備信息,下面的指令在位5置位時跳轉到某標號處,表示機器處于脫機狀態:
mov ?al ,status
test ?al,00100000b ?;測試位5
jnz ??EquipOffline
? ? 下面的語句在位0位1位4中的任何一位置位時跳轉到另一個標號處:
mov ?al ,status
test ?al ,00010011b ??;測試位0,1,4
jnz ??InputDataByte
? ? 如果想在2,3,7全部置位時跳轉某標號處,需要使用AND和CMP兩條指令:
mov ??al ,status
and ??al ,10001100b
cmp ??al ,10001100b
je ????ResetMachine
? ? 取兩個整數中的較大的值:下面的指令比較AX和BX中的無符號整數并把其中的較大者送DX寄存器:
mov ?dx ,ax ???;假設AX較大
cmp ?ax ,bx
jae ??L1 ??????;如果A>=B 就直接跳轉到L1,否則就把較大的值B放到結果dx
mov ?dx ,bx
L1:
? ? 取三個整數中的較小值:下面的指令比較V1,V2和V3三個無符號變量的值,并把其中的最小者送至AX寄存器:
.data
V1 WORD ?
V2 WORD ?
V3 WORD ?
.code
??mov ?ax ,V1 ?;假設V1是最小的
??cmp ?ax ,V2
??jbe ??L1 ????;小于等于則跳轉
??mov ?ax ,V2
L1: cmp ax ,V3
??jbe ??L2 ??
??mov ?ax ,V3
L2:
? ? 應用:數組的順序查找
? ? 在數組中找到第一個非零值。
?
應用:字符串加密(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指令統稱為位測試(bit testing)指令,這些指令很重要,因為他們可以在單挑院子指令內執行很多個步驟。為測試指令對多線程程序非常有用,對多線程程序而言,在不冒被其他線程中斷的危險的情況下對重要的標志(稱為信號量)進行測試、清除、設置或求反是非常重要的。
BT指令
BT(位測試,bit test)指令選擇第一個操作數位n并把它復制到進位標志中:
BT bitBase,n
第一個操作數成為位基(bitBase),它不會被指令所修改。BT指令允許以下類型操作數:
BT ?r/m16 ,r16
BT ?r/m32 ,r32
BT ?r/m16 ,imm8
BT ?r/m32 ,imm8
在下例中,進位標志等于變量semaphone第七位的值:
.data
semaphone WORD 10001000b
.code
BT ?semaphone ,7 ?????;CF = 1
在Intel指令集引入BT指令之前,我們不得不把變量復制到寄存器中,然后再通過移位把第7位送到進位標志中:
mov ?ax ,semaphone
shr ??ax ,8 ????????;CF = 1
BTC指令
BTC(位測試并取反,bit test and complement)指令選擇第一個操作數的位n并把它復制到標志位中,同時對位n取反。
BTR指令
BTR(位測試并復位,bit test and reset)指令選擇第一個操作數位n并把它復制到進位標志中,同時位n清零。
BTS指令
BTS指令(位測試并置位,bit test and set)指令選擇第一個操作數的位n并把它復制到進位標志中,同時位n置位。
6.4 ?條件循環指令
? ? LOOPZ和LOOPE指令:ecx大于0,并且零標志位置位則循環。
? ? LOOPNZ和LOOPNE指令:ecx大于0,并且零標志位復位則循環。
6.5 ?條件結構
? ? 條件結構可認為是在不同的邏輯分支之間引發選擇的一個或多個條件表達式,每個分支都會執行不同的指令序列。
6.5.1 ?IF塊結構語句
? ? 這節不想細總結了,書上很大的篇幅就是為了解釋用cmp和j*來對應解釋高級語言里那些IF語句什么的。沒什么新東西。
6.5.2 ?復合表達式
? ? 這節是說在高級語言中的類似if(A And B) [A&&B] if(A OR B) [A||B]等在匯編里怎么對應翻譯,其實比較簡單,比如A&&B 可以判斷A滿足然后跳轉到B繼續判斷,有一個不滿足那么直接jmp到其他地方,A||B的話就是先判斷A,如果滿足 那么jmp到滿足,否則判斷B如果滿足那么jmp到滿足,否則jmp到不滿足,這樣也就明白了為什么在高級語言中 a = 0 ,b = 0 ?if(++a || ++b)..之后b沒有被自加的原因(a = 1 ,b = 0)。比較簡單,這一節也不細總結了。
6.5.3 ?WHILE循環
????額...這節是說高級語言中的while怎么解析成匯編,比較簡單,我們直接mark一個地方,然后滿足條件就直接往上跳回去就行了,如果不滿足那么就不跳,這樣就自動往下執行,相當于while完了,當然也可以增加其他cmp,j*指令實現break等。
?
6.5.4 ?以表格驅動的分支選擇
? ? 原理是對于多層條件語句嵌套那種,翻譯成匯編會很亂,很麻煩,同時如果我們用匯編開發過程中出現了太多層的條件嵌套寫著也麻煩,有一種方法是我們把每個條件和執行地址看成一個”結構體”,然后在創建一個”結構體數組”,例如
?
? ? 條件A執行00000120處的函數,或者跳轉到那里,條件B則是00000130...這樣我們每次只要線性掃描這個表就行了,這個姿勢叫做以表格驅動的分支選擇。
例子程序:用戶從鍵盤輸入一個字符,程序使用一個循環將該字符同表中每個項比較,對于找到的第一個匹配項,緊跟在待查找值其后存儲的過程將被調用。每個過程使用EDX來裝入不同的字符串偏移,然后在循環中顯示該字符串:
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.一個是函數名字直接可以當變量用了:
?
2.A=B不占用.data定義東西的時候的地址空間(不然的話,上面那么寫代碼就算錯了)
?
3.CALL指令調用存儲在EBX+1內存地質處的過程地址,這種間接調用格式要使用NEAR PTR運算符。
?
?
總結
以上是生活随笔為你收集整理的Intel汇编语言程序设计学习-第六章 条件处理-中的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Intel汇编语言程序设计学习-第六章
- 下一篇: Intel汇编语言程序设计学习-第六章