位运算
汇编语言中的位运算指令非常丰富,它们直接在二进制位上进行操作,效率极高。在 x86 架构中,位运算指令主要可以分为以下五大类:
一、 逻辑运算指令 (Logical Instructions)
这类指令类似于高级语言中的 &, |, ^, ~ 运算符,按位执行布尔逻辑。
AND(按位与):- 作用:只有两个对应位都为 1 时,结果才为 1。
- 常见用途:掩码操作(清空特定位)。例如
and al, 0x0F会保留低4位,清空高4位。 - 标志位:清空 CF 和 OF,根据结果设置 ZF、SF、PF。
OR(按位或):- 作用:只要对应位中有一个为 1,结果就为 1。
- 常见用途:设置特定位。例如
or al, 0x80会强制将最高位设为 1。
XOR(按位异或):- 作用:对应位不同则为 1,相同则为 0。
- 常见用途:取反特定位或寄存器清零。
xor rax, rax比mov rax, 0更快且指令更短。
NOT(按位取反):- 作用:0 变 1,1 变 0(一元操作)。
- 注意:不影响任何标志位。
TEST(逻辑比较):- 作用:执行
AND运算,但不保存结果,只更新标志位。 - 常见用途:检查某一位是否为 1。例如
test al, 1可以检查 AL 是否为奇数。
- 作用:执行
二、 移位指令 (Shift Instructions)
移位指令会将位向左或向右移动,空出的位置补 0 或补符号位。
SHL/SAL(逻辑左移/算术左移):- 动作:所有位左移,最低位补 0,移出的最高位进入 CF。
- 用途:快速计算 乘以 2 的 n 次方。
SHR(逻辑右移):- 动作:所有位右移,最高位补 0,最低位进入 CF。
- 用途:快速计算 无符号除以 2 的 n 次方。
SAR(算术右移):- 动作:所有位右移,最高位补 原来的符号位(保持正负号不变)。
- 用途:快速计算 有符号除以 2 的 n 次方。
三、 循环移位指令 (Rotate Instructions)
移出的位不会丢弃,而是绕回到另一端重新进入。
ROL(左循环移位):最高位移出后,进入 CF 的同时回到最低位。ROR(右循环移位):最低位移出后,进入 CF 的同时回到最高位。RCL(带进位左循环移位):将 CF 也看作数据的一部分参与循环。RCR(带进位右循环移位):同上,右向循环。
四、 位测试与修改指令 (Bit Test & Modify)
这类指令允许你直接操作指定的某一个二进制位(通过索引)。
BT(Bit Test):把指定的第 \(n\) 位复制到 CF 标志位。BTS(Bit Test and Set):把第 \(n\) 位存入 CF,然后将该位置 1。BTR(Bit Test and Reset):把第 \(n\) 位存入 CF,然后将该位置 0。BTC(Bit Test and Complement):把第 \(n\) 位存入 CF,然后将该位 翻转 (0\(\leftrightarrow\)1)。
五、 位扫描指令 (Bit Scan)
用于寻找寄存器中第一个出现的 "1"。
BSF(Bit Scan Forward):从低位向高位扫描,返回第一个 1 的索引。BSR(Bit Scan Reverse):从高位向低位扫描,返回第一个 1 的索引。- 如果源操作数为 0,则 ZF 被设为 1。
六、 高级位操作指令 (BMI1 / BMI2 扩展)
现代 CPU (Intel Haswell / AMD Piledriver 以后) 增加了一些更强大的指令:
* POPCNT:计算一个数字里总共有多少个 "1"(Hamming weight)。
* LZCNT:计算开头有多少个连续的 "0"。
* TZCNT:计算末尾有多少个连续的 "0"。
总结表格
| 操作类型 | 指令 | 核心特点 |
|---|---|---|
| 逻辑 | AND, OR, XOR, NOT | 处理位遮罩、反转、清零 |
| 移位 | SHL, SHR, SAR | 用于 2 的幂次乘除法运算 |
| 循环 | ROL, ROR, RCL, RCR | 数据重组、加密算法常用 |
| 单位 | BT, BTS, BTR, BTC | 精确控制某一个比特位 |
| 扫描 | BSF, BSR, POPCNT | 查找 1 的位置或统计数量 |
学习建议:位运算最常配合 TEST 和 Jcc 指令使用。比如你想判断 RAX 的第 3 位是否为 1,通常写成:
TEST 指令非常简单。