第三章 汇编语言

指令是使计算机执行某种特定操作的二进制编码。
8086 CPU指令系统有133条指令,通常分为数据寻址方式和程序寻址方式
8086指令是不定长,一般为1~6个字节。

数据寻址方式

  1. 隐含寻址
    指令已经默认对CPU中的某个寄存器进行操作,不用在指令中指明所使用的寄存器,即隐含了规定的操作数,这样的寻址方式称为隐含寻址。

  2. 立即数寻址

  3. 寄存器寻址

  4. 存储器操作数寻址
    执行单元EU根据指令中给出的寻址方式计算出16位的偏移量,称为有效地址(EA)送到总线接口单元BIU,经过加法器生成20位实际物理地址,在存储器读写总线周期对存储器进行操作,一般在表示EA时,用 [操作数] 表示
    由于计算EA需要时间,进行总线操作比较慢,因此存储器操作寻址比前三种要慢。

  • 直接寻址
    例:MOV SI, [2000H]
    默认使用DS段,若需使用其他段可使用段超越:MOV SI, ES:[2000H]

  • 寄存器间接寻址
    可间接寻址的寄存器有:BX、BP、SI、DI
    例:MOV AL, [BX]

    BX用于间接寻址时,默认段寄存器为DS,允许段超越
    BP用于间接寻址时,默认段寄存器为SS,允许段超越  
    SI用于间接寻址时,默认段寄存器为DS,允许段超越  
    DI用于间接寻址时,只有在串操作指令中,默认段寄存器为ES,其余情况默认段寄存器均为DS,不允许段超越
    

注:IP只能在代码段中(CS)寻址,SP只能在堆栈段(SS)中寻址

  • 寄存器相对寻址

    • 基址寻址
      操作数的有效地址是一个基址寄存器的内容加上一个8位或者16位的偏移量,基址寄存器是BX或者BP
      例:MOV AX,[BX+1000H]
      有时也写成 MOV AX,1000H[BX]或MOV AX,[BX]1000H

    • 变址寻址
      操作数的有效地址是一个变址寄存器的内容加上一个8位或者16位的偏移量,变址寄存器是SI和DI
      例:MOV AX, ARRAY[SI]

    • 基址加变址寻址
      操作数的有效地址是由基址寄存器和变址寄存器的内容相加产生
      例:MOV AX, [BP+SI]

    • 相对的基址加变址寻址
      操作数的有效地址是由基址寄存器、变址寄存器和偏移量三者相加产生。
      例:MOV AX, [BX+SI+3H]
      也可写成MOV AX,3H[BX][SI]或MOV AX,3H[BX+SI]

    • 数据串寻址
      DS:SI指示源串,ES:DI指示目的串,串长度计数用CX,并自动修改指针和计数器值,只用于串操作命令。
      例:MOVSB ;((ES:DI))((DS:SI)),CX=CX-1,SI=SI+1,DI=DI+1

  1. I/O端口寻址
    操作数存放在I/O端口中,指令执行时必须通过累加器(AX或AL)实现对端口的访问
  • 直接端口寻址
    指令直接提供8位端口的地址。
    例:IN AL, 63H
    当端口地址用一个字节来表示时,可使用直接端口寻址

  • 间接端口寻址
    由DX寄存器给出16位端口地址。
    例:MOV DX, 162H
    IN AX, DX

程序寻址方式

段内直接寻址

  1. 短跳转:把IP的内容加上一个字节的补码数作为新的IP,往前最多跳-128个字节,往后最多跳127个字节。

  2. 近跳转:把IP的内容加上两个字节的补码数作为新的IP,往前最多跳-32768个字节,往后最多跳32767个字节。

段内间接寻址

将寄存器或存储器操作数的内容赋给IP

段间直接寻址

直接在指令中给出新的CS和IP内容

段间间接寻址

用存储器操作数的内容赋给CS和IP

8086指令格式

指令一般由1~6个字节组成,具体格式如下图:


