汇编语言做得最好的事情之一就是位测试。通常,不希望改变进行位测试的数值,但是却希望能修改 CPU 状态标志位的值。
条件跳转指令常常用这些状态标志位来决定是否将控制转向代码标号。例如,假设有一个名为 status 的 8 位内存操作数,它包含了与计算机连接的一个外设的状态信息。如果该操作数的位 5 等于 1,表示外设离线,则下面的指令就跳转到标号:
如果位 0、1 或 4 中任一位置 1,则下面的语句跳转到标号:
如果是位 2、3 和 7 都置 1 使得跳转发生,则还需要 AND 和 CMP 指令:
下面的代码比较了 EAX 和 EBX 中的两个无符号整数,并且把其中较大的数送入 EDX:
下面的代码比较了分别存放于三个变量 VI、V2 和 V3 的无符号 16 位数值,并且把其中最小的数送入AX:
下面的 32 位代码会持续循环,直到用户按下任意一个标准的字母数字键。如果输入缓冲区中当前没有按键,那么 Irvine32 库中的 ReadKey 函数就会将零标 志位置1:
上述代码在循环中插入了一个 10 毫秒的延迟,以便 MS-Windows 有时间处理事件消息。如果省略这个延迟,那么按键可能被忽略。
常见的编程任务是在数组中搜索满足某些条件的数值。例如,下述程序就是在一个 16 位数组中寻找第一个非零数值。如果找到,则显示该数值;否则,就显示一条信息,以说明没有发现非零数值:
;扫描数组 (ArrayScan.asm)
;扫描数组寻找第一个非零数值
INCLUDE Irvine32.inc
.data
intArray SWORD 0,0,0,0,1,20,35,-12,66,4,0
;intArray SWORD 1,0,0,0 ;候补测试数据
;intArray SWORD 0,0,0,0 ;候补测试数据
;intArray SWORD 0,0,0,1 ;候补测试数据
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 ;寻找数值
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 main
本程序包含了可以替换的测试数据,它们已经被注释出来。取消这些注释行,就可 以用不同的数据配置来测试程序。
XOR 指令有一个有趣的属性。如果一个整数 X 与 Y 进行 XOR,其结果再次与 Y 进行 XOR,则最后的结果就是 X:
XOR 的可逆性为简单数据加密提供了一种方便的途径:明文消息转换成加密字符串,这个加密字符串被称为密文,加密方法是将该消息与被称为密钥的第三个字符串按位进行 XOR 操作。预期的查看者可以用密钥解密密文,从而生成原始的明文。
下面将演示一个使用对称加密的简单程序,即用同一个密钥既实现加密又实现解密的过程。运行时,下述步骤依序发生:
1) 用户输入明文。
2) 程序使用单字符密钥对明文加密,产生密文并显示在屏幕上。
3) 程序解密密文,产生初始明文并显示出来。
程序清单完整的程序清单如下所示:
;加密程序 (Encrypt.asm)
INCLUDE Irvine32.inc
KEY = 239 ;1-255之间的任一值
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
;
;提示用户输入一个纯文本字符串
;保存字符串和它的长度
;接收:无
;返回:无
;-----------------------------------------
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
;-----------------------------------------
DisplayMessage PROC
;
;显示加密或解密消息
;接收:EDX指向消息
;返回:无
;-----------------------------------------
pushad
call WriteString
mov edx,OFFSET buffer ;显示缓冲区
call WriteString
call Crlf
call Crlf
popad
ret
DisplayMessage ENDP
;-----------------------------------------
TranslateBuffer PROC
;
;字符串的每个字节都与密钥字节进行异或
;实现转换
;接收:无
;返回:无
;-----------------------------------------
pushad
mov ecx,bufSize ;循环计数器
mov esi,0 ;缓冲区索引初始值赋0
L1:
xor buffer[esi],KEY ;转换一个字节
inc esi ;指向下一个字节
loop L1
popad
ret
TranslateBuffer ENDP
END main