汇编语言逻辑指令.md

原始源文件

---
ingested: true
ingestedAt: 2026-05-17
---
标题: 汇编语言 - 逻辑指令
UP主: 菜鸟教程
链接: https://www.runoob.com/assembly/assembly-logic.html
提取方式: WebFetch
内容: 
## 汇编语言 - 逻辑指令

逻辑指令在汇编编程中用于位级操作,广泛用于掩码运算、位提取、标志位设置和高效乘除运算。

---

## AND - 按位与

`AND` 对两个操作数逐位执行"与"运算(都为 1 时才为 1)。

## 实例

; 文件路径:and_demo.asm  
; AND 指令示例

section .text  
global _start

_start:  
; 基本按位与  
mov eax, 0x0F0F ; 0000 1111 0000 1111  
and eax, 0x00FF ; 0000 0000 1111 1111  
; 结果:eax = 0x000F ; 0000 0000 0000 1111

; 常用技巧1:屏蔽低 4 位(保留低 4 位)  
mov eax, 0xAB ; 1010 1011  
and eax, 0x0F ; 0000 1111  
; eax = 0x0B ; 0000 1011

; 常用技巧2:判断奇偶性(和 1 做 AND)  
mov eax, 42 ; 偶数  
and eax, 1 ; eax = 0(偶数)  
; 42 的二进制末尾是 0,42 & 1 = 0

mov eax, 43 ; 奇数  
and eax, 1 ; eax = 1(奇数)  
; 43 的二进制末尾是 1,43 & 1 = 1

; 常用技巧3:将寄存器清零  
xor eax, eax ; 等同于 mov eax, 0,但更快更短

; AND 会设置标志位:CF=0, OF=0, ZF 和 SF 根据结果  
mov eax, 1  
mov ebx, 0  
int 0x80  

---

## OR - 按位或

`OR` 对两个操作数逐位执行"或"运算(只要有一个为 1 就是 1)。

## 实例

; OR 指令示例

; 合并标志位  
mov eax, 0x0F00 ; 0000 1111 0000 0000  
or eax, 0x00FF ; 0000 0000 1111 1111  
; eax = 0x0FFF ; 0000 1111 1111 1111

; 设置某个位(把第 3 位设为 1)  
mov eax, 0 ; 0000 0000  
or eax, 0x08 ; 0000 1000  
; eax = 0x8 ; 0000 1000

; 大小写转换:大写转小写  
mov al, 'A' ; al = 0x41 (0100 0001)  
or al, 0x20 ; 0x20 = 0010 0000  
; al = 0x61 = 'a' ; 0110 0001  

---

## NOT - 按位取反

`NOT` 将操作数的每个位取反(0 变 1,1 变 0)。

## 实例

; NOT 指令示例

mov eax, 0x0F0F0F0F ; 0000 1111 0000 1111 ...  
not eax ; 1111 0000 1111 0000 ...  
; eax = 0xF0F0F0F0

; NOT 不影响任何标志位(与 AND/OR/XOR 不同)  

---

## XOR - 按位异或

`XOR` 对两个操作数逐位执行"异或"运算(不同为 1,相同为 0)。

## 实例

; 文件路径:xor_demo.asm  
; XOR 指令示例

section .text  
global _start

_start:  
; 基本异或  
mov eax, 0x0F0F ; 0000 1111 0000 1111  
xor eax, 0x00FF ; 0000 0000 1111 1111  
; 结果:eax = 0x0FF0 ; 0000 1111 1111 0000

; 经典技巧1:寄存器清零(比 mov reg, 0 高效)  
xor eax, eax ; eax = 0,只占用 2 字节  
xor ebx, ebx  
xor ecx, ecx

; 经典技巧2:交换两个寄存器(不需要第三个临时寄存器)  
mov eax, 100 ; eax = 100  
mov ebx, 200 ; ebx = 200  
xor eax, ebx ; eax = 100 xor 200  
xor ebx, eax ; ebx = 200 xor (100 xor 200) = 100  
xor eax, ebx ; eax = (100 xor 200) xor 100 = 200  
; 现在 eax = 200, ebx = 100(交换完成!)

; 经典技巧3:简单的加密/解密  
mov al, 'A' ; 原始字符 'A' = 0x41  
xor al, 0x55 ; 加密:al = 'A' xor 0x55  
; al 现在是某个乱码值  
xor al, 0x55 ; 解密:再 xor 0x55 恢复  
; al = 'A' 回来了!

mov eax, 1  
mov ebx, 0  
int 0x80  

> XOR 交换技巧虽然很酷,但在现代 CPU 上效率不如使用 `XCHG` 指令或临时寄存器。了解即可,不必执着使用。

---

## 移位指令

移位指令将二进制位向左或向右移动,常用于高效乘除运算(乘2、除2等)。

