Intel指令包含了AND,OR,XOR,NOT,TEST指令,它们能直接在二进制位上实现布尔操作。其中TEST是不会改变数据的AND指令,但会改变CPU标志位。
部分布尔指令 | 说明 |
AND | AND 指令在两个操作数的对应位之间进行按位逻辑与操作,并将结果存放在目标操作数中。操作数可以是 8、16、32、64位,但是两个操作数必须是同样大小。 |
OR | OR 指令在两个操作数的对应位之间进行按位逻辑或操作,并将结果存放在目标操作数中。操作数可以是 8、16、32、64位,但是两个操作数必须是同样大小。 |
XOR | XOR 指令在两个操作数的对应位之间进行按位逻辑异或操作,并将结果存放在目标操作数中。 |
NOT | 翻转操作数中的所有位。其结果被称为反码。 |
TEST | 在两个操作数的对应位之间进行 AND 操作,并根据运算结果设置符号标志位、零标志位和奇偶标志位。但是TEST 指令不修改目标操作数。 |
AND指令
AND指令说明
X | Y | and的结果 | 备注 |
0 | 0 | 0 | 0 0 得 0 |
0 | 1 | 0 | 0 1 得 0 |
1 | 0 | 0 | 1 0 得 0 |
1 | 1 | 1 | 1 1 得 1 |
下列是被允许的操作数组合,但是立即操作数不能超过 32 位:
AND 寄存器,寄存器
AND 寄存器,内存地址
AND 寄存器,立即数(最大32位)
AND 内存地址,寄存器
AND 内存地址,立即数(最大32位)
AND 指令可以清除一个操作数中的 1 个位或多个位,同时又不影响其他位。这个技术就称为位屏蔽,就像在粉刷房子时,用遮盖胶带把不用粉刷的地方(如窗户)盖起来。目标数的哪个位想要设计为0,操作数的对应位就写0然后其它位写1。
mov al, 10101110b
and al, 11110110b ;AL 中的结果 = 1010 0110
AND 指令提供了一种简单的方法将字符从小写转换为大写。如果对比大写 A 和小写 a 的 ASCII 码,就会发现只有第5位不同:
0 1 1 0 0 0 0 1 = 61h ('a')
0 1 0 0 0 0 0 1 = 41h ('A')
其他的字母字符也是同样的关系。下例中,数组中所有字符都转换为大写:
.data
array BYTE 50 DUP(?)
.code
mov ecx,LENGTHOF array
mov esi,OFFSET array
L1: and BYTE PTR [esi], 11011111b ;清除位 5
inc esi
loop L1
AND 指令总是清除溢出和进位标志位,并根据目标操作数的值来修改符号标志位、零标志位和奇偶标志位。比如,下面指令的结果存放在 EAX 寄存器,假设其值为 0。在这种情况下,零标志位就会置 1:
and eax,1Fh
OR指令
OR指令说明
X | Y | or的结果 | 备注 |
0 | 0 | 0 | 0 0 得 0 |
0 | 1 | 1 | 0 1 得 1 |
1 | 0 | 1 | 1 0 得 1 |
1 | 1 | 1 | 1 1 得 1 |
下列是被允许的操作数组合,但是立即操作数不能超过 32 位。
OR 寄存器,寄存器
OR 寄存器,内存地址
OR 寄存器,立即数
OR 内存地址,寄存器
OR 内存地址,立即数
当需要在不影响其他位的情况下,将操作数中的 1 个位或多个位置为 1 时,OR 指令就非常有用了。目标数哪个位要改为1,就把操作数对应的位置改为1然后其它位写0。如果 AL 初始化为二进制数 1110 0011,把它与 0000 0100 进行 OR 操作,其结果等于 1110 0111:
mov al,11100011b
or al, 00000100b ;AL 中的结果 =1110 0111
OR 指令总是清除进位和溢出标志位,并根据目标操作数的值来修改符号标志位、零标志位和奇偶标志位。比如,可以将一个数与它自身(或 0)进行 OR 运算,来获取该数值的某些信息:
or al,al
零标志位 | 符号标志位 | AL 中的值 |
清0 | 清0 | 大于0 |
置1 | 清0 | 等于0 |
清0 | 置1 | 小于0 |
XOR指令
XOR 指令操作数组合和大小与 AND 指令及 OR 指令相同。两个操作数的每一对对应位都应用如下操作原则:如果两个位的值相同(同为 0 或同为 1),则结果位等于 0;否则结果位等于 1。
x | y | XOR结果 | 备注 |
0 | 0 | 0 | 0 0 得 0 |
0 | 1 | 1 | 0 1 得 1 |
1 | 0 | 1 | 1 0 得 1 |
1 | 1 | 0 | 1 1 得 0 |
对相同操作数进行两次 XOR 运算,则结果逆转为其本身。如下表所示,位 x 与位 y 进行了两次异或,结果逆转回 x 的初始值。异或运算这种“可逆的”属性使其成为简单对称加密的理想工具。
x | y | x㊉y(第一次XOR) | (x㊉y)㊉y(第二次XOR) |
0 | 0 | 0 | 0 |
0 | 1 | 1 | 0 |
1 | 0 | 1 | 1 |
1 | 1 | 0 | 1 |
XOR 指令总是清除溢岀和进位标志位,并根据目标操作数的值来修改符号标志位、零标志位和奇偶标志位。
NOT指令
NOT 指令触发(翻转)操作数中的所有位,其结果被称为反码。0变成1,1变成0。该指令允许的操作数类型如下所示:
NOT 寄存器
NOT 内存地址
例如,F0h 的反码是 0Fh:
mov al,11110000b
not al ;AL = 00001111b
NOT 指令不影响标志位。
TEST指令
TEST 与 AND 指令唯一不同的地方是,TEST 指令不修改目标操作数。TEST 指令允许的操作数组合与 AND 指令相同。在发现操作数中单个位是否置位时,TEST 指令非常有用。TEST 指令同时能够检查几个位。假设想要知道 AL 寄存器的位 0 和位 3 是否置 1,可以使用如下指令:
test al, 00001001b ;测试位 0 和位 3
从下面的数据集例子中,可以推断只有当所有测试位都清 0 时,零标志位才置 1:
0 0 1 0 0 1 0 1 <- 输入值
0 0 0 0 1 0 0 1 <- 测试值
0 0 0 0 0 0 0 1 <- 结果:ZF=0
0 0 1 0 0 1 0 0 <- 输入值
0 0 0 0 1 0 0 1 <- 测试值
0 0 0 0 0 0 0 0 <- 结果:ZF=1
TEST 指令总是清除溢出和进位标志位,其修改符号标志位、零标志位和奇偶标志位的方法与 AND 指令相同。