1. 條件分支
允許決策的編程語言允許您使用稱為條件分支的技術(shù)來改變控制流镶柱。在高級語言中姑曙,每個if狀態(tài),switch狀態(tài)纬向,分支循環(huán)都已經(jīng)有分支邏輯择浊,在匯編語言中,提供所有的你認為需要做的邏輯跳轉(zhuǎn)逾条。
2. Boolean 和Comparison 指令
1). CPU 狀態(tài)標識
Boolean 指令影響ZF琢岩,CF,SF师脂,OF担孔,PF標志位。
- ZF:操作的結(jié)果為0時設(shè)置
- CF:操作使目的操作數(shù)高位產(chǎn)生進位時設(shè)置吃警。
- SF:如果復(fù)制目的操作數(shù)的高位時糕篇,設(shè)置為負;否則清除設(shè)置為正酌心。
- OF:指令生成目的操作數(shù)在范圍之外的結(jié)果時設(shè)置拌消。
- PF:指令生成目的操作的1的個數(shù)為奇數(shù)時設(shè)置。
2). AND 指令
- 格式
AND destination, source
AND reg,reg
AND reg,mem
AND reg,imm
AND mem,reg
AND mem,imm
操作可以是8位安券,16位墩崩,32位或64位氓英,但他們必須是相同的大小。
示例:
mov al,10101110b
and al,11110110b ; result in AL = 10100110
標志位:AND 指令總是清除OF鹦筹、CF铝阐。 目的操作數(shù)分配數(shù)值修改SF,ZF铐拐,PF徘键。
- 轉(zhuǎn)換字符為大寫
AND 指令提供一個簡單的方式將小寫轉(zhuǎn)換為大寫,通過比較ASCII碼的方式進行轉(zhuǎn)換余舶,因為他們只有第5位是不同的啊鸭。
0 1 1 0 0 0 0 1 = 61h ('a')
0 1 0 0 0 0 0 1 = 41h ('A')
3). OR 指令
- 格式
OR destination,source
OR reg,reg
OR reg,mem
OR reg,imm
OR mem,reg
OR mem,imm
操作可以是8位,16位匿值,32位或64位赠制,但他們必須是相同的大小。
示例:
mov al,11100011b
or al,00000100b ; result in AL = 11100111
標記:AND 指令總是清除OF挟憔、CF钟些。 目的操作數(shù)分配數(shù)值修改SF,ZF绊谭,PF政恍。
4). XOR 指令
- 格式
XOR destination,source
標志位:AND 指令總是清除OF、CF达传。 目的操作數(shù)分配數(shù)值修改SF篙耗,ZF,PF宪赶。
5). NOR 指令
- 格式
NOT reg
NOT mem
示例:
mov al,11110000b
not al ; AL = 00001111b
標志位:沒有標志位被設(shè)置宗弯。
6). TEST 指令
- 作用
TEST指令在兩個操作數(shù)中的每對匹配位之間執(zhí)行隱含的AND操作,并根據(jù)分配給目標操作數(shù)的值設(shè)置SF搂妻,ZF和PF標志蒙保。 與AND指令的區(qū)別僅在TEST指令不修改目標操作數(shù)。
test al,00001001b; test bits 0 and 3
標志位:AND 指令總是清除OF欲主、CF邓厕。 目的操作數(shù)分配數(shù)值修改SF,ZF扁瓢,PF详恼。
7). CMP 指令
作用
比較兩個整數(shù)的大小格式
CMP destination,source
標志位:CMP指令根據(jù)目標操作數(shù)在發(fā)生實際減法時所具有的值來更改溢出,符號引几,零单雾,進位,輔助進位和奇偶校驗標志。
示例:
mov ax,5
cmp ax,10 ; ZF = 0 and CF = 1
mov ax,1000
mov cx,1000
cmp cx,ax ; ZF = 1 and CF = 0
mov si,105
cmp si,0 ; ZF = 0 and CF = 0
8). 設(shè)置和清除標志位
- 設(shè)置零標記位
test al,0 ; set Zero flag
and al,0 ; set Zero flag
or al,1 ; clear Zero flag
- 設(shè)置符號標記位
or al,80h ; set Sign flag
and al,7Fh ; clear Sign flag
- 設(shè)置進位標志位
stc ; set Carry flag
clc ; clear Carry flag
- 設(shè)置溢出標記位
mov al,7Fh ; AL = +127
inc al ; AL = 80h (-128), OF=1
or eax,0 ; clear Overflow flag
3. 分支跳轉(zhuǎn)
1). 分支結(jié)構(gòu)
- 示例1
cmp eax,0
jz L1 ; jump if ZF = 1
.
.
L1:
- 示例2
and dl,10110000b
jnz L2 ; jump if ZF = 0
.
.
L2:
2). Jcond 指令
作用
當狀態(tài)標志條件為真時硅堆,條件跳轉(zhuǎn)指令分支到目標標簽屿储。格式
Jcond destination
其中cond指的是標識一個或多個標志的狀態(tài)的標志條件。例如基與CF與ZF標志位跳轉(zhuǎn)如下:
- 使用CMP 指令
cmp eax,5
je L1 ; 當EAX值等于5的時候跳轉(zhuǎn)到L1
mov ax,5
cmp ax,6
jl L1 ; 當AX值小于6的時候跳轉(zhuǎn)到L1
mov ax,5
cmp ax,4
jg L1 ; 當AX值大于4的時候跳轉(zhuǎn)到L1
3). 條件跳轉(zhuǎn)指令類型
-
跳轉(zhuǎn)指令集的四種分組
- 基于特殊寄存器
- (E)CX 操作數(shù)之間是否相等
- 無符號操作數(shù)比較
- 有符號操作數(shù)比較
下表位基于ZF渐逃,CF够掠,OF,PF茄菊,SF標志位的跳轉(zhuǎn)指令
- 等于比較
在一些情況下兩個操作數(shù)進行比較疯潭;另一些情況下,基于CX/ECX/RCX比較面殖。
CMP leftOp,rightOp
下面是基于等號的跳轉(zhuǎn)指令
- 示例: JE, JNE, JCXZ, and JECXZ
Example 1:
mov edx,0A523h
cmp edx,0A523h
jne L5 ; jump not taken
je L1 ; jump is taken
Example 2:
mov bx,1234h
sub bx,1234h
jne L5 ; jump not taken
je L1 ; jump is taken
Example 3:
mov cx,0FFFFh
inc cx
jcxz L2 ; jump is taken
Example 4:
xor ecx,ecx
jecxz L2 ; jump is taken
- 無符號比較
- 有符號比較
示例:
Example 1
mov edx,-1
cmp edx,0
jnl L5 ; jump not taken (-1 >= 0 is false)
jnle L5 ; jump not taken (-1 > 0 is false)
jl L1 ; jump is taken (-1 < 0 is true)
Example 2
mov bx,+32
cmp bx,-35
jng L5 ; jump not taken (+32 <= -35 is false)
jnge L5 ; jump not taken (+32 < -35 is false)
jge L1 ; jump is taken (+32 >= -35 is true)
Example 3
mov ecx,0
cmp ecx,0
jg L5 ; jump not taken (0 > 0 is false)
jnl L1 ; jump is taken (0 >= 0 is true)
Example 4
mov ecx,0
cmp ecx,0
jl L5 ; jump not taken (0 < 0 is false)
jng L1 ; jump is taken (0 <= 0 is true)
4). 條件跳轉(zhuǎn)應(yīng)用
- 測試狀態(tài)位
mov al,status
test al,00100000b ; test bit 5
jnz DeviceOffline
- 兩個數(shù)比較大小
mov edx,eax ; assume EAX is larger
cmp eax,ebx ; if EAX is >= EBX
jae L1 ; jump to L1
mov edx,ebx ; else move EBX to EDX
L1: ; EDX contains the larger integer
- 三個數(shù)中求最小
.data
V1 WORD ?
V2 WORD ?
V3 WORD ?
.code
mov ax,V1 ; assume V1 is smallest
cmp ax,V2 ; if AX <= V2
jbe L1 ; jump to L1
mov ax,V2 ; else move V2 to AX
L1:
cmp ax,V3 ; if AX <= V3
jbe L2 ; jump to L2
mov ax,V3 ; else move V3 to AX
L2:
- 循環(huán)直到有鍵按下
.data
char BYTE ?
.code
L1:
mov eax,10 ; create 10 ms delay
call Delay
call ReadKey ; check for key
jz L1 ; repeat if no key
mov char,AL ; save the character
5). 應(yīng)用: 順序搜索數(shù)組
; 掃描數(shù)組
; 掃描數(shù)組中的非0值
INCLUDE Irvine32.inc
.data
intArray SWORD 0, 0, 0, 0, 1, 20, 35, -12, 66, 4, 0 ; 無符號整型數(shù)組
noneMsg BYTE "A non-zero value was not found", 0 ; 提示信息
.code
main PROC
mov ebx, OFFSET intArray ; 數(shù)組指針
mov ecx, LENGTHOF intArray ; 循環(huán)計數(shù)
L1:
cmp WORD PTR [ebx], 0 ; 與0比較
jnz found ; 發(fā)現(xiàn)不等于0的值
add ebx, 2 ; 指向下一個數(shù)組元素
LOOP L1 ; 繼續(xù)循環(huán)
jmp notFound ; 未發(fā)現(xiàn)
found: ; 顯示值
movsx eax, WORD PTR [ebx] ; 將有符號的值設(shè)置到EAX
call WriteInt ; 輸出
jmp quit ; 退出程序
notFound: ; 顯示未發(fā)現(xiàn)信息
mov edx, OFFSET noneMsg
call WriteString
quit:
call Crlf
exit
main ENDP
END
6). 應(yīng)用:簡單的字符串加密
原理:( (X ? Y) ? Y) = X
代碼:
; 加密文本
INCLUDE Irvine32.inc
KEY = 239 ; 在1——255之間的任意數(shù)字
BUFMAX = 128 ; 最大緩沖字節(jié)
.data
sPrompt BYTE "Enter the plain text: ", 0 ; 輸入文本提示信息
sEncrypt BYTE "Cipher text: ", 0 ; 加密文本提示信息
sDecrypt BYTE "Decryted: ", 0 ; 解密文本提示信息
buffer BYTE BUFMAX + 1 DUP(0) ; 緩沖字節(jié)個數(shù)
bufSize DWORD ? ; 緩沖字節(jié)
.code
main PROC
call InputTheString ; 輸入待加密文本
call TranslateBuffer ; 加密文本
mov edx, OFFSET sEncrypt ; 顯示加密信息
call DisplayMessage ; 調(diào)用顯示文本程序
call TranslateBuffer ; 解密緩沖文本
mov edx, OFFSET sDecrypt ; 顯示解密信息
call DisplayMessage ; 調(diào)用顯示文本程序
call WaitMsg ; 顯示等待輸入任意鍵信息
exit
main ENDP
;-------------------------------------------------------
; 提示用戶輸入一個待加密文本竖哩,保存字符串及長度
; Receives: 無
; Returns: 無
;-------------------------------------------------------
InputTheString PROC
pushad ; 保存32位寄存器
mov edx, OFFSET sPrompt ; 顯示提示信息
call WriteString
mov ecx, BUFMAX ; 設(shè)置最大字符個數(shù)
mov edx, OFFSET buffer ; 設(shè)置緩沖指針
call ReadString ; 讀取字符串
mov bufSize, eax ; 存儲長度
call Crlf
popad
RET
InputTheString ENDP
;-------------------------------------------------------
; 顯示信息
; Receives: EDX 指針消息
; Returns: 無
;-------------------------------------------------------
DisplayMessage PROC
pushad
call WriteString
mov edx, OFFSET buffer ; 顯示緩沖中的信息
call WriteString
call Crlf
call Crlf
popad
RET
DisplayMessage ENDP
;-------------------------------------------------------
; 加解密文本
; Receives: 無
; Returns: 無
;-------------------------------------------------------
TranslateBuffer PROC
pushad
mov ecx, bufSize ; 設(shè)置循環(huán)計數(shù)
mov esi, 0 ; 設(shè)置緩沖序號
L1:
xor buffer[esi], KEY ; 翻譯字節(jié)
inc esi ; 指向下一個字節(jié)
LOOP L1
popad
RET
TranslateBuffer ENDP
END
4.循環(huán)條件指令
1). LOOPZ 和 LOOPE 指令
- LOOPZ (Loop if zero)
想LOOP一樣工作,附加條件:必須設(shè)置零標志脊僚,以便控制轉(zhuǎn)移到目標標簽相叁。 格式如下:
LOOPZ destination
- LOOPE (Loop if equal)
與LOOPZ用法相同。
2). LOOPNZ 和 LOOPNE 指令
- LOOPNZ (Loop if not zero)
與LOOPZ相反辽幌,循環(huán)繼續(xù)的條件是ECX無符號整數(shù)大于0并且ZF被清空增淹。格式如下:
LOOPNZ destination
LOOPNE (Loop if not equal)
與LOOPE相反衔掸。示例
; 循環(huán)查找非負數(shù)
INCLUDE Irvine32.inc
.data
array SWORD -3, -6, -1, -10, 10, 30, 40, 4
sentinel SWORD 0
.code
main PROC
mov esi, OFFSET array
mov ecx, LENGTHOF array
L1:
test WORD PTR [esi], 8000h ; 設(shè)置符號位
pushfd ; 將flags入棧
add esi, TYPE array ; 移動到下一個元素
popfd ; 將flags出棧
LOOPNZ L1
jnz quit ; none found
sub esi,TYPE array ; ESI points to value
quit:
movsx eax,WORD PTR[esi] ; display the value
call WriteInt
call crlf
call WaitMsg ; 顯示等待輸入任意鍵信息
exit
main ENDP
END
5. 條件結(jié)構(gòu)
1). IF 塊結(jié)構(gòu)
- 示例1:
偽代碼:
if( boolean-expression )
statement-list-1
else
statement-list-2
匯編代碼:
mov eax,op1
cmp eax,op2 ; op1 == op2?
jne L1 ; no: skip next
mov X,1 ; yes: assign X and Y
mov Y,2
L1:
- 示例2:
偽代碼:
if op1 > op2
call Routine1
else
call Routine2
end if
匯編代碼:
mov eax,op1 ; move op1 to a register
cmp eax,op2 ; op1 > op2?
jg A1 ; yes: call Routine1
call Routine2 ; no: call Routine2
jmp A2 ; exit the IF statement
A1: call Routine1
A2:
- 示例3:
偽代碼:
if op1 == op2
if X > Y
call Routine1
else
call Routine2
end if
else
call Routine3
end if
匯編代碼:
mov eax,op1
cmp eax,op2 ; op1 == op2?
jne L2 ; no: call Routine3
; process the inner IF-ELSE statement.
mov eax,X
cmp eax,Y ; X > Y?
jg L1 ; yes: call Routine1
call Routine2 ; no: call Routine2
jmp L3 ; and exit
L1: call Routine1 ; call Routine1
jmp L3 ; and exit
L2: call Routine3
L3:
2). 符合表達式
- 邏輯AND運算符
偽代碼:
if (al > bl) AND (bl > cl)
X = 1
end if
匯編代碼:
cmp al,bl ; first expression...
ja L1
jmp next
L1:
cmp bl,cl ; second expression...
ja L2
jmp next
L2:
mov X,1 ; both true: set X to 1
next:
3). WHILE 循環(huán)
偽代碼:
while( val1 < val2 )
{
val1++;
val2--;
}
匯編代碼:
mov eax,val1 ; copy variable to EAX
beginwhile:
cmp eax,val2 ; if not (val1 < val2)
jnl endwhile ; exit the loop
inc eax ; val1++;
dec val2 ; val2--;
jmp beginwhile ; repeat the loop
endwhile:
mov val1,eax ; save new value for val1
示例:循環(huán)中嵌套IF狀態(tài)
C++代碼:
int array[] = {10,60,20,33,72,89,45,65,72,18};
int sample = 50;
int ArraySize = sizeof array / sizeof sample;
int index = 0;
int sum = 0;
while( index < ArraySize )
{
if( array[index] > sample )
{
sum += array[index];
}
index++;
}
匯編代碼:
; 判斷數(shù)組元素值是否大于50外驱, 如果大于則求和座哩。
INCLUDE Irvine32.inc
.data
sum DWORD 0 ; 大于50的數(shù)組元素之和
sample DWORD 50 ; 求和標準
array DWORD 10, 60, 30, 33, 72, 89, 45, 65, 72, 18 ; 數(shù)組
ArraySize = ($ - array) / TYPE array ; 數(shù)組長度
.code
main PROC
mov eax, 0 ; sum
mov edx, sample
mov esi, 0 ; 數(shù)組標識
mov ecx, ArraySize
L1:
cmp esi, ecx ; 判斷數(shù)組標識是否小于數(shù)組長度
jl L2
jmp L5 ; 無條件跳轉(zhuǎn)
L2:
cmp array[esi * 4], edx ; 判斷數(shù)組元素的數(shù)值是否大于50
jg L3
jmp L4
L3:
add eax, array[esi * 4] ; 求和
L4:
inc esi ; 數(shù)組標識+1
jmp L1 ; 跳轉(zhuǎn)
L5:
mov sum, eax ; 設(shè)置和
call WaitMsg ; 顯示等待輸入任意鍵信息
exit
main ENDP
END
4). 表驅(qū)動選擇
示例:用戶從鍵盤輸入朝蜘,根據(jù)輸入的字符查找對應(yīng)的字符串
; 用戶從鍵盤輸入,根據(jù)輸入的字符查找對應(yīng)的字符串
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, C, or 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 ; 從Al中讀取一個字符
mov ebx, OFFSET CaseTable ; EBX 指向表
mov ecx, NumberOfEntries ; 循環(huán)計數(shù)
L1:
cmp al, [ebx] ; 是否匹配
jne L2 ; 未發(fā)現(xiàn)因痛,繼續(xù)
call NEAR PTR [ebx + 1] ; 查找到燕耿,調(diào)用程序
call WriteString ; 顯示消息
call Crlf
jmp L3
L2:
add ebx, EntrySize ; 指向下一個實體
LOOP L1 ; 重復(fù)低千,直到ECX = 0
L3:
call WaitMsg ; 顯示等待輸入任意鍵信息
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
6. 有限狀態(tài)機
有限狀態(tài)機(FSM)是基于某些輸入改變狀態(tài)的機器或程序猪腕。
1). 驗證輸入字符串
程序在讀取輸入的字符串通常必須對輸入文本的異常檢測舞蔽。
2). 驗證有符號整型
程序驗證一個數(shù)字的符合正負號。
示例代碼:
; 有限狀態(tài)機
INCLUDE Irvine32.inc
ENTER_KEY = 13
.data
InvalidInputMsg BYTE "Invalid input", 13, 10, 0
.code
main PROC
call ClrScr
StateA:
call Getnext ; 讀取AL中的下一個字符
cmp al, "+" ; 判斷是否為+號
je StateB ; 等于就去StateB
cmp al, "-" ; 判斷是否為-號
je StateB ; 等于就去StateB
call IsDigit ; 判斷是否為數(shù)字, 如果AL包含數(shù)字码撰,則ZF等于1
jz StateC ; 等于就去StateC
call DisplayErrorMsg; 顯示異常信息
jmp Quit ; 退出程序
StateB:
call Getnext ; 讀取AL中的下一個字符
call IsDigit ; 如果包含數(shù)字則ZF = 1
jz StateC ; ZF = 1則跳到StateC
call DisplayErrorMsg; 顯示錯誤信息
jmp Quit ; 退出
StateC:
call Getnext
call IsDigit
jz StateC
cmp al, ENTER_KEY
je Quit
call DisplayErrorMsg
jmp Quit
Quit:
call Crlf
call WaitMsg
exit
main ENDP
;------------------------------------------------
; 從標準輸入讀取一個字符
; Receives: 無
; Returns: AL 包含一個字符
;------------------------------------------------
Getnext PROC
call ReadChar
call WriteChar
RET
Getnext ENDP
;------------------------------------------------
; 顯示錯誤信息
; Receives: 無
; Returns: 無
;------------------------------------------------
DisplayErrorMsg PROC USES edx
call Crlf
mov edx, OFFSET InvalidInputMsg
call WriteString
RET
DisplayErrorMsg ENDP
END
7. 條件控制流程指令
32位模式下,MASM包含一些高級的條件控制流程指令个盆,幫助我們簡單的使用條件狀態(tài)脖岛,但在64位模式下不可用。
1). 創(chuàng)建IF狀態(tài)
- 格式
.IF condition1
statements
[.ELSEIF condition2
statements ]
[.ELSE
statements ]
.ENDIF
- 條件可選表達式操作符
- 生成匯編代碼
mov eax,6
.IF eax > val1
mov result,1
.ENDIF
2). 有符號和無符號比較
- 無符號比較
.data
val1 DWORD 5
result DWORD ?
.code
mov eax,6
.IF eax > val1
mov result,1
.ENDIF
- 有符號比較
.data
val2 SDWORD -1
result DWORD ?
.code
mov eax,6
.IF eax > val2
mov result,1
.ENDIF
- 寄存器比較
mov eax,6
mov ebx,val2
.IF eax > ebx
mov result,1
.ENDIF
3). 符合表達式
- 格式
.IF expression1 ||[&&] expression2
statements
.ENDIF
- 示例:設(shè)置光標位置
; 設(shè)置光標位置
INCLUDE Irvine32.inc
; 使用.IF 和 .ENDIF 指令設(shè)置光標的位置
.code
main PROC
mov dl, 79 ; X軸
mov dh, 24 ; Y軸
call SetCursorPosition
call Crlf
call WaitMsg
exit
main ENDP
;------------------------------------------------
; 設(shè)置光標位置
; Receives: DL: X軸颊亮, DH: Y軸
; Returns: 無
;------------------------------------------------
SetCursorPosition PROC
.data
BadXCoordMsg BYTE "X-Coordinate out of range!", 0Dh, 0Ah, 0
BadYCoordMsg BYTE "Y-Coordinate out of range!", 0Dh, 0Ah, 0
.code
.IF (DL < 0) || (DL > 79)
mov edx, OFFSET BadXCoordMsg
call WriteString
jmp quit
.ENDIF
.IF (DH < 0) || (DH > 24)
mov edx, OFFSET BadYCoordMsg
call WriteString
jmp quit
.ENDIF
call Gotoxy ; 修改x,y值
quit:
RET
SetCursorPosition ENDP
END
- 示例:大學注冊
; 大學生注冊
; 使用.IF, .ENDIF, .ELSEIF指令
INCLUDE Irvine32.inc
.data
TRUE = 1
FALSE = 0
gradeAverage WORD 275 ; 測試值
credits WORD 12 ; 測試值
OkToRegister BYTE ?
.code
main PROC
mov OkToRegister, FALSE
.IF gradeAverage > 350
mov OkToRegister, TRUE
.ELSEIF (gradeAverage > 250) && (credits <= 16)
mov OkToRegister, TRUE
.ELSEIF (credits <= 12)
mov OkToRegister, TRUE
.ENDIF
call Crlf
call WaitMsg
exit
main ENDP
END
4). 使用.REPEAT
和.WHILE
創(chuàng)建循環(huán)
- 格式
; .REPEAT 指令
.REPEAT
statements
.UNTIL condition
; .WHILE 指令
.WHILE condition
statements
.ENDW
-
.REPEAT
示例
mov eax,0
.REPEAT
inc eax
call WriteDec
call Crlf
.UNTIL eax == 10
-
.WHILE
示例
mov eax,0
.WHILE eax < 10
inc eax
call WriteDec
call Crlf
.ENDW