| 指令  | 功能                 | 示例                  |
| --- | ------------------ | ------------------- |
| SHL | 逻辑左移(左边出去,右边补0)    | shl eax, 1(乘以 2)    |
| SHR | 逻辑右移(右边出去,左边补0)    | shr eax, 1(无符号除以 2) |
| SAL | 算术左移(同 SHL)        | sal eax, 1          |
| SAR | 算术右移(右边出去,左边保持符号位) | sar eax, 1(有符号除以 2) |

## 实例

; 文件路径:shift_demo.asm  
; 移位指令示例

section .text  
global _start

_start:  
; SHL:逻辑左移 = 乘以 2 的幂  
mov eax, 10 ; eax = 10 (1010)  
shl eax, 1 ; eax = 20 (10100),即 10×2  
shl eax, 2 ; eax = 80 (1010000),即 20×4

; SHR:逻辑右移 = 无符号除以 2 的幂  
mov eax, 80 ; eax = 80  
shr eax, 3 ; eax = 10,即 80÷8

; SAR:算术右移 = 有符号除以 2 的幂(保留符号位)  
mov eax, -16 ; eax = -16 (0xFFFFFFF0)  
sar eax, 2 ; eax = -4 (0xFFFFFFFC),即 -16÷4  
; SAR 对比 SHR:  
; 如果 eax = 0xFFFFFFF0 (-16),SHR 会得到 0x3FFFFFFC (很大的正数)  
; 而 SAR 会得到 0xFFFFFFFC (-4),保留了符号位

; 移出的最后一位会进入 CF 标志位  
mov eax, 5 ; 0101  
shr eax, 1 ; eax = 2, CF = 1(末尾的1被移出)  
jc carry_was_set ; 如果 CF=1,说明原数是奇数

carry_was_set:  
mov eax, 1  
mov ebx, 0  
int 0x80  

---

## 循环移位指令

循环移位将移出的位重新填入另一端,形成循环:

| 指令  | 功能              |
| --- | --------------- |
| ROL | 循环左移(绕过 CF)     |
| ROR | 循环右移(绕过 CF)     |
| RCL | 带进位的循环左移(通过 CF) |
| RCR | 带进位的循环右移(通过 CF) |

## 实例

; 循环移位示例

; ROL:循环左移  
mov al, 0x85 ; 1000 0101  
rol al, 1 ; 左移 1 位:0000 1011  
; CF = 1(最高位移出到 CF)  
; 同时 CF 原本的 1 被移入最低位,形成循环

; ROL 实际效果:向左移 1 位,最高位同时进入 CF 和最低位  
; 1000 0101 -> ROL 1 -> 0000 1011

; RCL:带进位循环左移(CF 参与循环)  
clc ; 清除 CF = 0  
mov al, 0x85 ; 1000 0101  
rcl al, 1 ; CF 参与:CF bit7...bit0 -> CF  
; 结果:0000 1010, CF = 1

; 循环移位在加密算法和位操作中常用  

---

## 逻辑运算的实际用途

一个综合示例——使用逻辑运算实现简单的位标志系统:

## 实例

; 文件路径:bit_flags.asm  
; 使用逻辑运算实现位标志系统

section .data  
 flags db 0 ; 8 个标志位,初始全为 0  
; bit0: 是否激活  
; bit1: 是否可见  
; bit2: 是否需要保存  
; bit3: 是否已修改

 FLAG_ACTIVE equ 1 ; 0000 0001  
 FLAG_VISIBLE equ 2 ; 0000 0010  
 FLAG_NEED_SAVE equ 4 ; 0000 0100  
 FLAG_MODIFIED equ 8 ; 0000 1000

section .text  
global _start

_start:  
; 设置标志位:OR  
mov al, [flags]  
or al, FLAG_ACTIVE ; 设置 bit0  
or al, FLAG_VISIBLE ; 设置 bit1  
; al = 0000 0011 = 3  
mov [flags], al

; 检查标志位:AND + TEST  
test byte [flags], FLAG_ACTIVE ; 测试 bit0 是否为 1  
jnz is_active ; ZF=0 表示该位是 1

is_active:  
; 清除标志位:AND + NOT  
mov al, [flags]  
and al, ~FLAG_VISIBLE ; 清除 bit1(保留其他位不变)  
; al = 0000 0001 = 1  
mov [flags], al

; 切换标志位:XOR  
mov al, [flags]  
xor al, FLAG_MODIFIED ; 切换 bit3  
; 如果原来是 0 变成 1,原来是 1 变成 0

mov eax, 1  
mov ebx, 0  
int 0x80  

> 位标志操作在系统编程中极为常见。操作系统内核、设备驱动和嵌入式系统中广泛使用这种技巧来管理状态。