算术与逻辑指令(Arithmetic & Logic)

所有指令都带大小后缀(b/w/l/q)。此处以 l/q 举例,按需替换。

数据传送

指令 作用
mov 复制
movzx 零扩展复制(如 movzbl 8→32)
movsx 符号扩展复制(如 movslq 32→64)
xchg 交换
push / pop 压栈 / 出栈(64 位默认 pushq/popqpushq %rax = subq $8,%rsp 后写 (%rsp)popq 反之)
lea 载入有效地址(只做地址运算,不访问内存)
movabsq 装入 64 位立即数(等价 movq $imm64, %reg

常用扩展形式:

形式 含义
movzbl %al, %eax 8→32 零扩展
movzbq %al, %rax 8→64 零扩展
movzwl %ax, %eax 16→32 零扩展
movzwq %ax, %rax 16→64 零扩展
movsbl %al, %eax 8→32 符号扩展
movsbq %al, %rax 8→64 符号扩展
movswl %ax, %eax 16→32 符号扩展
movswq %ax, %rax 16→64 符号扩展
movslq %eax, %rax 32→64 符号扩展

注意:没有 32→64 的零扩展指令——因为写 32 位寄存器会自动清零高 32 位,movl %ecx, %eax 本身就是 32→64 零扩展(见模块一)。

累加器内部的符号扩展(无操作数,GAS 名 / Intel 名):

GAS Intel 作用
cbtw cbw %al 符号扩展 → %ax
cwtl cwde %ax 符号扩展 → %eax
cltq cdqe %eax 符号扩展 → %rax
cwtd cwd %ax%dx:%ax
cltd cdq %eax%edx:%eax
cqto cqo %rax%rdx:%rax
leaq (%rdi,%rsi,4), %rax     # rax = rdi + rsi*4 (仅计算,不取内存)

算术运算

指令 作用 影响标志
add src,dst dst += src ZF SF CF OF
sub src,dst dst -= src 同上
adc src,dst dst += src + CF(带进位加,多精度运算用) 同上
sbb src,dst dst -= src + CF(带借位减) 同上
inc dst dst += 1 除 CF 外
dec dst dst -= 1 除 CF 外
neg dst dst = -dst(取补)
imul src,dst dst *= src(有符号) CF OF
imul src,reg,dst dst = reg * src CF OF
imul $imm,reg,dst dst = reg * imm(三操作数立即数形式) CF OF
imul src 单操作数形式:%rdx:%rax = %rax * src(有符号版 mul) CF OF
mul src 无符号乘(隐式累加器) CF OF
idiv src 有符号除(隐式累加器) 无定义
div src 无符号除(隐式累加器) 无定义

mul/div/idiv 只有一个显式操作数,被除数/结果位置由大小决定:

大小 被除数(隐式) 结果
b %ax %al,余数 %ah
w %dx:%ax %ax,余数 %dx
l %edx:%eax %eax,余数 %edx
q %rdx:%rax %rax,余数 %rdx
movq $10, %rax
xorq %rdx, %rdx        # 无符号除法必须先清 rdx(被除数高位)
movq $3, %rbx
divq %rbx              # rax=10/3=3(商), rdx=10%3=1(余数)

movq $-10, %rax
cqto                   # 有符号除法先符号扩展 rax -> rdx:rax
movq $3, %rbx
idivq %rbx             # rax=-3, rdx=-1(余数随被除数符号)

多精度(128 位)加法示例——adc 把低 64 位的进位带进高 64 位:

# (rdx:rax) += (rcx:rbx),rdx:rax 为 128 位整数(高:低)
addq %rbx, %rax        # 低 64 位相加,进位进 CF
adcq %rcx, %rdx        # 高 64 位 = 高 + 高 + CF

忘了清 %rdx/cqto 是除法最常见的 bug——%rdx 里的残留值会一起参与被除数。

补码与有符号数(理解符号扩展与比较的基础)

  • x86 用补码表示有符号整数:最高位是符号位,-x = ~x + 1。8 位范围 −128…127,0xFF 是 −1,0x80 是 −128。
  • 同一个位模式既可以当无符号数也可以当有符号数解释:0xFF 作为无符号是 255,作为有符号是 −1。CPU 只做运算,解释权在使用者——这就是"有符号比较"和"无符号比较"要分开的原因。
  • 符号扩展:把有符号数从窄变宽,高位填符号位(movsblmovslqcqto 等);零扩展:当无符号数处理,高位填 0(movzbl 等)。扩展错了会得到完全不同的数:8 位的 −1(0xFF)零扩展成 256,符号扩展成 −1。
  • 算术右移 sar 填符号位(-8 >> 1 == -4),逻辑右移 shr 填 0;左移两种等价。
  • 比较规则汇总:cmp 之后,无符号比较用 ja/jb(看 CF),有符号比较用 jg/jl(看 SF 与 OF 的组合)——比较 −1 与 1 时,无符号视角 −1 是最大的 255。
movq $-1, %rax           # rax = 0xFFFFFFFFFFFFFFFF(补码 -1)
sarq $1, %rax            # 算术右移:仍是 -1(0xFFFF...)
movq $0x7FFFFFFFFFFFFFFF, %rax
addq $1, %rax            # 溢出:变为 0x8000... = 最小的负数,OF=1

逻辑运算

指令 作用
and 按位与
or 按位或
xor 按位异或(常用 xorl %eax,%eax 清零,比 movl $0,%eax 短)
not 按位取反
sal / shl 左移(同一操作码)
sar 算术右移(保留符号位)
shr 逻辑右移

移位指令:第二个操作数可为立即数或 %cl(移位数放 cl 中)。硬件只使用计数的低 5 位(32 位操作数)或低 6 位(64 位操作数),即 shlq $66, %rax 实际移 2 位。

双精度移位(shld/shrd)把第二个寄存器作为"延长部分"参与移位:

shldl $4, %ebx, %eax   # eax = (eax << 4) | (ebx >> 28)
shrdl %cl, %ebx, %eax  # eax = (eax >> cl) | (ebx << (32-cl))
xorl %eax, %eax        # rax = 0 (写 32 位自动清高 32 位)
shll $2, %eax          # eax <<= 2
sarl %cl, %ebx         # ebx 算术右移 cl 位

位操作与循环移位

指令 作用
bt src,dst 测试 dst 第 src 位,结果进 CF
bts src,dst 测试并置位(Test and Set)
btr src,dst 测试并清零
btc src,dst 测试并取反
bsf src,dst 从低向高找第一个置位位的索引(src 为 0 时 ZF=1,dst 无定义)
bsr src,dst 从高向低找第一个置位位的索引
popcnt src,dst 统计置位位数(需 POPCNT 特性)
bswap dst 字节序反转(32/64 位,大小端转换)
rol / ror 循环左/右移
rcl / rcr 带 CF 的循环左/右移(CF 参与循环)
btl $3, %ecx           # 测试 ecx 第 3 位
jc  bit3_set           # CF=1 表示该位为 1
popcntq %rax, %rbx     # rbx = rax 中 1 的个数
bswap %eax             # 0x11223344 -> 0x44332211

比较与测试

指令 作用
cmp b,a 计算 a-b 并设置标志(不保存结果)
test a,b 计算 a&b 并设置标志(常用于 test %eax,%eax 判零)
cmpl %ebx, %eax        # 计算 eax - ebx,据此设置标志
testl %eax, %eax       # eax 自身相与:判断是否为 0 / 正负

标志位操作

指令 作用
clc / stc / cmc 清 CF / 置 CF / CF 取反
lahf %eflags 低 8 位装入 %ah
sahf %ah 写回 %eflags 低 8 位
pushfq / popfq 整个 %rflags 压栈 / 弹出(32 位为 pushfl/popfl

注意:64 位模式下 push/pop 只支持 64 位操作数(无 pushl),写 pushq/popq 或裸 push/pop 均可。popfq 无法通过栈修改受限标志(如 IF 需特权)。

标志位速查

标志 含义 典型用途
ZF 结果为零 相等判断
CF 进位/借位 无符号溢出、adc/sbb
SF 符号位为负 有符号正负
OF 有符号溢出 有符号溢出
PF 低 8 位中 1 的个数为偶数 较少使用
AF 低 4 位向高 4 位进位 BCD 运算

对应条件跳转见模块五