image.png
  1. 字节1
  • OPCODE:指令操作码

  • D:操作数传输方向(立即数指令和串操作指令除外)

    • D=0,Reg为源操作数
    • D=1,Reg为目的操作数
  • W:操作数字节长度

    • W=0,字节操作
    • W=1,字操作
  1. 字节2,寻址方式
  • MOD:寻址方式字段
    • 00=存储器方式,指令中无偏移量
    • 01=存储器方式,指令中有8位偏移量
    • 10=存储器方式,指令中有16位偏移量
    • 11=寄存器方式,指令中无偏移量
  • Reg:寄存器编码字段
000=AL/AX 100=AH/SP 001=CL/CX 101=CH/BP
010=DL/DX 110=DH/SI 011=BL/BX 111=BH/DI
  • R/M:寄存器/存储器字段
    • 在MOD=11,寄存器模式下,R/M给出第二个操作数的寄存器编码。
    • 在MOD≠11,存储器模式下,R/M给出计算有效地址的方法。


      image.png
  1. 字节3~字节6

DISP:存储器操作数地址偏移量,长度由MOD字段定义

DATA:指令中的立即数

8086指令系统

操作数符号表示

符号 含义
DST 目的操作数
SRC 源操作数
TARGET 循环、转移和调用指令操作数
imm 立即操作数,字节或字
acc 累加器AL或AX
reg 寄存器操作数
seg_reg 段寄存器
mem 存储器操作数
short_label 短标号(8位偏移量)
near_label 近标号(16位地址或偏移)
far_label 远标号(32位地址)

数据传送指令

  1. 通用数据传送指令 MOV DST,SRC

  2. 堆栈及堆栈操作
    堆栈是一种按先进后出(FILO)原则存取的存储器,它由堆栈指针寄存器SS:SP和RAM中的一部分组成,主要用于子程序调用或中断子程序的现场保护和恢复,以及参数传递等。
    SP的内容总是指向栈顶,即最后推入信息所在单元。

  • 进栈指令 PUSH SRC

  • 出栈指令 POP DST

  • 交换指令 XCHG DST,SRC

  • 累加器专用传送指令

    • 输入指令 IN AL/AX,PORT/DX
    • 输出指令 OUT PORT/DX,AL/AX
      PORT为8位直接地址
    • 换码指令 XLAT : (AL)←((BX)+(AL))
  • 地址传送指令

    • 有效地址传送指令 LEA reg16,SRC:(reg16) ←SRC
    • 指针送寄存器和DS
      LDS reg16,mem32 :(reg16) ←(mem32);(DS) ←(mem32+2)
    • 指针送寄存器和ES
      LES reg16,mem32 :(reg16) ←(mem32); (ES) ←(mem32+2)
  • 标志寄存器传送

    • LAHF : (AH) ←(flag低字节)
    • SAHF : (flag低字节) ←(AH)
    • PUSHF : (SP) ←(SP)-2, ((SP)+1),(SP)) ←flag
    • POPF : flag ←((SP)+1),(SP)), (SP) ←(SP)+2

算术指令

  1. 加法指令
  • ADD DST,SRC : (DST) ← (SRC) + (DST)
  • ADC DST,SRC : (DST) ← (SRC) + (DST)+CF
  • INC DST : (DST) ←(DST)+1 //不影响进位标志CF
  1. 减法指令
  • SUB DST,SRC : (DST) ←(DST)-(SRC)
  • SBB DST,SRC : (DST) ←(DST)-(SRC)-CF
  • DEC DST : (DST) ←(DST)-1 //不影响进位标志CF
  • NEG DST : (DST)=0-(DST) //求补指令
  • CMP DST,SRC : (DST)-(SRC),仅影响标志 //比较指令
  1. 乘法指令
  • 无符号数乘法
    MUL SRC : (AX) ←(AL)*(SRC)或(DX,AX) ←(AX)*(SRC)

  • 有符号数乘法
    IMUL SRC : (AX) ←(AL)(SRC)或(DX,AX) ←(AX)(SRC)

  1. 除法指令 //除数必须为被除数一半字长
  • 无符号数除法指令 DIV SRC
    (AL) ←(AX)/(SRC);(AH) ←(AX)%(SRC)
    或(AX)←(DX,AX)/(SRC);(DX) ←(DX,AX)%(SRC)

  • 有符号数除法指令 IDIV SRC : 操作与DIV相同

  1. 类型转换指令
  • 字节转换成字指令(有符号数)CBW
    若(AL) <80H则(AH)←0,否则(AH) ←FFH即将AL符号位扩展到AH

  • 有符号字转换成双字指令CWD
    若(AX)<8000H,则(DX) ←0,否则(DX) ←FFFFH

  1. BCD码调整指令
    加减运算非压缩BCD码高4位的值可不为0,乘除时高4位必须是0。
  • 压缩BCD码调整指令

    • DAA :对BCD码加法运算结果(AL)进行调整。
    • DAS :对BCD码减法运算结果(AL)进行调整。
  • 非压缩BCD码调整

    • AAA :对非压缩BCD码加法运算结果进行调整,进位送(AH)中
    • AAS :对非压缩BCD码减法运算结果进行调整
    • AAM :对非压缩BCD码乘法运算进行调整
    • AAD :对非压缩BCD码除法运算进行调整

