汇编语言总结
0 操作数的表示方法
符号 | 表示内容 |
---|---|
data | 立即数 |
reg | 通用寄存器(AX、BX、CX、DX、BP、SP、SI、DI) |
seg或segreg | 段寄存器(CS、DS、SS、ES) |
mem或[] | 存储器 |
src | 源操作数 |
dst | 目的操作数 |
n, nn, nnnn | 8位、16位、32位数 |
ac | 主累加器 |
oprd | 操作数 |
注意:
- 汇编语言不区分大小写
- 操作数有特定的范围
- 以A、B、C、D、E开头的十六进制数前面要加0
1 数据传送类指令
1.1 MOV 指令
格式:MOV dst, src
可以实现:
reg / mem / segreg ← reg
; reg to reg MOV AX, CX MOV BH, AL ; reg to segreg MOV DS, BX
reg / segreg ← mem
; mem to segreg MOV DS, [SI+BX] ; mem to reg MOV AX, [2000H]
reg / mem ← segreg
; segreg to reg MOV DX, ES
reg / mem ← data
; data to reg MOV CL, 05H MOV AX, 1234H ; data to mem MOV word ptr[BX], 0001H ; 显式声明字地址
- 立即数不能作为目的操作数
- CS只能作为源操作数
- IP寄存器不能通过MOV访问
- 立即数不能直接传送到段寄存器,但可以通过其他寄存器或堆栈传送
1.2 XCHG 指令(exchange)
格式:XCHG oprd1, oprd2
可以实现:
reg ← reg
XCHG AX, BX ; 字操作 XCHG AH, BL ; 字节操作
- reg ← mem
- mem ← reg
- 不允许立即数、段寄存器作为操作数
- 存储器之间不能交换(mem 和 mem不能交换)
1.3 堆栈操作指令
1.3.1 PUSH 入栈指令
PUSH mem/reg
将指定寄存器或存储单元的内容压入栈顶。PUSH AX ; SP = SP - 2
PUSH segreg
将指定的16位段寄存器的内容压入栈顶。PUSH DS
PUSHF
将标志寄存器的内容压入栈顶。
- 操作数均为16位
1.3.2 POP 出栈指令
POP mem/reg
POP segreg
segreg不能为CS寄存器POPF
- 操作数均为16位
- 执行完命令后SP = SP + 2
1.4 地址传送指令
1.4.1 LEA reg, mem
将指定存储器操作数的16位偏移地址装入指定的8个通用16位寄存器之一中。
; BX = 0400H, SI = 003CH
LEA BX, [BX + SI + 0F62H]
; BX = 0400H + 003CH + 0F62H = 139EH
1.4.2 LDS reg, mem
把一个存放在4个存储单元中共计为32位的数据(段地址和偏移量)传送到两个寄存器中。其中后两个字节(高16位)内容送到DS,前两个字节(低16位)内容送到指令中所出现的目的寄存器中。
; DS = 1000H, [10010H] = 0180H, [10012H] = 2000H
LDS SI, [0010H]
; DS = 2000H, SI = 0180H
1.4.3 LES reg, mem
与上条指令类似,只是把DS换成ES。
把一个存放在4个存储单元中共计为32位的数据(段地址和偏移量)传送到两个寄存器中。其中后两个字节(高16位)内容送到ES,前两个字节(低16位)内容送到指令中所出现的目的寄存器中。
; DS = 1000H, BX = 080AH
; [1080AH] = 05A2H, [1080CH] = 4000H
LES DI, [BX]
; ES = 4000H, DI = 05A2H
1.5 累加器专用传送指令
1.5.1 IN 输入指令(从外设取数据读入CPU)
IN AL, DX
或IN AX, DX
该指令中DX寄存器的内容就是I/O地址,将此端口地址中的8位或16位数据装入到AL或AX寄存器中。此指令允许访问的端口地址为0000H~FFFFH。; DX = 1234H ; 端口1234H在I/O缓冲器中的低字节是23H,高字节是F4H。 IN AX,DX ; AX = F423H
IN AL, port
或IN AX, port
IO端口直接寻址
port只能为8位端口地址。
将此端口地址中的8位或16位数据装入到AL或AX寄存器中。此指令允许访问的端口地址为00H~FFH。; 端口60H在I/O缓冲器中内容为43H IN AL, 60H ; AL = 43H
1.5.2 OUT 输出指令
OUT DX, AL
或OUT DX, AX
将AL或AX中的内容输出到由DX指定的I/O端口。端口地址范围0000H~FFFFH。MOV DX,0300H OUT DX,AL ; 向0300H端口传送8位数据 MOV DX,02FEH OUT DX,AX ; 向02FEH端口传送16位数据
OUT port, AL
或OUT port, AX
将AL或AX中的内容输出到由port所指定的端口中。port为8位端口地址,其地址范围为00H~FFH。OUT 80H, AL ; 向80H端口传送8位数据 OUT 82H, AX ; 向82H端口传送16位数据
1.6 XLAT 查表转换指令
BX为表格起点,AL为索引值。从[BX+AL]中取一个字节送给AL。
; DS = 2000H, BX = 0040H, AL = 0FH
XLAT
; AL = [20000H + 0040H + 0FH] = [2004FH]
1.7 标志寄存器传送指令
1.7.1 LAHF
把标志寄存器Flag的低8位传送到AH寄存器的指定位。
1.7.1 SAHF
把AH寄存器的指定位传送到标志寄存器中的SF、ZF、AF、PF和CF标志位。
1.7.1 PUSHF
把整个标志寄存器(包括全部九个标志,共16位)压入堆栈。
1.7.1 POPF
把栈顶内容弹出到标志寄存器。
1.8 小结
- 通用数据传送
MOV
、PUSH
、POP
、XCHG
- 累加器专用传送
IN
、OUT
、XLAT
- 地址传送
LEA
、LDS
、LES
- 标志传送
PUSHF
、POPF
、LAHF
、SAHF
- 除
POPF
、SAHF
外,其他传送指令对标志位均无影响 - 有且只有
MOV
、PUSH
、POP
这三条指令允许以段寄存器做为操作数
2 算术运算指令
2.1 加法指令
指令 | 功能 |
---|---|
ADD mem/reg, mem/reg/data | 不带进位加法 |
ADC mem/reg, mem/reg/data | 带进位加法 |
INC mem/reg | 加1指令 |
- 源操作数和目的操作数不能同时为存储器操作数[mem]
ADD
、ADC
指令影响标志位INC
指令不能用于给段寄存器加1,此指令不改变CF标志,但影响SF、ZF、AF、PF、OF标志位
2.2 减法指令
指令 | 功能 |
---|---|
SUB mem/reg, mem/reg/data | 不带借位减法 |
SBB mem/reg, mem/reg/data | 带借位减法 |
DEC mem/reg | 减1指令 |
- 源操作数和目的操作数不能同时为存储器操作数[mem]
SUB
、SBB
指令影响标志位DEC
指令不能用于给段寄存器减1,此指令不改变CF标志,但影响SF、ZF、AF、PF、OF标志位
2.3 NEG 求补指令
NEG mem/reg
用0减去指定的操作数来完成补码操作。其结果存放在指定的操作数中。可进行8位或16位操作。
2.4 CMP 比较指令
CMP mem/reg, mem/reg/data
该指令允许8位或16位操作数比较。源操作数或目的操作数之中任一个都可以作为存储器操作数[mem]。但其中的另一个一定是寄存器操作数。比较后源与目的操作数内容都不变。
CMP x, y
当两数x, y为无符号数比较时,用CF标志判断大小:
若x - y,CF = 0,则x > y;
若x - y,CF = 1,则x < y。
若两数x, y为带符号数比较大小时,用OF与SF判断大小:
若x - y后,SF 异或 OF = 0,则x > y;
若x - y后,SF 异或 OF = 1,则x < y。
2.5 乘法指令
指令 | 功能 |
---|---|
MUL reg/mem | 无符号数乘法 |
IMUL reg/mem | 带符号数乘法 |
reg/mem(8bit) × AL(8bit) = AH | AL(16bit) |
reg/mem(16bit) × AX(16bit) = DX | AX(32bit) |
MUL
只影响OF、CF标志位
OF = CF = 0,乘积的高一半(AH或DX)为0
OF = CF = 1,乘积的有效数字在AH或DX中
IMUL
只影响OF、CF标志位
OF = CF = 0,乘积的高一半是符号位扩展(AH或DX中不是00就是FF)
OF = CF = 1,乘积的有效数字在AH或DX中
2.6 除法指令
指令 | 功能 |
---|---|
DIV reg/mem | 无符号数除法 |
IDIV reg/mem | 带符号数除法 |
DX|AX(32bit) ÷ mem/reg(16bit) = AX(商)……DX(余)
AX(16bit) ÷ mem/reg(8bit) = AL(商)……AH(余)
DIV
标志SF、ZF、AF、PF、CF、OF不定
IDIV
余数与被除数具有相同的符号
当8位÷8位、或16位÷16位时,被除数做符号扩展
符号扩展指令:
CBW
(Convert Byte to Word):将AL的符号扩展到AH中(8位→16位)
CWD
(Convert Word to Doubleword):扩展AX的符号到DX中(16位→32位)
符号扩展指令不影响标志位。
2.7 压缩BCD码的调整/修正
DAA 加法调整(Decimal Adjust after Addition)
- 若运算结果低位大于9或AF=1(低位发生进位),则结果+06H;
- 若运算结果高位大于9或CF=1(高位发生进位),则结果+60H;
- 若1、2都满足,则结果+66H。
DAS 减法调整(Decimal Adjust after Subtraction)
- 若运算结果低位大于9或AF=1(低位发生借位),则结果-06H;
- 若运算结果高位大于9或CF=1(高位发生借位),则结果-60H;
- 若1、2都满足,则结果-66H。
2.8 非ASCII码的调整/修正
- AAA 加法调整(ASCII Adjust after Addition)
- AAS 减法调整(ASCII Adjust after Subtraction)
- AAM 乘法调整(ASCII Adjust after Multiplication)
- AAD 除法调整(ASCII Adjust before Division)
3 逻辑运算指令
3.1 移位指令
指令名称 | 指令格式 | 执行操作 |
---|---|---|
逻辑左移 | SHL mem/reg, 1/CL | 高位移至CF标志位,低位补零 |
算数左移 | SAL mem/reg, 1/CL | 高位移至CF标志位,低位补零 |
逻辑右移 | SHR mem/reg, 1/CL | 高位补零,低位移至CF标志位 |
算数右移 | SAR mem/reg, 1/CL | 正数高位补零,负数高位补一,低位移至CF标志位 |
循环左移 | ROL mem/reg, 1/CL | CF不在循环中,高位移至CF标志位和低位中 |
循环右移 | ROR mem/reg, 1/CL | CF不在循环中,低位移至CF标志位和高位中 |
循环左移(包括CF) | RCL mem/reg, 1/CL | CF在循环中,高位移至CF标志位,CF移至低位中 |
循环右移(包括CF) | RCR mem/reg, 1/CL | CF在循环中,低位移至CF标志位,CF移至高位中 |
- 移位次数等于1可在指令中直接给出;大于1则需要由CL寄存器给出。
对标志位的影响:
- 移位指令
- 设置CF、SF、ZF、PF
- 移位后,若最高位发生变化,则OF = 1;否则OF = 0(仅在移位次数为1时设置)
- 循环移位指令
- 设置CF
- 移位后,若最高位发生变化,则OF = 1;否则OF = 0(仅在移位次数为1时设置)
3.2 逻辑运算
指令名称 | 指令格式 | 执行操作 |
---|---|---|
与 | AND dst, src | (dst) ← (dst) ∧ (src) |
或 | OR dst, src | (dst) ← (dst) ∨ (src) |
非 | NOT oprd | (oprd) ← ¬(oprd) |
异或 | XOR dst, src | (dst) ← (dst) ⊕ (src) |
TEST | TEST oprd1, oprd2 | (oprd1) ∧ (oprd2) |
- 与“0”清零
- 或“1”置一
- 异或“1”取反
注:
- NOT指令不影响标志位
- 其他指令置CF、OF为0;SF、ZF、PF根据结果置位;AF未定义
- TEST指令只设置标志位,不保存结果
4 串操作指令
- 全部为1字节指令
- 用SI寻址源操作数(默认段为DS)
- 用DI寻址目的操作数(默认段为ES)
- 用CX做计数器
- 当标志位DF = 0时,地址增量;当DF = 1时,地址减量
- 串操作指令前面可以加上重复操作前缀,指令会重复执行,直到CX操作次数满足要求为止
4.1 MOVSB/MOVSW 字符串传送指令
由SI指定的MEM单元中的8位(MOVSB)或16位(MOVSW)数移动到DI指定的MEM单元中。
可以使用重复前缀REP,重复执行指令,直到CX减到0。
对标志位无影响。
MOV SI, 0100H ; 源地址偏移量
MOV DI, 2000H ; 目的地址偏移量
MOV CX, 100 ; 字符串的长度(重复操作的次数)
CLD ; 使DF=0,采用地址增量
REP MOVSB ; 重复执行100次
4.2 CMPSB/CMPSW 字符串比较指令
可用来检查两个字符串(数据块)是否相等。
根据[SI] - [DI]的结果设置FR标志寄存器。
- 加前缀REPE或REPZ,意为“当串未结束(CX≠0)且字符相等(ZF=1)时,继续比较”。(比较到不相等为止)
- 加前缀REPNE或REPNZ,意为“当串未结束(CX≠0)且字符不相等(ZF=0)时,继续比较”。(比较到相等为止)
; example: compare two strings
; 设两个字符串分别存放在DS段(ES=DS)的str1和str2区域,长度分别为L1和L2。
; 比较这两个字符串是否相等,若相等,则置M1单元为FFH,否则为00H。
LEA SI, str1 ; 将地址偏移量装入SI寄存器中
LEA DI, str2 ; 将地址偏移量装入DI寄存器中
MOV CX, L1
CMP CX, L2 ; 判断两字符串长度是否相同
JNE UNEQ ; 如果不相等跳转到UNEQ位置
CLD ; 使DF=0,采用地址增量
REPZ CMPSB
JNE UNEQ
MOV AL, 0FFH
JMP EXIT1
UNEQ: MOV AL, 00H
EXIT1: MOV M1, LZ
INT 20
4.3 SCASB/SCASW 字符串搜索指令
在字符串中搜索关键字。
根据AL/AX - ES:[DI]的结果设置FR标志寄存器。
- 加前缀REPE或REPZ,意为“当串未结束(CX≠0)且字符与关键字相等(ZF=1)时,继续搜索”。(找不一样的字符)
- 加前缀REPNE或REPNZ,意为“当串未结束(CX≠0)且字符与关键字不相等(ZF=0)时,继续搜索”。(找一样的字符)
; 确定字符串的长度
; 在以STRING为起始地址的字符串中搜索字符串结束符"$",并将字符串的长度(不包括"$")放入STRLN单元中。
; 如果连续100个字节均未出现"$",则在STRLN中填入0FFH。
LEA DI, STRING ; 加载地址
MOV AL, '$' ; 设置关键字
MOV CX, 100 ; 设置比较次数
CLD ; 使DF=0,采用地址增量
REPNE SCASB
JZ DONE1
MOV AL, 0FFH ; 未找到'$'
JMP DONE2
DONE1: MOV BX, 100
SUB BX, CX
MOV AL, BL ; 计算字符串长度
DONE2: MOV STRLN, AL
INT 20H
4.4 LODSB/LODSW 字符串装入指令
将DS:[SI]中的一个字节或一个字装入AL或AX寄存器中,并且修改SI的值,使其指向下一个字节或字。
- 不要使用REP前缀。如果使用了REP,等价于把字符串中最后一个字符装入AL/AX。
4.5 STOSB/STOSW 字符串填充指令
将AL或AX寄存器中的一个字节或一个字装入ES:[DI]中,并且修改DI的值,使其指向下一个字节或字的位置。
- 可以使用REP前缀,在内存中填充一串相同的数据。如清零,把内存某个区域填入相同的字符。
若源地址大于目的地址,则用地址增量方式从首地址开始传送;反之,则用地址减量方式从末地址开始传送。
4.6 字符串重复操作前缀
REP / REPE / REPZ / REPNE / REPNZ
该指令前缀重复执行后面的串指令,直到CX的内容减到0为止。
通常REP前缀与MOVS和STOS配合使用;CMPS和SCAS则可使用REPE,REPZ,REPNE和REPNZ等条件重复前缀。
5 程序控制类指令
5.1 目的地址的表示方法
5.1.1 符号地址
目的地址在指令中,取来指令后直接得到目的地址。
; example:
CMP AX, BX
JGE great
XCHG AX, BX
great: MOV max, AX
- 短属性标号 SHORT
标号与控制转移指令的相对位置范围:在控制转移指令之上128行,之下127行。(-128 ~ 127)
用1个字节存放 - 近属性标号 NEAR
标号与控制转移指令在同一段中
标号在段中的偏移量在0000H ~ FFFFH之间
用1个字存放 - 远属性标号 FAR
标号与控制转移指令不在同一段中
用2个字分别存放符号地址的段值、偏移量
5.1.2 寄存器reg
目的地址在reg中,取来指令后间接得到目的地址。
; example
JMP AX
5.1.3 储存器mem
目的地址在mem中,取来指令后间接得到目的地址。
; example
JMP word ptr [BX]
5.2 转移指令
5.2.1 JMP 无条件转移指令
格式:JMP 目标地址
执行操作:无条件转移到目标地址处
JMP short next ; 无条件短转移,指令长度:2Byte
JMP near next ; 无条件近转移,指令长度:3Byte
JMP far next ; 无条件远转移,指令长度:5Byte
5.2.2 Jcc 条件转移指令
格式:Jcc 目标地址
执行操作:当转移条件满足时,转向目标地址执行;当转移条件不满足时,执行下一条指令。
- 只允许段内短转移,跳转范围为 -128 ~ 127
5.2.2.1 以单个状态标志位或CX寄存器的值为转移条件
助记符 | 转移条件 |
---|---|
JZ/JNZ | ZF=1/0 |
JS/JNS | SF=1/0 |
JO/JNO | OF=1/0 |
JP/JNP | PF=1/0 |
JC/JNC | CF=1/0 |
JCXZ | CX=0 |
5.2.2.2 以两个无符号数比较的结果作为转移条件
助记符 | 转移条件 | 说明 |
---|---|---|
JA/JNBE | CF∨ZF=0 | 大于/不小于等于 |
JAE/JNB/JNC | CF=0 | 大于等于/不小于/无进位 |
JB/JNAE/JC | CF=1 | 小于/不大于等于/有进位 |
JBE/JNA | CF∨ZF=1 | 小于等于/不大于 |
5.2.2.3 以两个带符号数比较的结果作为转移条件
助记符 | 转移条件 | 说明 |
---|---|---|
JG/JNLE | (SF⊕OF)∨ZF=0 | 大于/不小于等于 |
JGE/JNL | SF⊕OF=0 | 大于等于/不小于 |
JL/JNGE | (SF⊕OF=1)∧(ZF=0) | 小于/不大于等于 |
JLE/JNG | (SF⊕OF)∨ZF=1 | 小于等于/不大于 |
5.3 过程调用和返回指令
5.3.1 PROC/ENDP 过程定义指令
[过程名] PROC [过程类型]
...
...
...
[过程名] ENDP
; example
display PROC NEAR
...
...
...
display ENDP
- NEAR类型:调用指令与过程在同一个段中
- FAR类型:调用指令与过程不在同一个段中
5.3.2 CALL 过程调用指令
格式:
CALL addr
:直接给出调用地址CALL disp16
:直接给出调用地址16位偏移量CALL reg/mem
:通过reg或mem给出地址CALL 符号地址
5.3.2.1 段内调用
; example
CALL DX
CALL Near[BX]
CALL Near[1000H]
CALL 1200H
; Near可以省去
- 将返回地址偏移量IP(调用指令的下一个地址)保存到堆栈中
SP = SP - 2
SS:SP = IP - 将符号地址的偏移量存入IP
IP = 符号地址的偏移量
5.3.2.2 段间调用
; example
CALL Far[BX]
CALL Far[100H]
CALL 1200H:1000H
; Far不能省去
- 将返回地址段基址CS保存到堆栈中
SP = SP - 2
SS:SP = CS - 将返回地址偏移量IP(调用指令的下一个地址)保存到堆栈中
SP = SP - 2
SS:SP = IP - 跳转至符号地址
IP = 符号地址的偏移量
CS = 符号地址的段基址
5.3.3 RET 返回指令
5.3.3.1 段内返回
- 从堆栈中取回返回地址偏移量
IP = SS:SP
SP = SP + 2
5.3.3.2 段间返回
- 从堆栈中取回返回地址偏移量
IP = SS:SP
SP = SP + 2 - 从堆栈中取回返回地址段基址
CS = SS:SP
SP = SP + 2
- 段内和段间返回指令的汇编语言格式均可用RET,但机器码不同,段内为C3H,段间为CBH。
5.4 LOOPxx 循环指令
格式:LOOPxx 符号地址
执行操作:
- CX = CX - 1(此操作不影响标志位)
- 检查转移条件,若满足,则转向目标地址执行;否则执行LOOPxx后一条指令
转移方式:只允许段内短转移,跳转范围为 -128 ~ 127
助记符 | 转移条件 | 不转移条件 |
---|---|---|
LOOP | CX≠0 | CX=0 |
LOOPZ | CX≠0且ZF=1 | CX=0或ZF=0 |
LOOPNZ | CX≠0且ZF=0 | CX=0或ZF=1 |
6 CPU控制指令
6.1 标志位操作指令
助记符 | 指令名称 | 作用 |
---|---|---|
CLC | 进位标志清0 | CF=0 |
STC | 进位标志置1 | CF=1 |
CMC | 进位标志取反 | CF=¬CF |
CLD | 方向标志清0 | DF=0 |
STD | 方向标志置1 | DF=1 |
CLI | 中断标志清0 | IF=0 |
STI | 中断标志置1 | IF=1 |
6.2 NOP 空操作指令
指令不执行任何操作,其机器码占一个字节单元,在调试程序、修改程序时使用。
也可用NOP指令进行短延时。