算术与逻辑指令(Arithmetic & Logic)
所有指令都带大小后缀(b/w/l/q)。此处以 l/q 举例,按需替换。
数据传送
| 指令 | 作用 |
|---|---|
mov |
复制 |
movzx |
零扩展复制(如 movzbl 8→32) |
movsx |
符号扩展复制(如 movslq 32→64) |
xchg |
交换 |
push / pop |
压栈 / 出栈(64 位默认 pushq/popq;pushq %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 只做运算,解释权在使用者——这就是"有符号比较"和"无符号比较"要分开的原因。 - 符号扩展:把有符号数从窄变宽,高位填符号位(
movsbl、movslq、cqto等);零扩展:当无符号数处理,高位填 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 运算 |
对应条件跳转见模块五。