逻辑指令

  1. 逻辑运算指令
  • AND DST,SRC (DST) ←(DST)&(SRC)
  • OR DST,SRC (DST) ←(DST)|(SRC)
  • NOT DST ~DST
  • XOR DST,SRC (DST) ←(DST)^(SRC)//异或
  • TEST DST,SRC (DST)&(SRC),仅影响标志
  1. 移位指令
  • 逻辑左移指令 SHL DST,count :DST左移count位,每左移一位,最低位补0,最高位进入CF
    • count可以为数字,也可以为CL做移位计数。
  • 算术左移指令 SAL DST,count :同SHL
  • 逻辑右移指令 SHR DST,count :最高位添零,最低位进入CF
  • 算术右移指令 SAR DST,count :最高位不变,最低位进入CF
  • 循环左移指令 ROL DST,count :最高位进入CF和最低位
  • 循环右移指令 ROR DST,count :最低位进入CF和最高位
  • 带进位循环左移指令 RCL DST,count
  • 带进位循环右移指令 RCR DST,count

串处理指令

  1. 数据串传送指令:唯一的目的操作数和源操作数都在存储器中的指令
  • 串传送指令 MOVSB/MOVSW :DST与SRC做类型检查

    • MOVSB : ((ES:DI)) ←((DS:SI)),(SI) ←(SI)±1, (DI)←(DI)±1
    • MOVSW :((ES:DI)) ←((DS:SI)),(SI) ←(SI)±2, (DI) ←(DI)±2
      其中,加、减地址指针SI和DI由FLAG中的DF决定,DF=0地址增加,DF=1地址减小。
  • 建立方向标志指令

    • CLD ;DF←0
    • STD ;DF←1
  • REP重复前缀
    例:REP MOVSB :以CX寄存器做计数器,每传送一个数(CX)减1,直到(CX)为0。
    REPZ/REPE : 若(CX)≠0且ZF=1时继续执行,否则退出。
    REPNZ/REPNE : 若(CX)≠0且ZF=0(比较不相等)时继续执行,否则退出。

  • 存入串指令 STOSB/STOSW : DST做类型检查

    • STOSB : ((ES:DI)) ←(AL), (DI) ←(DI)±1
    • STOSW : ((ES:DI)) ←(AX),(DI) ←(DI)±2
      由DF决定方向,可加入前缀REP。
  • 从串中取指令 LODSB/LODSW :SRC做类型检查

    • LODSB : (AL) ←((DS:SI)) , (SI) ←(SI)±1
    • LODSW : (AX) ←((DS:SI)) ,(SI) ←(SI)±2
      地址增减由DF决定
  1. 字符串扫描和比较指令
  • 串比较指令 CMPS : SRC和DST仅做类型检查

    • CMPSB ;((DS:SI))-((ES:DI)), (SI) ←(SI)±1, (DI) ←(DI)±1
    • CMPSW ;((DS:SI))-((ES:DI)), (SI) ←(SI)±2, (DI) ←(DI)±2
      串比较仅影响标志,地址增减由DF决定。
  • 串扫描指令 SCAS : DST做类型检查

    • SCASB : (AL)-((ES:DI)) ,(DI) ←(DI)±1
    • SCASW : (AX)-((ES:DI)) ,(DI) ←(DI)±2
      仅影响标志,地址增减由DF决定,可加条件前缀。

