Post

汇编语言总结

0 操作数的表示方法

符号表示内容
data立即数
reg通用寄存器(AX、BX、CX、DX、BP、SP、SI、DI)
seg或segreg段寄存器(CS、DS、SS、ES)
mem或[]存储器
src源操作数
dst目的操作数
n, nn, nnnn8位、16位、32位数
ac主累加器
oprd操作数

注意:

  • 汇编语言不区分大小写
  • 操作数有特定的范围
  • 以A、B、C、D、E开头的十六进制数前面要加0

1 数据传送类指令

1.1 MOV 指令

格式:MOV dst, src

可以实现:

  1. reg / mem / segreg ← reg

    ; reg to reg
    MOV AX, CX
    MOV BH, AL
    ; reg to segreg
    MOV DS, BX
    
  2. reg / segreg ← mem

    ; mem to segreg
    MOV DS, [SI+BX]
    ; mem to reg
    MOV AX, [2000H]
    
  3. reg / mem ← segreg

    ; segreg to reg
    MOV DX, ES
    
  4. 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

可以实现:

  1. reg ← reg

    XCHG AX, BX ; 字操作
    XCHG AH, BL ; 字节操作
    
  2. reg ← mem
  3. mem ← reg
  • 不允许立即数、段寄存器作为操作数
  • 存储器之间不能交换(mem 和 mem不能交换)

1.3 堆栈操作指令

1.3.1 PUSH 入栈指令

  1. PUSH mem/reg 将指定寄存器或存储单元的内容压入栈顶。

    PUSH AX ; SP = SP - 2
    
  2. PUSH segreg 将指定的16位段寄存器的内容压入栈顶。

    PUSH DS
    
  3. PUSHF标志寄存器的内容压入栈顶。

  • 操作数均为16位

1.3.2 POP 出栈指令

  1. POP mem/reg
  2. POP segreg segreg不能为CS寄存器
  3. 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)

  1. IN AL, DXIN AX, DX
    该指令中DX寄存器的内容就是I/O地址,将此端口地址中的8位或16位数据装入到AL或AX寄存器中。此指令允许访问的端口地址为0000H~FFFFH。

    ; DX = 1234H
    ; 端口1234H在I/O缓冲器中的低字节是23H,高字节是F4H。
    IN  AX,DX
    ; AX = F423H
    
  2. IN AL, portIN AX, port IO端口直接寻址
    port只能为8位端口地址。
    将此端口地址中的8位或16位数据装入到AL或AX寄存器中。此指令允许访问的端口地址为00H~FFH。

    ; 端口60H在I/O缓冲器中内容为43H
    IN AL, 60H
    ; AL = 43H
    

1.5.2 OUT 输出指令

  1. OUT DX, ALOUT 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位数据
    
  2. OUT port, ALOUT 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 小结

  1. 通用数据传送 MOVPUSHPOPXCHG
  2. 累加器专用传送 INOUTXLAT
  3. 地址传送 LEALDSLES
  4. 标志传送 PUSHFPOPFLAHFSAHF
  • POPFSAHF外,其他传送指令对标志位均无影响
  • 有且只有MOVPUSHPOP这三条指令允许以段寄存器做为操作数

2 算术运算指令

2.1 加法指令

指令功能
ADD mem/reg, mem/reg/data不带进位加法
ADC mem/reg, mem/reg/data带进位加法
INC mem/reg加1指令
  • 源操作数和目的操作数不能同时为存储器操作数[mem]
  • ADDADC 指令影响标志位
  • 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]
  • SUBSBB 指令影响标志位
  • 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) = AHAL(16bit)
reg/mem(16bit) × AX(16bit) = DXAX(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)

    1. 若运算结果低位大于9或AF=1(低位发生进位),则结果+06H;
    2. 若运算结果高位大于9或CF=1(高位发生进位),则结果+60H;
    3. 若1、2都满足,则结果+66H。
  • DAS 减法调整(Decimal Adjust after Subtraction)

    1. 若运算结果低位大于9或AF=1(低位发生借位),则结果-06H;
    2. 若运算结果高位大于9或CF=1(高位发生借位),则结果-60H;
    3. 若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/CLCF不在循环中,高位移至CF标志位和低位中
