汇编指令速查表
本文以最常见的 x86 架构汇编语言为对象,将常用指令助记符按功能分类整理,方便学习和快速查阅。
指令助记符在不同汇编器(MASM、NASM、GAS)中基本一致,仅在操作数书写格式上略有差异。
九大类指令概览:
| 分类 | 指令数量 | 主要用途 |
|---|---|---|
| 数据传送指令 | 15 条 | 在寄存器、内存、I/O 端口之间搬运数据 |
| 算术运算指令 | 18 条 | 加减乘除、比较及数制调整 |
| 逻辑运算与移位指令 | 14 条 | 按位与或非异或、移位和循环移位 |
| 串操作指令 | 8 条 | 处理连续内存区域,配合重复前缀批量操作 |
| 控制转移指令 | 30+ 条 | 跳转、循环、过程调用与中断 |
| 条件设置指令 | 16 条 | 根据标志位设置字节值,用于消除分支 |
| 输入输出指令 | 4 条 | 读写 I/O 端口 |
| 处理器控制指令 | 14 条 | 控制标志位、同步、系统管理 |
| 浮点指令(x87 FPU) | 14 条 | 传统 x87 浮点栈运算 |
数据传送指令
数据传送指令是最基本的指令类型,负责在寄存器、内存和 I/O 端口之间搬运数据。
大部分传送指令不影响标志位(SAHF、POPF 除外)。
| 助记符 | 功能简述 |
|---|---|
MOV |
把源操作数复制到目的操作数,支持寄存器与寄存器、寄存器与内存、立即数到寄存器或内存 |
MOVSX |
带符号扩展的传送,将小尺寸操作数符号扩展为大尺寸(如字节扩展为双字,高位填充符号位) |
MOVZX |
带零扩展的传送,高位补 0(用于无符号数扩展) |
PUSH |
将操作数压入堆栈,栈指针 ESP/RSP 自动减小(先减后存) |
POP |
从堆栈弹出数据到目的操作数,栈指针自动增加(先取后加) |
PUSHA / PUSHAD |
将所有通用寄存器压栈(16 位用 PUSHA,32 位用 PUSHAD),常用于保存现场 |
POPA / POPAD |
从堆栈恢复所有通用寄存器,与 PUSHA/PUSHAD 对称使用 |
XCHG |
交换两个操作数的内容,至少有一个操作数是寄存器 |
LEA |
取有效地址(Load Effective Address),将源操作数的地址而非内存内容存入目的寄存器,常用于指针计算 |
LDS / LES / LFS / LGS / LSS |
将远指针装入段寄存器与通用寄存器(现代平坦内存模型中较少使用) |
LAHF |
将标志寄存器的低 8 位装入 AH 寄存器 |
SAHF |
将 AH 寄存器的内容存回标志寄存器的低 8 位 |
PUSHF / PUSHFD |
标志寄存器压栈(16 位用 PUSHF,32 位用 PUSHFD) |
POPF / POPFD |
从堆栈恢复标志寄存器 |
XLAT / XLATB |
查表翻译指令,将 AL 中的索引值对应内存字节送入 AL,BX/EBX 指向表基址 |
LEA与MOV的关键区别:LEA REG, [ADDR]装入的是地址值本身,而MOV REG, [ADDR]装入的是该地址处的内存内容。在进行地址计算(如LEA EAX, [EBX+4*ECX+8])时 LEA 非常高效。
算术运算指令
算术运算指令完成加、减、乘、除以及比较等操作,执行结果会直接影响标志寄存器中的相关标志位。
程序员通常根据运算后的零标志(ZF)、进位标志(CF)、符号标志(SF)和溢出标志(OF)来判断计算结果。
| 助记符 | 功能简述 |
|---|---|
ADD |
加法,目的 = 目的 + 源,影响 OF、SF、ZF、CF 等标志位 |
ADC |
带进位加法,目的 = 目的 + 源 + CF,用于多精度算术运算 |
SUB |
减法,目的 = 目的 - 源 |
SBB |
带借位减法,目的 = 目的 - 源 - CF,配合 ADC 用于多精度运算 |
INC |
操作数加 1,不影响 CF 标志 |
DEC |
操作数减 1,不影响 CF 标志 |
MUL |
无符号乘法,被乘数在 AL/AX/EAX,乘积存入 AX/DX:AX/EDX:EAX |
IMUL |
带符号乘法,支持单操作数、双操作数和三操作数三种形式 |
DIV |
无符号除法,被除数在 AX/DX:AX/EDX:EAX,商和余数存入指定寄存器 |
IDIV |
带符号除法,规则与 DIV 类似但处理符号 |
CMP |
比较两个操作数,执行减法但不保存结果,仅影响标志位(通常后跟条件跳转) |
NEG |
求补,对操作数取反再加 1,等价于 0 减去操作数 |
DAA |
加法后十进制调整,将 AL 调整为压缩 BCD 码格式 |
DAS |
减法后十进制调整 |
AAA |
加法后 ASCII 调整,用于非压缩 BCD 码 |
AAS |
减法后 ASCII 调整 |
AAM |
乘法后 ASCII 调整 |
AAD |
除法前 ASCII 调整 |
CBW / CWDE |
符号扩展:CBW 将 AL 符号扩展为 AX,CWDE 将 AX 符号扩展为 EAX |
CWD / CDQ |
符号扩展:CWD 将 AX 扩展为 DX:AX,CDQ 将 EAX 扩展为 EDX:EAX(常用于除法前准备被除数) |
有符号运算使用
IMUL/IDIV,无符号运算使用MUL/DIV。选错指令会导致结果错误——比如同一个二进制值在有符号和无符号解释下代表不同的数值。
逻辑运算与移位指令
这类指令按位进行与、或、非、异或等逻辑操作,以及移位和循环移位。
移位操作常用于快速乘除 2 的幂、位域提取和位掩码操作。
| 助记符 | 功能简述 |
|---|---|
AND |
按位与,常用于掩码操作(将特定位清零) |
OR |
按位或,常用于将特定位置 1 |
XOR |
按位异或,相同位为 0、不同为 1。XOR REG, REG 是清零寄存器的经典高效写法 |
NOT |
按位取反,所有位翻转 |
TEST |
测试位,执行 AND 运算但不保存结果,仅影响标志位(常用于检测某位是否为 0) |
SHL / SAL |
逻辑左移 / 算术左移,两者功能完全相同,低位补 0,高位移入 CF |
SHR |
逻辑右移,高位补 0,低位移入 CF(用于无符号数) |
SAR |
算术右移,高位用原符号位填充,保留数值符号(用于有符号数) |
ROL |
循环左移,移出的位补回另一侧 |
ROR |
循环右移,移出的位补回另一侧 |
RCL |
带进位循环左移,CF 参与循环(CF 作为临时存储位) |
RCR |
带进位循环右移,CF 参与循环 |
SHLD |
双精度左移,将目的和源操作数联合左移,结果存入目的 |
SHRD |
双精度右移,将目的和源操作数联合右移,结果存入目的 |
XOR REG, REG是清零寄存器的最优方式——生成的机器码比MOV REG, 0更短,执行速度也更快。
串操作指令
串操作指令专门处理连续内存区域,搭配重复前缀使用,常用于数组复制、内存比较和缓冲区搜索等批量操作。
这些指令的源地址默认由 DS:ESI 指向,目的地址由 ES:EDI 指向。
| 助记符 | 功能简述 |
|---|---|
MOVS |
串传送,将 [DS:ESI] 复制到 [ES:EDI] 并自动更新 ESI、EDI。按操作数大小分为 MOVSB(字节)、MOVSW(字)、MOVSD(双字) |
STOS |
串存储,将 AL/AX/EAX 存入 [ES:EDI] 并更新 EDI。常用于初始化内存区域为同一值 |
LODS |
串加载,从 [DS:ESI] 读入 AL/AX/EAX 并更新 ESI。较少使用,因为一次只加载一个值到累加器 |
CMPS |
串比较,比较 [DS:ESI] 与 [ES:EDI] 并影响标志位。通常配合 REPE/REPNE 搜索匹配或不匹配的位置 |
SCAS |
串扫描,比较 AL/AX/EAX 与 [ES:EDI] 并更新 EDI。常用于在内存中搜索特定值 |
REP |
重复前缀,当 ECX ≠ 0 时重复执行后续串指令,每次执行后 ECX 自动减 1 |
REPE / REPZ |
相等/为零时重复,ECX ≠ 0 且 ZF = 1 时继续(通常与 CMPS、SCAS 联用搜索匹配项) |
REPNE / REPNZ |
不等/不为零时重复,ECX ≠ 0 且 ZF = 0 时继续(用于搜索不匹配项) |
方向标志 DF 控制串操作指针的移动方向:执行
CLD后 DF=0,指针递增(正向处理);执行STD后 DF=1,指针递减(反向处理)。在使用串操作前应显式设置 DF,不要依赖默认值。
控制转移指令
控制转移指令改变程序执行流向,包括无条件跳转、条件跳转、循环以及过程调用与返回。
这是实现程序逻辑分支、循环和函数调用的基础。
无条件跳转与调用
无条件跳转不检查任何条件,直接改变 EIP/RIP 的值,让 CPU 从新地址继续执行。
| 助记符 | 功能简述 |
|---|---|
JMP |
无条件跳转,支持短跳转(-128 到 +127 字节)、近跳转(段内)和远跳转(跨段) |
CALL |
调用过程,先将返回地址压入堆栈,然后跳转到目标地址 |
RET / RETF |
从过程返回。RET 用于近返回(段内),RETF 用于远返回(跨段)。可带立即数参数同时释放栈上的参数空间 |
条件跳转
条件跳转根据标志寄存器中特定标志位的值决定是否跳转。
通常紧跟在 CMP 或 TEST 指令之后使用。
| 助记符 | 跳转条件 | 典型用途 |
|---|---|---|
JE / JZ |
ZF = 1(相等 / 为零) | CMP 后相等时跳转 |
JNE / JNZ |
ZF = 0(不等 / 不为零) | CMP 后不等时跳转 |
JS |
SF = 1(结果为负) | 运算结果为负数时跳转 |
JNS |
SF = 0(结果为正) | 运算结果为非负数时跳转 |
JC |
CF = 1(有进位/借位) | 无符号比较中小于时跳转,等同于 JB |
JNC |
CF = 0(无进位/借位) | 无符号比较中大于等于时跳转,等同于 JAE |
JO |
OF = 1(有溢出) | 有符号运算溢出时跳转 |
JNO |
OF = 0(无溢出) | 有符号运算无溢出时跳转 |
JP / JPE |
PF = 1(低 8 位中 1 的个数为偶数) | 奇偶校验为偶时跳转 |
JNP / JPO |
PF = 0(1 的个数为奇数) | 奇偶校验为奇时跳转 |
JA / JNBE |
CF = 0 且 ZF = 0 | 无符号大于(Above) |
JAE / JNB |
CF = 0 | 无符号大于等于(Above or Equal) |
JB / JNAE |
CF = 1 | 无符号小于(Below) |
JBE / JNA |
CF = 1 或 ZF = 1 | 无符号小于等于(Below or Equal) |
JG / JNLE |
ZF = 0 且 SF = OF | 有符号大于(Greater) |
JGE / JNL |
SF = OF | 有符号大于等于(Greater or Equal) |
JL / JNGE |
SF ≠ OF | 有符号小于(Less) |
JLE / JNG |
ZF = 1 或 SF ≠ OF | 有符号小于等于(Less or Equal) |
JCXZ |
CX = 0 时跳转 | 16 位模式下判断 CX 是否为零 |
JECXZ |
ECX = 0 时跳转 | 32 位模式下判断 ECX 是否为零 |
无符号比较和有符号比较使用不同的跳转指令,这是初学者最容易出错的地方。例如,比较两个数时
JA检查无符号大于,JG检查有符号大于——同一个 CMP 结果在这两种判断下可能不同。
循环指令
循环指令使用 ECX 作为计数器,每次迭代自动递减并判断是否继续循环。
| 助记符 | 功能简述 |
|---|---|
LOOP |
ECX 减 1,若 ECX ≠ 0 则跳转到目标地址 |
LOOPE / LOOPZ |
ECX 减 1,若 ECX ≠ 0 且 ZF = 1 则跳转(等于时继续循环) |
LOOPNE / LOOPNZ |
ECX 减 1,若 ECX ≠ 0 且 ZF = 0 则跳转(不等时继续循环) |
中断与返回
| 助记符 | 功能简述 |
|---|---|
INT n |
软件中断,调用中断向量号为 n 的中断服务程序(如 DOS 下 INT 21h 为系统功能调用) |
INTO |
溢出中断,当 OF = 1 时调用 INT 4(用于捕获算术溢出异常) |
IRET / IRETD |
从中断服务程序返回,恢复被中断时的 EFLAGS 和返回地址 |
条件设置指令
条件设置指令(386 及以上处理器支持)根据标志位状态将目的字节置为 1 或 0。
这类指令常用于消除分支跳转,提升代码执行效率——用条件设置替代短分支可以避免分支预测失败带来的性能损失。
| 助记符 | 设置条件 | 等价语义 |
|---|---|---|
SETZ / SETE |
ZF = 1 | 相等 / 结果为零时设置 |
SETNZ / SETNE |
ZF = 0 | 不等 / 结果不为零时设置 |
SETC |
CF = 1 | 有进位/借位时设置 |
SETNC |
CF = 0 | 无进位/借位时设置 |
SETO |
OF = 1 | 有溢出时设置 |
SETNO |
OF = 0 | 无溢出时设置 |
SETS |
SF = 1 | 结果为负时设置 |
SETNS |
SF = 0 | 结果为正时设置 |
SETG / SETNLE |
ZF=0 且 SF=OF | 有符号大于时设置 |
SETGE / SETNL |
SF = OF | 有符号大于等于时设置 |
SETL / SETNGE |
SF ≠ OF | 有符号小于时设置 |
SETLE / SETNG |
ZF=1 或 SF≠OF | 有符号小于等于时设置 |
SETA / SETNBE |
CF=0 且 ZF=0 | 无符号大于时设置 |
SETAE / SETNB |
CF = 0 | 无符号大于等于时设置 |
SETB / SETNAE |
CF = 1 | 无符号小于时设置 |
SETBE / SETNA |
CF=1 或 ZF=1 | 无符号小于等于时设置 |
CMP EAX, EBX后跟SETG AL的效果是:如果 EAX 有符号大于 EBX,则 AL 被设为 1,否则为 0。这比JG label; MOV AL, 1; JMP done; label: MOV AL, 0; done:更简洁高效。
输入输出指令
I/O 指令用于 CPU 与外部设备端口之间的数据交换。
在 x86 架构中,端口地址空间与内存地址空间相互独立,需要通过专门的 I/O 指令来访问。
| 助记符 | 功能简述 |
|---|---|
IN |
从指定端口读入数据到 AL/AX/EAX。端口地址在 0-255 时可直接写立即数,超过 255 时必须通过 DX 寄存器指定 |
OUT |
将 AL/AX/EAX 中的数据写入指定端口。端口地址规则与 IN 相同 |
INS |
从端口读入字节/字/双字到 ES:EDI 指向的内存,并自动更新 EDI(类似 STOS 但从 I/O 读取) |
OUTS |
将 DS:ESI 指向的内存字节/字/双字输出到端口,并自动更新 ESI |
在现代操作系统中(Windows、Linux),用户态程序通常无法直接执行 I/O 指令——这些指令被操作系统限制为仅内核态可用。在 DOS 环境或裸机编程中则可以自由使用。
处理器控制与杂项指令
这类指令用于控制处理器的运行状态,包括标志位操作、同步控制和系统信息获取。
| 助记符 | 功能简述 |
|---|---|
CLC |
清进位标志,CF 置为 0 |
STC |
置进位标志,CF 置为 1 |
CMC |
进位标志取反,CF 变为其相反值 |
CLD |
清方向标志,DF 置为 0,串操作指针自动递增 |
STD |
置方向标志,DF 置为 1,串操作指针自动递减 |
CLI |
清中断标志,IF 置为 0,禁止可屏蔽硬件中断 |
STI |
置中断标志,IF 置为 1,允许可屏蔽硬件中断 |
NOP |
空操作,机器码为 0x90,不执行任何有效操作。常用于指令对齐、延时填充或预留补丁空间 |
HLT |
停机,处理器暂停执行直到收到外部中断或复位信号 |
WAIT / FWAIT |
等待 FPU 完成当前操作,主要用于与 x87 协处理器同步 |
LOCK |
总线锁定前缀,使紧随其后的指令以原子方式执行。经典用法:LOCK XCHG 实现自旋锁、LOCK CMPXCHG 实现 CAS 操作 |
CPUID |
获取 CPU 特征信息,包括厂商 ID、支持的指令集扩展等。调用前需在 EAX 中设置功能号 |
RDTSC |
读取时间戳计数器,将 64 位计数值存入 EDX:EAX,用于高精度性能测量 |
浮点指令
以下为传统 x87 FPU 浮点指令,适用于使用浮点栈进行科学计算的场景。
在现代编程中,SSE/SSE2 等 SIMD 指令集已逐步取代 x87,但在理解遗留代码或进行简单浮点运算时,x87 仍被广泛使用。
| 助记符 | 功能简述 |
|---|---|
FLD |
将浮点数从内存加载到 FPU 栈顶 ST(0),栈指针上移 |
FST / FSTP |
将栈顶数据存入内存。FST 不弹出栈,FSTP 弹出栈(栈指针下移) |
FADD |
浮点加法,将 ST(0) 与指定操作数相加,结果存入 ST(0) |
FSUB |
浮点减法,ST(0) 减去指定操作数 |
FMUL |
浮点乘法 |
FDIV |
浮点除法,ST(0) 除以指定操作数 |
FCOM / FCOMP |
比较 ST(0) 与指定操作数,设置 FPU 状态字中的条件码。FCOMP 比较后弹出栈 |
FCHS |
改变 ST(0) 中数值的符号(正变负、负变正) |
FSQRT |
计算 ST(0) 的平方根,结果存入 ST(0) |
FSIN / FCOS |
计算 ST(0) 的正弦 / 余弦值(参数以弧度为单位),结果存入 ST(0) |
FPTAN |
计算 ST(0) 的正切值 |
FLD1 |
将常数 1.0 压入 FPU 栈顶 |
FLDZ |
将常数 0.0 压入 FPU 栈顶 |
FLDPI |
将常数 π(3.14159...)压入 FPU 栈顶 |
x87 FPU 使用浮点寄存器栈(ST(0) - ST(7) 共 8 个 80 位寄存器)进行操作。使用前需注意栈的深度限制——压入超过 8 个值会导致栈溢出异常。
注意事项
-
区分有符号和无符号指令。MUL/IMUL、DIV/IDIV、条件跳转中的 JG/JA 系列对应不同的数值解释。汇编器不会帮你检查类型——用错指令会静默产生错误结果。
-
串操作前务必设置 DF 标志。使用 CLD(递增)或 STD(递减)显式指定方向,不要假设默认值。不同编译器、不同调用约定的默认 DF 状态可能不同。
-
现代操作系统限制特权指令。CLI/STI、HLT、IN/OUT 等指令在 Ring 3(用户态)下执行会导致异常。这些指令通常仅在操作系统内核或裸机环境中使用。
-
优先使用现代指令集。在新代码中,条件设置指令(SETcc)优于条件跳转(消除分支预测开销),SSE/AVX 指令优于 x87(性能更好、编程模型更简单)。本表涵盖的 x87 和传统指令主要用于理解遗留代码。