控制转移指令

  1. 无条件转移指令:JMP TARGET
  • JMP short_label :(IP)<-(IP)+short_label 短跳转
  • JMP near_label :(IP)<-(IP)+near_label 近跳转
  • JMP far_label :(CS:IP)<-far_label 远跳转
  1. 条件转移指令
  • 根据单个标志转移
指令 含义 测试条件
JZ short_label 结果为0转移 ZF=1
JE short_label 结果相等转移 ZF=1
JNZ short_label 结果不为0则转移 ZF=0
JNE short_label 结果不相等则转移 ZF=0
JS short_label 结果为负则转移 SF=1
JNS short_label 结果非负则转移 SF=0
JNO short_label 结果不溢出则转移 OF=0
JO short_label 结果溢出则转移 OF=1
JP short_label 奇偶为1则转移 PF=1
JPE short_label 偶转移 PF=1
JNP short_label 奇偶为0则转移 PF=0
JPO short_label 奇转移 PF=0
JB short_label 有借位转移 CF=1
JNAE short_label 不大于等于转移 CF=1
JC short_label 有进位转移 CF=1
JNB short_label 无借位转移 CF=0
JAE short_label 大于等于转移 CF=0
JNC short_label 无进位转移 CF=0
  • 两个无符号数比较转移
A大于 B小于 E等于
JB/JNAE/JC CF=1 小于
JNB/JAE/JNC CF=0 不小于
JBE/JNA CF|ZF=1 不大于
JNBE/JA CF|ZF=0 大于
  • 两个有符号数比较转移
G大于 L小于 E等于
JL/JNGE SF^OF=1 小于
JNL/JGE SF^OF=0 不小于
JNLE/JG (SF^OF)|ZF=0 大于
JLE /JNG (SF^OF)|ZF=1 不大于
  • 测试CX值,为0则转移
    JCXZ short_label :(CX)=0则转移
  1. 循环指令
  • LOOP short_label : (CX) ←(CX)-1,(CX)≠0则转移
  • LOOPZ/LOOPE short_label : (CX) ←(CX)-1,(CX)≠0且ZF=1则转移
    LOOPNZ/LOOPNE short_label :(CX) ←(CX)-1,(CX)≠0且ZF=0则转移
  1. 子程序调用与返回
  • 子程序调用指令 CALL TARGET
    具体指令
    CALL near_proc;段内调用
    CALL far_proc;段间调用
    CALL mem16/regp16/mem32;

  • 返回指令 RET

  • 带立即数返回 RET IMM16
    在RET指令的基础上,当从堆栈中弹出IP和CS后,再将SP加上一个字的立即数,使得返回后(SP) ← (SP) + IMM16

中断调用与返回

  1. 中断调用
  • INT n
    依次将FLAG,当前CS和IP(即断点地址)放入堆栈,清除IF和TF。执行中断类型码为n的中断服务程序。
    注: INT n 的机器码为 CDH n,INT 3 的机器码特殊,为 CCH

  • INTO
    在有符号数运算结束以后,可以使用INTO,若OF=1,则执行中断指令INT 4,否则无操作。

  • IRET
    中断返回指令,从中断程序返回主程序,恢复断点和FLAG

控制类指令

  1. 标志处理指令
  • CLC/STC/CMC 对CF 清0 / 置位 /取反
  • CLD/STD 对DF 清0 / 置位
  • CLI/STI 对IF 清0 / 置位
  1. 处理器控制指令
NOP 空操作指令 占用一个字节的机器码,不执行任何操作
HLT (Halt)停机指令 该指令使处理器处于停机状态,以便等待一次外部中断到来
WAIT 等待指令 该指令使处理器处于空转状态,也可用来等待外部中断的到来
ESC (Escape)换码指令,用作前缀 格式:ESC MEM,其中MEM指出一个存储单元,ESC指令把该存储单元的内容送到数据总线去
LOCK 封锁指令,用作前缀 该指令与其他指令联合,用来维持总线的封锁信号直到与其联合的指令执行完为止

推荐阅读更多精彩内容