循环右移ROR mem/reg, 1/CLCF不在循环中,低位移至CF标志位和高位中
循环左移(包括CF)RCL mem/reg, 1/CLCF循环中,高位移至CF标志位,CF移至低位中
循环右移(包括CF)RCR mem/reg, 1/CLCF循环中,低位移至CF标志位,CF移至高位中
  • 移位次数等于1可在指令中直接给出;大于1则需要由CL寄存器给出。

对标志位的影响:

  • 移位指令
    1. 设置CF、SF、ZF、PF
    2. 移位后,若最高位发生变化,则OF = 1;否则OF = 0(仅在移位次数为1时设置)
  • 循环移位指令
    1. 设置CF
    2. 移位后,若最高位发生变化,则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)
TESTTEST 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
  1. 短属性标号 SHORT

    标号与控制转移指令的相对位置范围:在控制转移指令之上128行,之下127行。(-128 ~ 127)
    1个字节存放

  2. 近属性标号 NEAR

    标号与控制转移指令在同一段中
    标号在段中的偏移量在0000H ~ FFFFH之间
    1个字存放

  3. 远属性标号 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/JNZZF=1/0
JS/JNSSF=1/0
JO/JNOOF=1/0
JP/JNPPF=1/0
JC/JNCCF=1/0
JCXZCX=0
5.2.2.2 以两个无符号数比较的结果作为转移条件
助记符转移条件说明
JA/JNBECF∨ZF=0大于/不小于等于
JAE/JNB/JNCCF=0大于等于/不小于/无进位
JB/JNAE/JCCF=1小于/不大于等于/有进位
JBE/JNACF∨ZF=1小于等于/不大于
5.2.2.3 以两个带符号数比较的结果作为转移条件
助记符转移条件说明
JG/JNLE(SF⊕OF)∨ZF=0大于/不小于等于
JGE/JNLSF⊕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可以省去
  1. 将返回地址偏移量IP(调用指令的下一个地址)保存到堆栈中

    SP = SP - 2
    SS:SP = IP

  2. 将符号地址的偏移量存入IP

    IP = 符号地址的偏移量

5.3.2.2 段间调用
; example
CALL Far[BX]
CALL Far[100H]
CALL 1200H:1000H
; Far不能省去
  1. 将返回地址段基址CS保存到堆栈中

    SP = SP - 2
    SS:SP = CS

  2. 将返回地址偏移量IP(调用指令的下一个地址)保存到堆栈中

    SP = SP - 2
    SS:SP = IP

  3. 跳转至符号地址

    IP = 符号地址的偏移量
    CS = 符号地址的段基址

5.3.3 RET 返回指令

5.3.3.1 段内返回
  1. 从堆栈中取回返回地址偏移量

    IP = SS:SP
    SP = SP + 2

5.3.3.2 段间返回
  1. 从堆栈中取回返回地址偏移量

    IP = SS:SP
    SP = SP + 2

  2. 从堆栈中取回返回地址段基址

    CS = SS:SP
    SP = SP + 2

  • 段内和段间返回指令的汇编语言格式均可用RET,但机器码不同,段内为C3H,段间为CBH。

5.4 LOOPxx 循环指令

格式:LOOPxx 符号地址

执行操作:

  1. CX = CX - 1(此操作不影响标志位)
  2. 检查转移条件,若满足,则转向目标地址执行;否则执行LOOPxx后一条指令

转移方式:只允许段内短转移,跳转范围为 -128 ~ 127

助记符转移条件不转移条件
LOOPCX≠0CX=0
LOOPZCX≠0且ZF=1CX=0或ZF=0
LOOPNZCX≠0且ZF=0CX=0或ZF=1

6 CPU控制指令

6.1 标志位操作指令

助记符指令名称作用
CLC进位标志清0CF=0
STC进位标志置1CF=1
CMC进位标志取反CF=¬CF
CLD方向标志清0DF=0
STD方向标志置1DF=1
CLI中断标志清0IF=0
STI中断标志置1IF=1

6.2 NOP 空操作指令

指令不执行任何操作,其机器码占一个字节单元,在调试程序、修改程序时使用。
也可用NOP指令进行短延时。

This post is licensed under CC BY 4.0 by the author.