1. 条件分支
允许决策的编程语言允许您使用称为条件分支的技术来改变控制流。在高级语言中,每个if状态,switch状态,分支循环都已经有分支逻辑,在汇编语言中,提供所有的你认为需要做的逻辑跳转。
2. Boolean 和Comparison 指令
Selected Boolean Instructions.png1). CPU 状态标识
Boolean 指令影响ZF,CF,SF,OF,PF标志位。
- ZF:操作的结果为0时设置
- CF:操作使目的操作数高位产生进位时设置。
- SF:如果复制目的操作数的高位时,设置为负;否则清除设置为正。
- OF:指令生成目的操作数在范围之外的结果时设置。
- PF:指令生成目的操作的1的个数为奇数时设置。
2). AND 指令
- 格式
AND destination, source
AND reg,reg
AND reg,mem
AND reg,imm
AND mem,reg
AND mem,imm
操作可以是8位,16位,32位或64位,但他们必须是相同的大小。
AND.png示例:
mov al,10101110b
and al,11110110b ; result in AL = 10100110
标志位:AND 指令总是清除OF、CF。 目的操作数分配数值修改SF,ZF,PF。
- 转换字符为大写
AND 指令提供一个简单的方式将小写转换为大写,通过比较ASCII码的方式进行转换,因为他们只有第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位,但他们必须是相同的大小。
OR.png示例:
mov al,11100011b
or al,00000100b ; result in AL = 11100111
标记:AND 指令总是清除OF、CF。 目的操作数分配数值修改SF,ZF,PF。
ZF_PF.png4). XOR 指令
- 格式
XOR destination,source
XOR.png
标志位:AND 指令总是清除OF、CF。 目的操作数分配数值修改SF,ZF,PF。
5). NOR 指令
- 格式
NOT reg
NOT mem
示例:
mov al,11110000b
not al ; AL = 00001111b
标志位:没有标志位被设置。
6). TEST 指令
- 作用
TEST指令在两个操作数中的每对匹配位之间执行隐含的AND操作,并根据分配给目标操作数的值设置SF,ZF和PF标志。 与AND指令的区别仅在TEST指令不修改目标操作数。
test al,00001001b; test bits 0 and 3
标志位:AND 指令总是清除OF、CF。 目的操作数分配数值修改SF,ZF,PF。
7). CMP 指令
-
作用
比较两个整数的大小 -
格式
CMP destination,source
标志位:CMP指令根据目标操作数在发生实际减法时所具有的值来更改溢出,符号,零,进位,辅助进位和奇偶校验标志。
ZF_CF.png示例:
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). 设置和清除标志位
- 设置零标记位
test al,0 ; set Zero flag
and al,0 ; set Zero flag
or al,1 ; clear Zero flag
- 设置符号标记位
or al,80h ; set Sign flag
and al,7Fh ; clear Sign flag
- 设置进位标志位
stc ; set Carry flag
clc ; clear Carry flag
- 设置溢出标记位
mov al,7Fh ; AL = +127
inc al ; AL = 80h (-128), OF=1
or eax,0 ; clear Overflow flag
3. 分支跳转
1). 分支结构
- 示例1
cmp eax,0
jz L1 ; jump if ZF = 1
.
.
L1:
- 示例2
and dl,10110000b
jnz L2 ; jump if ZF = 0
.
.
L2:
2). Jcond 指令
-
作用
当状态标志条件为真时,条件跳转指令分支到目标标签。 -
格式
Jcond destination
其中cond指的是标识一个或多个标志的状态的标志条件。例如基与CF与ZF标志位跳转如下:
Jcond.png- 使用CMP 指令
cmp eax,5
je L1 ; 当EAX值等于5的时候跳转到L1
mov ax,5
cmp ax,6
jl L1 ; 当AX值小于6的时候跳转到L1
mov ax,5
cmp ax,4
jg L1 ; 当AX值大于4的时候跳转到L1
3). 条件跳转指令类型
-
跳转指令集的四种分组
- 基于特殊寄存器
- (E)CX 操作数之间是否相等
- 无符号操作数比较
- 有符号操作数比较
下表位基于ZF,CF,OF,PF,SF标志位的跳转指令
Jumps Based on Specific Flag Values.png- 等于比较
在一些情况下两个操作数进行比较;另一些情况下,基于CX/ECX/RCX比较。
CMP leftOp,rightOp
下面是基于等号的跳转指令
Jumps Based on Equality.png- 示例: 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). 条件跳转应用
- 测试状态位
mov al,status
test al,00100000b ; test bit 5
jnz DeviceOffline
- 两个数比较大小
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
- 三个数中求最小
.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:
- 循环直到有键按下
.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). 应用: 顺序搜索数组
; 扫描数组
; 扫描数组中的非0值
INCLUDE Irvine32.inc
.data
intArray SWORD 0, 0, 0, 0, 1, 20, 35, -12, 66, 4, 0 ; 无符号整型数组
noneMsg BYTE "A non-zero value was not found", 0 ; 提示信息
.code
main PROC
mov ebx, OFFSET intArray ; 数组指针
mov ecx, LENGTHOF intArray ; 循环计数
L1:
cmp WORD PTR [ebx], 0 ; 与0比较
jnz found ; 发现不等于0的值
add ebx, 2 ; 指向下一个数组元素
LOOP L1 ; 继续循环
jmp notFound ; 未发现
found: ; 显示值
movsx eax, WORD PTR [ebx] ; 将有符号的值设置到EAX
call WriteInt ; 输出
jmp quit ; 退出程序
notFound: ; 显示未发现信息
mov edx, OFFSET noneMsg
call WriteString
quit:
call Crlf
exit
main ENDP
END
6). 应用:简单的字符串加密
-
原理:( (X ⊗ Y) ⊗ Y) = X
-
代码:
; 加密文本
INCLUDE Irvine32.inc
KEY = 239 ; 在1——255之间的任意数字
BUFMAX = 128 ; 最大缓冲字节
.data
sPrompt BYTE "Enter the plain text: ", 0 ; 输入文本提示信息
sEncrypt BYTE "Cipher text: ", 0 ; 加密文本提示信息
sDecrypt BYTE "Decryted: ", 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 ; 调用显示文本程序
call WaitMsg ; 显示等待输入任意键信息
exit
main ENDP
;-------------------------------------------------------
; 提示用户输入一个待加密文本,保存字符串及长度
; Receives: 无
; Returns: 无
;-------------------------------------------------------
InputTheString PROC
pushad ; 保存32位寄存器
mov edx, OFFSET sPrompt ; 显示提示信息
call WriteString
mov ecx, BUFMAX ; 设置最大字符个数
mov edx, OFFSET buffer ; 设置缓冲指针
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 ; 设置循环计数
mov esi, 0 ; 设置缓冲序号
L1:
xor buffer[esi], KEY ; 翻译字节
inc esi ; 指向下一个字节
LOOP L1
popad
RET
TranslateBuffer ENDP
END
效果.png
4.循环条件指令
1). LOOPZ 和 LOOPE 指令
- LOOPZ (Loop if zero)
想LOOP一样工作,附加条件:必须设置零标志,以便控制转移到目标标签。 格式如下:
LOOPZ destination
- LOOPE (Loop if equal)
与LOOPZ用法相同。
2). LOOPNZ 和 LOOPNE 指令
- LOOPNZ (Loop if not zero)
与LOOPZ相反,循环继续的条件是ECX无符号整数大于0并且ZF被清空。格式如下:
LOOPNZ destination
-
LOOPNE (Loop if not equal)
与LOOPE相反。 -
示例
; 循环查找非负数
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 ; 设置符号位
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. 条件结构
1). IF 块结构
- 示例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 循环
伪代码:
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
示例:循环中嵌套IF状态
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++;
}
汇编代码:
; 判断数组元素值是否大于50, 如果大于则求和。
INCLUDE Irvine32.inc
.data
sum DWORD 0 ; 大于50的数组元素之和
sample DWORD 50 ; 求和标准
array DWORD 10, 60, 30, 33, 72, 89, 45, 65, 72, 18 ; 数组
ArraySize = ($ - array) / TYPE array ; 数组长度
.code
main PROC
mov eax, 0 ; sum
mov edx, sample
mov esi, 0 ; 数组标识
mov ecx, ArraySize
L1:
cmp esi, ecx ; 判断数组标识是否小于数组长度
jl L2
jmp L5 ; 无条件跳转
L2:
cmp array[esi * 4], edx ; 判断数组元素的数值是否大于50
jg L3
jmp L4
L3:
add eax, array[esi * 4] ; 求和
L4:
inc esi ; 数组标识+1
jmp L1 ; 跳转
L5:
mov sum, eax ; 设置和
call WaitMsg ; 显示等待输入任意键信息
exit
main ENDP
END
4). 表驱动选择
示例:用户从键盘输入,根据输入的字符查找对应的字符串
; 用户从键盘输入,根据输入的字符查找对应的字符串
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 ; 循环计数
L1:
cmp al, [ebx] ; 是否匹配
jne L2 ; 未发现,继续
call NEAR PTR [ebx + 1] ; 查找到,调用程序
call WriteString ; 显示消息
call Crlf
jmp L3
L2:
add ebx, EntrySize ; 指向下一个实体
LOOP L1 ; 重复,直到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. 有限状态机
有限状态机(FSM)是基于某些输入改变状态的机器或程序。
Simple finite-state machine.png1). 验证输入字符串
程序在读取输入的字符串通常必须对输入文本的异常检测。
2). 验证有符号整型
程序验证一个数字的符合正负号。
示例代码:
; 有限状态机
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 ; 判断是否为数字, 如果AL包含数字,则ZF等于1
jz StateC ; 等于就去StateC
call DisplayErrorMsg; 显示异常信息
jmp Quit ; 退出程序
StateB:
call Getnext ; 读取AL中的下一个字符
call IsDigit ; 如果包含数字则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包含一些高级的条件控制流程指令,帮助我们简单的使用条件状态,但在64位模式下不可用。
Conditional Control Flow Directives.png1). 创建IF状态
- 格式
.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
- 示例:设置光标位置
; 设置光标位置
INCLUDE Irvine32.inc
; 使用.IF 和 .ENDIF 指令设置光标的位置
.code
main PROC
mov dl, 79 ; X轴
mov dh, 24 ; Y轴
call SetCursorPosition
call Crlf
call WaitMsg
exit
main ENDP
;------------------------------------------------
; 设置光标位置
; 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
创建循环
- 格式
; .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
网友评论