史上最详细汇编指令总结精讲
一. 汇编指令
1.1 数据传输指令
1.1.1mov指令
- **作用:**把一个字或者一个字节的操作数从源地址传送到目标地址
- 格式:
mov target, source
注意事项:
target不能是CS(代码段寄存器)
target和source不能同时为内存数、段寄存器(CS\DS\ES\SS\FS\GS)
不能将立即数传送给段寄存器
target和source必须类型匹配,比如,要么都是字节,要么都是字或者都是双字等。
由于立即数没有明确的类型,所以将立即数传送到target时,系统会自动将立即数零扩展到与target数的位数相同,再进行传送。有时,需要用BYTE PTR、WORD PTR明确指出立即数的位数
1.1.2xchg指令
- **作用:**把一个字或者一个字节的源操作数和目的操作数相交换
- 格式:
xchg target, source
注意事项:
- 不能同时都为内存操作
- 任意一个寄存器都不能为段寄存器
- 任意一个操作不能使用立即数
- 两个操作数的长度必须相等
1.1.3xlat换码指令
- **作用:**将 bx 指定的缓冲区、AL 指定的位移处的一个字节数据取出赋值给 AL
- 格式:
xlat
XLAT 指令: 功能: AL = DS:[BX + AL] 说明: - BX 指向一个字节表(缓冲区)的首地址 - AL 原来的值作为表内的偏移量 - 从 DS 段中 BX+AL 地址处取出一个字节 - 将取出的数据重新存入 AL1.1.4push pop堆栈指令
- **作用:**将 bx 指定的缓冲区、AL 指定的位移处的一个字节数据取出赋值给 AL
- 格式:
PUSH ax ; 将ax寄存器中的数据压入到栈中 POP ax ; 将栈顶中的数据出栈到ax中注意事项:
- 当栈为空时能不进行出栈
- 指令的操作数必须是16位,即不能使用al这种8位寄存器
1.1.5 地址传送指令lea lds les
**作用:**将对应的地址表示送入对应的寄存器中
格式:
LEA reg, mem ; reg ---> Register—寄存器 LDS reg, mem ; mem ---> Memory—内存 LES reg, mem
注意事项:
- LDS:将 mem 指定的字送入指定的寄存器中,并且 DS = mem+2
- LES:将 mem 指定的字送入指定的寄存器中,并且 ES = mem+2
1.1.6 标志寄存器传送指令lahf sahf pushf popf
**作用:**标志寄存器传送指令用来传送标志寄存器 FLAGS 的内容,方便对各个标志位的直接操作
格式:
; 低8位传送 LAHF ; 将标志寄存器的低字节传送给寄存器AH ; SF/ZF/AF/PF/CF状态标志位分别送入AH的第7/6/4/2/0位,而AH的第5/3/1位任意 SAHF ; SAHF将AH寄存器内容送FLAGS的低字节 ; 用AH的第7/6/4/2/0位相应设置SF/ZF/AF/PF/CF标志 ; 16位传送 PUSHF ; PUSHF指令将标志寄存器的内容压入堆栈,同时栈顶指针SP减2 POPF ; POPF指令将栈顶单元内容送标志寄存器,同时栈顶指针SP加2标志寄存器:用来存储相关指令的某些执行结果,用来为 CPU 执行相关指令提供依据并可以以此来控制 CPU 的相关行为。8086 中的标志寄存器为 PSW(程序状态字)。该寄存器并不是用来存放普通数据的,而是按位起作用,每一位都有专门的含义。
| 位 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 标志位 | - | - | - | - | OF | DF | IF | TF | SF | ZF | - | AF | - | PF | - | CF |
| 标志位 | 名称 | 作用说明 |
|---|---|---|
| SF | 符号标志位 | 如果执行结果为负数,则SF=1;如果结果非负,则SF=0。 |
| ZF | 零标志位 | 如果执行结果为0,则ZF=1;否则ZF=0。 |
| PF | 奇偶标志位 | 如果执行结果中二进制位1 的个数为偶数,则PF=1;否则PF=0。 |
| CF | 进/借位标志位 | 运算过程中最高位产生进位或借位,则CF=1,否则CF=0。常用于表示无符号数溢出。 |
| OF | 溢出标志位 | 当运算结果超出机器所能表示的范围时,产生溢出,OF=1。常用于表示有符号数溢出。 |
| DF | 方向标志位 | 控制串处理指令中DI、SI的增减方向。 DF=0:寄存器递增; DF=1:寄存器递减。 通过CLD指令清零,通过STD指令置1。 |
| TF | 调试标志位 | 当TF=1时,CPU进入单步执行模式,每执行一条指令产生一次调试中断。 |
| IF | 中断允许标志位 | 控制CPU是否响应外部中断请求。 IF=1:允许外部中断; IF=0:屏蔽外部中断。 |
| AF | 辅助进位标志位 | 运算过程中观察低4位(第三位向第四位进位)。如果最后四位向前产生进位或借位,则AF=1,否则AF=0。 |
| 标志位 | 为1(是) | 为0(否) |
|---|---|---|
| OF | OV | NV |
| DF | DN | UP |
| IF | EI | DI |
| SF | NG | PL |
| ZF | ZR | NZ |
| AF | AC | NA |
| PF | PE(偶) | PO(奇) |
| CF | CY | NC |
1.1.7 输入输出指令in out
IN指令
作用:
从外部设备端口读取数据到AL/AX。
格式:
| 格式 | 说明 |
|---|---|
| IN AL,PORT | 读取8位数据 |
| IN AX,PORT | 读取16位数据 |
| IN AL,DX | DX保存端口号 |
示例:
IN AL,60HOUT指令
作用:
将AL/AX中的数据输出到外部设备。
格式:
| 格式 | 说明 |
|---|---|
| OUT PORT,AL | 输出8位数据 |
| OUT PORT,AX | 输出16位数据 |
| OUT DX,AL | DX保存端口号 |
示例:
MOV AL,20H OUT 80H,AL1.2 算数运算指令
1.2.1 加法指令add adc inc
add ax, bx ; ax += bx adc ax, bx ; ax += bx + CF标志位 inc ax ; ax += 1注意事项:
- INC指令不影响进位CF标志位,按定义设置其他状态位标志
1.2.2 减法指令sub sbb dec
sub ax, bx ; ax -= bx sbb ax, bx ; ax -= bx - CF标志位 dec ax ; ax -= 1注意事项:
- DEC指令不影响位CF标志位,按定义设置其他状态位标志
1.2.3 比较指令cmp
cmp ax, bx ; ax - bx注意事项:
- CMP指令只做运算设置状态位标志,不进行赋值
1.2.4 乘法指令mul imul
mul bl ; ax = al × bl MUL无符号乘法(字/字节) imul bx ; dx:ax = ax × bx IMUL有符号乘法(字/字节)注意事项:
- 被乘数被隐藏在al/ax中,结果溢出的数据被保存在ah/dx中
- 不支持立即数(如
mul 5是错误的),乘数必须是寄存器或内存单元。
1.2.5 除法指令div idiv
div b1 ; al = ax ÷ b1, ah放余数 DIV 无符号除法(字/字节) idiv bx ; ax = dx:ax ÷ bx, dx放余数 IDIV 有符号除法(字/字节)注意事项:
- 被除数被隐藏在 AX / DX:AX 中:
- 8位除法:被除数在
AX中(AL放商,AH放余数)- 16位除法:被除数在
DX:AX中(AX放商,DX放余数)- 若使用16位除法,必须提前将 DX 清零(DIV)或符号扩展(IDIV)
- 除数放在 8/16 位 reg 或内存单元中,不支持立即数(如
div 5是错误的)- 除数为 0 或商溢出会触发CPU 除法溢出中断(0号中断),程序崩溃
1.2.6 求反指令neg
neg ax ; ax = 0 - ax1.2.7 符号扩展指令cbw cwd
| 指令 | 作用 | 操作数 |
|---|---|---|
CBW | 字节 → 字(8位 → 16位) | 隐含AL→AX |
CWD | 字 → 双字(16位 → 32位) | 隐含AX→DX:AX |
1.2.8 十进制调整指令
| 指令 | 作用 | 操作数 |
|---|---|---|
DAA | 加法后的压缩BCD码调整 | 隐含AL |
DAS | 减法后的压缩BCD码调整 | 隐含AL |
AAA | 加法后的非压缩BCD码调整 | 隐含AL |
AAS | 减法后的非压缩BCD码调整 | 隐含AL |
AAM | 乘法后的非压缩BCD码调整 | 隐含AX |
AAD | 除法前的非压缩BCD码调整 | 隐含AX |
压缩BCD码(Packed BCD):
- 一个字节存两位十进制数
- 例如:
0x12= 12(十进制) - 有效范围:
00H ~ 99H
非压缩BCD码(Unpacked BCD):
- 一个字节存一位十进制数(高4位为0)
- 例如:
0x02= 2,0x09= 9 - 有效范围:
00H ~ 09H
1.3 位运算指令
1.3.1 逻辑运算指令
| 指令 | 格式 | 功能说明 | 特殊要求 |
|---|---|---|---|
| AND | AND target, source | 按位与:1 & 1 = 1,其余为0,结果保存到target | 操作数要求同MOV |
| OR | OR target, source | 按位或:`1 | 1 = 1,1 |
| XOR | XOR target, source | 按位异或:相同为0,不同为1,结果保存到target | 同上 |
| NOT | NOT target | 按位非:1 → 0,0 → 1,结果保存到target | 操作数不能是立即数 |
| TEST | TEST target, source | 按位与操作,只设置标志位,不保存结果 | 同上 |
注意事项:
- 通常使用AND指令对指定位清0
- 通常使用OR指令对指定位置1
- 通常使用NOT指令将某个数据取反码,再加1就得到补码
- 通常使用XOR指令来取反某位
- 通常使用TEST指令来测试指定位置是0还是1
- 非运算对标志位不影响,其余指令对标志均会产生影响
1.3.2 移位运算
- 非循环移位运算
| 指令 | 格式 | 类型 | 移动方向 | 补位方式 | 标志位影响 |
|---|---|---|---|---|---|
| SHL(逻辑左移) | SHL reg/mem, 1/CL | 无符号数 | 左移 | 低位补0,最高位移入 CF | 移位后若 CF ≠ 最高位,则 OF=1,否则 OF=0 |
| SAL(算术左移) | SAL reg/mem, 1/CL | 有符号数 | 左移 | 低位补0,最高位移入 CF | 与 SHL 相同(操作完全相同) |
| SHR(逻辑右移) | SHR reg/mem, 1/CL | 无符号数 | 右移 | 高位补0,最低位移入 CF | — |
| SAR(算术右移) | SAR reg/mem, 1/CL | 有符号数 | 右移 | 高位补符号位(原最高位),最低位移入 CF | — |
- 循环移位
| 指令 | 格式 | 名称 | 功能说明 |
|---|---|---|---|
| ROL | ROL reg/mem, 1/CL | 循环左移(不带进位) | 最高位移入 CF,同时循环移回最低位 |
| ROR | ROR reg/mem, 1/CL | 循环右移(不带进位) | 最低位移入 CF,同时循环移回最高位 |
| RCL | RCL reg/mem, 1/CL | 带进位循环左移 | 最高位移入 CF,CF 原值移入最低位 |
| RCR | RCR reg/mem, 1/CL | 带进位循环右移 | 最低位移入 CF,CF 原值移入最高位 |
1.4 串操作指令
串的概念:串是连续存放在内存中的字节块或字块。每个串有一个起始地址和长度,待操作的数据库称为源串,目的地址称为目标串。
串指令操作的特点:
- 源操作数用寄存器SI寻址,默认在数据段DS中,但允许段超越:DS:[SI]
- 目的操作数用寄存器DI寻址,默认在附加段ES中,不允许段超越:ES:[DI]
- 每执行一次串操作指令,SI和DI将自动修改:±1(对于字节串)或±2(对于字串)
- 执行指令CLD指令后,DF = 0,地址指针增1或2
- 执行指令STD指令后,DF = 1,地址指针减1或2
- 数据块长度值由CX指定
1.4.1 串传送指令movs
作用:把字节/字操作数从主存的源地址传送至目的地址
使用格式,指令包括 MOVSB、MOVSW
MOVSB; 字节串传送,ES:[DI] ← DS:[SI] ; DF0,SI←SI+1,DI←DI+1;DF1,则递减MOVSW; 字串传送,ES:[DI] ← DS:[SI] ; DF0,SI←SI+2,DI←DI+2;DF1,则递减
在使用串操作指令前,需要提前将DS、ES、SI、DI、CX、DF设置好。
1.4.2 串存储指令stos
作用:把AL或AX的数据传送至目的地址
使用格式,指令包括 STOSB、STOSW
STOSB; 字节串存储:ES:[DI] ← AL ; DI ← DI ± 1STOSW; 字串存储:ES:[DI] ← AX ; DI ← DI ± 2
1.4.3 串读取指令lods
作用:将字节/字从数据段中读取出来保存在AL或者AX中
使用格式,指令包括 LODSB、LODSW
LODSB; 字节串读取:AL ← DS:[SI] ; SI ← SI ± 1LODSW; 字串读取:AX ← DS:[SI] ; SI ← SI ± 2
1.4.4 串比较指令cmps
作用:将主存中的源操作数减去目的操作数,以便设置标志,进而比较两操作数之间的关系
使用格式,指令包括 CMPSB、CMPSW
CMPSB; 字节串比较:DS:[SI] - ES:[DI] ; SI ← SI ± 1,DI ← DI ± 1CMPSW; 字串比较:DS:[SI] - ES:[DI ; SI ← SI ± 2,DI ← DI ± 2
1.4.5 串扫描指令scas
使用格式,指令包括 SCASB、SCASW
SCASB; 字节扫描:AL - ES:[DI] ; DI ← DI ± 1SCASW; 字扫描:AX - ES:[DI] ; DI ← DI ± 2
1.4.6 重复前缀指令rep
重复前缀 REP 可以加到串传送操作指令时。REP 前缀是每次执行串指令后 CX-1。CX-1 后,重复执行串指令,直到 CX 值为 0 时,指令才终止。
使用示例:REP、REPZ、REPNZ、REPE、REPNE
rep movsx; 无条件重复直到 CX == 0repz cmpsx; 无条件重复直到 CX == 0 或 ZF == 0repnz cmpsx; 无条件重复直到 CX == 0 或 ZF == 1repe cmpsx; 不断比较,直到 CX == 0 或 ZF == 0repne cmpsx; 不断比较,直到 CX == 0 或 ZF == 1
1.5 控制转移指令
1.5.1 无条件转移指令jmp
作用:跳转到对应的指令地址
使用格式:
jmp label; IP ← IP + 位移量jmp reg/mem; IP ← reg/mem(reg以及mem都需要是16位)jmp far ptr label; CS = label的段地址,IP = label的偏移地址jmp far ptr mem; CS = [mem+2],IP = [mem]
当指令只需要在当前代码段范围内转移时(±32KB),不需要更改CS地址,只需要修改IP地址。
实际编程时,汇编程序会根据目标地址的距离,自动处理成短转移/近转移/远转移。
程序员可用操作符
short/near ptr/far ptr强制指定。
1.5.2 条件转移指令jcc
作用:根据运算结果跳转到对应的指令地址。CC 即指令条件码。
| JCC指令 | 含义 | 检查符号位 | 典型C应用 |
|---|---|---|---|
| JZ / JE | 若为0则跳转;若相等则跳转 | ZF=1 | if (i == j); if (i == 0); |
| JNZ / JNE | 若不为0则跳转;若不相等则跳转 | ZF=0 | if (i != j); if (i != 0); |
| JS | 若为负则跳转 | SF=1 | if (i < 0); |
| JNS | 若为正则跳转 | SF=0 | if (i > 0); |
| JP / JPE | 若1出现次数为偶数则跳转 | PF=1 | (null) |
| JNP / JPO | 若1出现次数为奇数则跳转 | PF=0 | (null) |
| JO | 若溢出则跳转 | OF=1 | (null) |
| JNO | 若无溢出则跳转 | OF=0 | (null) |
| JC / JB / JNAE | 若进位则跳转;若低于则跳转;若不高于等于则跳转 | CF=1 | if (i < j); |
| JNC / JNB / JAE | 若无进位则跳转;若不低于则跳转;若高于等于则跳转 | CF=0 | if (i >= j); |
| JBE / JNA | 若低于等于则跳转;若不高于则跳转 | ZF=1 或 CF=1 | if (i <= j); |
| JNBE / JA | 若不低于等于则跳转;若高于则跳转 | ZF=0 且 CF=0 | if (i > j); |
| JL / JNGE | 若小于则跳转;若不大于等于则跳转 | SF != OF | if (si < sj); |
| JNL / JGE | 若不小于则跳转;若大于等于则跳转 | SF == OF | if (si >= sj); |
| JLE / JNG | 若小于等于则跳转;若不大于则跳转 | ZF != OF 或 ZF=1 | if (si <= sj); |
| JNLE / JG | 若不小于等于则跳转;若大于则跳转 | SF == 0 且 ZF == 0 | if (si > sj); |
| Tables | Are |
|---|---|
| Z/E | 相等 |
| N | 非 |
| S | 符号 |
| P | 奇偶 |
| O | 溢出 |
| C | 进位 |
| L | 小于(有符号数) |
| G | 大于(有符号数) |
| A | 高于(无符号数) |
| B | 低于(无符号数) |
1.5.3 计数器CX为0跳转指令jcxz
CX寄存器通常在程序中用作计数器,JCXZ指令用来判断计数是否为0。
使用格式:
jcxz label; 若 CX = 0,发生转移:IP ← IP + 8位位移量 ; 若 CX ≠ 0,顺序执行
1.5.4 循环指令loop、loopz、loopnz、loopne
LOOP label; CX ← CX − 1,若 CX ≠ 0,则循环到标号 labelLOOPZ label; CX ← CX − 1,若 CX ≠ 0 且 ZF = 1,则循环到标号 labelLOOPNZ label; CX ← CX − 1,若 CX ≠ 0 且 ZF = 0,则循环到标号 label
(注:LOOPNE为LOOPNZ的等效写法,功能相同)
1.5.5 子程序跳转指令call
子程序:子程序是完成特定功能的一段程序,当主程序(调用程序)需要执行这个功能时,采用 CALL 调用指令转移到该子程序的起始处执行,当运行完子程序功能后,采用 RET 返回指令回到主程序继续执行。
使用格式:
CALL labelCALL reg/mem; SP ← SP − 2,SS:[SP] ← IP,然后 jmp label/reg/memCALL far ptr labelCALL far ptr mem; SP ← SP − 2,SS:[SP] ← IP ; SP ← SP − 2,SS:[SP] ← CS
CALL 指令其实是做了两件事:执行到 CALL 时,先将 CALL 指令的下一条指令的 IP 入栈,再 JMP 到指定的函数地址处。
1.5.6 子程序返回指令ret
使用格式:
RET(或RETN) ; 无参数段内返回RET(或RETN) i16 ; 有参数段内返回RETF; 无参数段间返回RETFi16 ; 有参数段间返回
段内返回时:出栈,IP ← SS:[SP],SP ← SP + 2
段间返回时:出栈,IP ← SS:[SP],SP ← SP + 2,CS ← SS:[SP],SP ← SP + 2
带参数时:最后SP ← SP + i16
注意:
CALL FAR PTR需要与RETF配合使用。
1.5.7 中断指令int
作用:改变程序的执行顺序
使用格式:
INT i8; i8 为 8 位的中断向量编号
8086 的中断:
8086 可以管理 256 个中断,各种中断用一个向量编号来区别,上述的 i8 即代表一个中断标号。
常见中断类型:
- 除法错中断:执行除法指令,结果溢出产生的 0 号中断
- 指令中断:执行中断调用指令
INT i8产生的 i8 号中断 - 断点中断:用于断点调试(
INT 3)的 3 号中断 - 溢出中断:执行溢出中断指令,OF=1 产生的 4 号中断
- 单步中断:TF=1 时,在每条指令执行后产生的 1 号中断
1.6 处理机控制指令
指令包括:
- 标志处理指令:CLC、STC、CMC、CLD、STD、CLI、STI
- 处理机控制指令:HLT、NOP、WAIT、ESC、LOCK
- 重点掌握:CLC、STC、CMC、CLD、STD、CLI、STI、NOP
使用格式:
CLC; 复位进位标志位,CF ← 0STC; 置位进位标志位,CF ← 1CMC; 求反进位标志位,CF ← ~CFCLD; 复位方向标志位,DF ← 0(串操作指令中使用)STD; 置位方向标志位,DF ← 1CLI; 复位中断标志位,IF ← 0(用于控制可屏蔽中断的允许和禁止)STI; 置位中断标志位,IF ← 1NOP; 空操作,占用一个字节存储单元,空耗一个指令执行周期HLT; 使CPU进入暂停状态,这时CPU不执行任何操作。可用来在程序中等待中断,一般不使用LOCK; 指令前缀,可以放在任何指令前。在当前指令未执行完,8086输出引脚被封锁,其他控制器不能控制总线ESC; 六位立即数, reg/mem;把浮点指令交给浮点处理器
1.7 伪指令
伪指令不同于汇编指令,汇编指令有对应CPU能够识别的机器码,而伪指令由编译器识别。
ASSUME:说明段所对应的段寄存器
使用示例:assume cs:codeseg段定义:
SEGMENT ... ENDS
使用示例:codeseg segment ... codeseg ends源程序结束:
END
编译程序在编译时,编译到END时会停止编译。变量定义:DB、DW、DD
使用示例:
data segment var dd 100001h ; 定义了一个双字,var 为变量名,代表了偏移地址 dw 100h ; 定义了字变量 db 0h ; 定义了字节变量 data ends stack segment dw 0,0,0,0,0,0,0,0 ; 每个 0 都占一个字空间 stack ends
