基础指令
本章介绍 x86 汇编中最常用的基础指令,包括数据传送、算术运算、逻辑运算等。
数据传送指令
MOV 指令
MOV 是最基本的数据传送指令,用于在寄存器和内存之间复制数据。
; 寄存器到寄存器
mov eax, ebx ; 将 EBX 的值复制到 EAX
mov rax, rbx ; 64 位传送
; 立即数到寄存器
mov eax, 100 ; 将 100 加载到 EAX
mov rax, 0x12345678 ; 将十六进制数加载到 RAX
; 寄存器到内存
mov [ebx], eax ; 将 EAX 存储到 EBX 指向的内存
mov dword [rsi], 100 ; 将 100 存储到 RSI 指向的内存
; 内存到寄存器
mov eax, [ebx] ; 将 EBX 指向的内存值加载到 EAX
mov eax, [value] ; 将变量 value 的值加载到 EAX
MOV 指令的限制:
; 不能直接在内存之间传送
; mov [ebx], [esi] ; 错误!
; 正确做法:通过寄存器中转
mov eax, [esi]
mov [ebx], eax
; 不能直接将立即数传送到段寄存器
; mov ds, 0x1000 ; 错误!
; 正确做法
mov ax, 0x1000
mov ds, ax
MOV 扩展指令
MOVZX - 零扩展传送
将较小的操作数零扩展后传送到较大的目标:
movzx eax, al ; 8 位 -> 32 位,高位填 0
movzx eax, ax ; 16 位 -> 32 位
movzx rax, byte [rsi] ; 8 位 -> 64 位
; 示例
mov al, 0xFF
movzx eax, al ; EAX = 0x000000FF = 255
MOVSX - 符号扩展传送
将较小的操作数符号扩展后传送到较大的目标:
movsx eax, al ; 8 位 -> 32 位,高位填符号位
movsx eax, ax ; 16 位 -> 32 位
movsx rax, byte [rsi] ; 8 位 -> 64 位
; 示例
mov al, -5 ; AL = 0xFB
movsx eax, al ; EAX = 0xFFFFFFFB = -5
MOVSXD - 符号扩展双字到四字
专门用于 32 位到 64 位的符号扩展:
movsxd rax, eax ; 32 位 -> 64 位符号扩展
movsxd rax, dword [rsi]
交换指令
XCHG - 交换
交换两个操作数的值:
xchg eax, ebx ; 交换 EAX 和 EBX
xchg [mem], eax ; 交换内存和寄存器
; 原子操作(带 LOCK 前缀)
lock xchg [mem], eax ; 原子交换
BSWAP - 字节交换
反转寄存器中的字节顺序:
mov eax, 0x12345678
bswap eax ; EAX = 0x78563412(字节序转换)
栈操作指令
PUSH - 压栈
将操作数压入栈:
push rax ; RSP -= 8,将 RAX 存入栈
push qword [mem] ; 将内存值压栈
push 100 ; 将立即数压栈
; 32 位模式
push eax ; ESP -= 4
POP - 出栈
从栈中弹出数据:
pop rax ; 从栈读取到 RAX,RSP += 8
pop qword [mem] ; 弹出到内存
PUSHF/POPF - 标志寄存器操作
pushf ; 压入 FLAGS(16 位)
pushfd ; 压入 EFLAGS(32 位)
pushfq ; 压入 RFLAGS(64 位)
popf ; 弹出到 FLAGS
popfd ; 弹出到 EFLAGS
popfq ; 弹出到 RFLAGS
地址加载指令
LEA - 加载有效地址
计算有效地址而不是加载内存值:
lea eax, [ebx + ecx*4 + 0x100] ; EAX = EBX + ECX*4 + 0x100
; 常用于获取变量地址
lea rax, [buffer] ; RAX = buffer 的地址
; 常用于算术运算
lea eax, [eax + eax*2] ; EAX = EAX * 3
lea eax, [eax + eax*4] ; EAX = EAX * 5
lea eax, [eax + eax*8] ; EAX = EAX * 9
LEA 与 MOV 的区别:
mov eax, [ebx] ; 将 EBX 指向的内存值加载到 EAX
lea eax, [ebx] ; 将 EBX 的值加载到 EAX(相当于 mov eax, ebx)
mov eax, [ebx + 4] ; 加载内存值
lea eax, [ebx + 4] ; EAX = EBX + 4(计算地址)
算术运算指令
加法指令
ADD - 加法
add eax, ebx ; EAX = EAX + EBX
add eax, 100 ; EAX = EAX + 100
add [mem], eax ; 内存值 += EAX
add eax, [mem] ; EAX += 内存值
; 影响标志位:CF, ZF, SF, OF, AF, PF
ADC - 带进位加法
用于多精度加法:
; 64 位加法(在 32 位模式下)
add eax, [low] ; 加低 32 位
adc edx, [high] ; 加高 32 位(带进位)
; 128 位加法
add rax, rbx ; 加低 64 位
adc rdx, rcx ; 加高 64 位(带进位)
INC - 自增
inc eax ; EAX++
inc byte [mem] ; 内存字节值加 1
; 注意:INC 不影响 CF 标志
减法指令
SUB - 减法
sub eax, ebx ; EAX = EAX - EBX
sub eax, 100 ; EAX = EAX - 100
sub [mem], eax ; 内存值 -= EAX
; 影响标志位:CF, ZF, SF, OF, AF, PF
SBB - 带借位减法
用于多精度减法:
sub eax, [low] ; 减低 32 位
sbb edx, [high] ; 减高 32 位(带借位)
DEC - 自减
dec eax ; EAX--
dec byte [mem] ; 内存字节值减 1
; 注意:DEC 不影响 CF 标志
取补指令
NEG - 取补(取负)
neg eax ; EAX = -EAX(取二进制补码)
; 示例
mov eax, 5
neg eax ; EAX = -5
mov eax, -5
neg eax ; EAX = 5
比较指令
CMP - 比较
执行减法但不保存结果,只设置标志位:
cmp eax, ebx ; 比较 EAX 和 EBX
cmp eax, 100 ; 比较 EAX 和 100
cmp [mem], eax ; 比较内存值和 EAX
; 根据结果设置标志位
; EAX == EBX -> ZF = 1
; EAX < EBX -> CF = 1(无符号)或 SF ≠ OF(有符号)
; EAX > EBX -> CF = 0 且 ZF = 0
常用比较后的条件跳转:
cmp eax, ebx
je equal ; 相等跳转
jne not_equal ; 不相等跳转
jl less ; 小于跳转(有符号)
jg greater ; 大于跳转(有符号)
jb below ; 小于跳转(无符号)
ja above ; 大于跳转(无符号)
乘法指令
MUL - 无符号乘法
; 8 位乘法:AL * r/m8 -> AX
mul bl ; AX = AL * BL
; 16 位乘法:AX * r/m16 -> DX:AX
mul bx ; DX:AX = AX * BX
; 32 位乘法:EAX * r/m32 -> EDX:EAX
mul ebx ; EDX:EAX = EAX * EBX
; 64 位乘法:RAX * r/m64 -> RDX:RAX
mul rbx ; RDX:RAX = RAX * RBX
IMUL - 有符号乘法
; 单操作数形式(与 MUL 相同格式)
imul ebx ; EDX:EAX = EAX * EBX(有符号)
; 双操作数形式
imul eax, ebx ; EAX = EAX * EBX
imul eax, [mem] ; EAX = EAX * 内存值
imul eax, 100 ; EAX = EAX * 100
; 三操作数形式
imul eax, ebx, 100 ; EAX = EBX * 100
imul rax, rbx, 10 ; RAX = RBX * 10
除法指令
DIV - 无符号除法
; 8 位除法:AX / r/m8 -> AL=商, AH=余数
div bl ; AX / BL
; 16 位除法:DX:AX / r/m16 -> AX=商, DX=余数
div bx ; DX:AX / BX
; 32 位除法:EDX:EAX / r/m32 -> EAX=商, EDX=余数
div ebx ; EDX:EAX / EBX
; 64 位除法:RDX:RAX / r/m64 -> RAX=商, RDX=余数
div rbx ; RDX:RAX / RBX
IDIV - 有符号除法
idiv ebx ; EDX:EAX / EBX(有符号)
除法注意事项:
; 除法前必须正确设置高位寄存器
mov eax, 100
xor edx, edx ; 清零 EDX(无符号)
div ebx
mov eax, -100
cdq ; 符号扩展 EAX 到 EDX:EAX(有符号)
idiv ebx
逻辑运算指令
基本逻辑运算
AND - 与运算
and eax, ebx ; EAX = EAX & EBX
and eax, 0xFF ; EAX = EAX & 0xFF(掩码操作)
; 清零特定位
and eax, ~0x0F ; 清零低 4 位
; 测试特定位
and eax, 0x80
jnz bit_set ; 如果第 7 位为 1,跳转
OR - 或运算
or eax, ebx ; EAX = EAX | EBX
or eax, 0x0F ; 设置低 4 位
; 设置特定位
or eax, 0x80 ; 设置第 7 位
XOR - 异或运算
xor eax, ebx ; EAX = EAX ^ EBX
xor eax, eax ; EAX = 0(快速清零)
; 翻转特定位
xor eax, 0x80 ; 翻转第 7 位
NOT - 取反
not eax ; EAX = ~EAX(按位取反)
TEST 指令
执行 AND 运算但不保存结果,只设置标志位:
test eax, eax ; 测试 EAX 是否为 0
jz is_zero ; 如果为 0,跳转
test al, 0x80 ; 测试 AL 的第 7 位
jnz bit_set ; 如果第 7 位为 1,跳转
test eax, 0x0F ; 测试低 4 位是否有 1
jnz has_bits ; 如果有,跳转
移位指令
逻辑移位
SHL/SAL - 左移
shl eax, 1 ; EAX 左移 1 位(乘以 2)
shl eax, 4 ; EAX 左移 4 位(乘以 16)
shl eax, cl ; EAX 左移 CL 位
; 示例:乘以 8
mov eax, 10
shl eax, 3 ; EAX = 80
SHR - 逻辑右移
shr eax, 1 ; EAX 右移 1 位(无符号除以 2)
shr eax, 4 ; EAX 右移 4 位
; 示例:无符号除以 4
mov eax, 100
shr eax, 2 ; EAX = 25
算术移位
SAR - 算术右移
保持符号位不变:
sar eax, 1 ; EAX 右移 1 位(有符号除以 2)
; 示例:有符号除以 4
mov eax, -100
sar eax, 2 ; EAX = -25
循环移位
ROL - 循环左移
rol eax, 1 ; 循环左移 1 位
; 示例
mov al, 0x85 ; AL = 10000101
rol al, 1 ; AL = 00001011(最高位移到最低位)
ROR - 循环右移
ror eax, 1 ; 循环右移 1 位
RCL/RCR - 带进位循环移位
rcl eax, 1 ; 带进位循环左移
rcr eax, 1 ; 带进位循环右移
小结
本章介绍了 x86 的基础指令:
- 数据传送:MOV、MOVZX、MOVSX、XCHG、PUSH、POP、LEA
- 算术运算:ADD、ADC、SUB、SBB、INC、DEC、NEG、CMP、MUL、IMUL、DIV、IDIV
- 逻辑运算:AND、OR、XOR、NOT、TEST
- 移位操作:SHL、SHR、SAR、ROL、ROR
这些指令是编写汇编程序的基础,下一章将学习控制流指令。