8086指令系统学习


学习指令关注:

  • 指令的汇编格式
  • 指令基本功能
  • 指令支持的寻址方式
  • 指令执行对标志位的影响
  • 指令的特殊要求

数据传送类指令

  • 通用数据传送指令:MOV、XCHG、PUSHPOP
  • 累加器专用传送指令:IN、OUT、XLAX
  • 地址传送指令:LEA、LDS、LES
  • 标志寄存器传送指令:LAHF、SAHF、PUSHF、POPF
  • 符号扩展指令:CBWCWD

除了SAHF和POPF指令外,均不影响标志位

通用数据传送指令MOV

格式:MOV DST,SRC;(DST)<--(SRC)

数据传输规则

数据传输规则

非法指令主要现象:

  • 两个操作数的类型不一致,或者不确定;
    • MOV [BX][SI],1;两个操作数类型不明确
    • MOV BP,AL;两操作数类型不一样
  • CS不能作为目的操作数(不能显示地修改),DX不能作为存储器寻址的寄存器
  • 传送方向错误

后续的双操作数指令一般也是这样规定指令的

数据交换指令XCHG(exchange)

格式:XCHG OPR1,OPR2;(OPR1)<-->(OPR2) 两操作数值交换

注意:

  • 遵守数据传输规则
  • 两个操作数都不能使用段寄存器和IP,也不能使用立即数

换码指令XLAT(查表指令)

格式:XLATXLAT OPR;(DS:[BX+AL])->AL (OPR是为了提高可读性)

可用于将一种代码转换为另外一种代码

使用方法:

  • 先在数据段中建立一张字节表格(长度不超过256,即2^8),表格的内容是要换取的代码
  • 表格的首地址送寄存器BX
  • 要换取的对应编码相对于表格首地址的位移量送寄存器AL
  • 执行XLAT,AL中即为转换后的编码

堆栈操作

堆栈是主存中一块连续的存储区域,常用于数据的暂存、交换、子程序的参数传递等场合。

堆栈操作按照后进先出原则。

  • 在8086系统里,堆栈所在的段为堆栈段,最大空间为64KB。
    • 段地址由SS寄存器指示
    • SP始终指示栈顶单元
  • 8086系统从较大地址开始分配和使用(其他段地址从小地址开始)
SSEG SEGMENT STACK;堆栈段开始
	DW 100 DUP(?) ;大小为100字
SSEG ENDS		  ;堆栈段结束

程序装入时,操作系统将SSEG的段基址置入SS,堆栈段的字节置入SP,即200(0C8H)

如果未定义堆栈段,用户程序装入内存时:

ES,DS指向PSP(Program Segment Prefix 程序段前缀区);SS指向用户程序区;CS指向用户代码段;(SP)=0000H指向64KB存储器尾部

对于8086系统堆栈操作:

  • 进栈操作:PUSH SRC

    • 执行:(SP) <- (SP)-2; ((SP)+1,(SP)) <- (SRC);
  • 出栈出栈:POP DST

    • 执行:(DST) <- ((SP)+1,(SP)); (SP) <- (SP)+2;

注意:

  • 对于8086系统堆栈操作只支持字为单位的操作
  • 不支持立即寻址
  • CS不能作为目的操作数

地址传送指令

  • 有效地址送寄存器指令:

    LEZ REG, SRC; (REG) <- SRC

  • 指针送寄存器和DS指令

    LDS REG,SRC; (REG) <-(SRC), (DS) <- (SRC+2)

    取两个字分别送往寄存器和DS

  • 指针送寄存器和ES指令

    LES REG, SRC; (REG) <- (SRC), (ES) <- (SRC+2)

注意:

  • REG不能为段寄存器
  • SRC必须为存储器寻址方式

LEA与MOV区别

标志寄存器传送指令

操作数都隐藏

  1. 标志送AH指令:LAHF ; (AH) <- (FLAGS低字节)

  2. AH送标志寄存器指令:SAHF; (FLAGS低字节) <- (AH)

  3. 标志进栈指令:PUSHF; (SP) <- (SP)-2, ((SP)+1, (SP)) <- (FLAGS)

  4. 标志出栈指令:POPF; (FLAGS)<- ((SP)+1,(SP)) , (SP)<-(SP)+2

POPF,PUSHF可用于子程序中,分别用来恢复主程序标志与保存主程序标志

类型转换指令(符号位扩展指令)

  • CBW; (AL)->AX 将字节扩展为字
  • CWD; (AX)->(DX,AX) 将字扩展为双字

操作数隐含,扩展为符号位扩展。

若(AX) = BA45H

CWD; (DX)=FFFFH,(AX)=BA45H

CBW; (AX)=0045H


关于无符号扩展,只要将高半部分清0即可,可以通过MOV来实现

算法运算类指令

加法指令

  • 加法指令:ADD DST,SRC ;(DST)<-(DST)+(SRC)
  • 带进位加法:ADC DST,SRC ;(DST)<-(DST)+(SRC)+CF
  • 加1指令:INC OPR

注意:

  • 加法指令影响状态标志位,但INC指令不影响CF标志位
  • 支持的操作数类型和MOV同,但操作数不能为段寄存器

减法指令

  • 减法指令:SUB DST,SRC ;(DST)<-(DST)-(SRC)
  • 带借位减法:SBB DST,SRC ;(DST)<-(DST)-(SRC)-CF
  • 减一指令:DEC OPR ;(OPR)<-(OPR)-1
  • 求补指令:NEG OPR ;(OPR)<-0-(OPR)
  • 比较指令:CMP OPR1,OPR2 ;(OPR1)-(OPR2)

注意:

  • 减法指令影响状态标志位,但DEC指令不影响CF标志位
  • 减法指令对标志位的影响和加法指令不同。详细看

XYZW均为已定义的双字数据,用指令序列实现:

W<-X+Y+24-Z

DATA SEGMENT
	X DD 778899AAH
	Y DD 9ABCDEF0H
	Z DD 56789ABCH
	W DD ?
DATA ENDS
CODE SEGMRNTma
	ASSUME CS:CODE,DS:DATA
START:MOV AX,DATA
	  MOV DS,AX
	  MOV AX,WORD PTR X
	  MOV DX,WORD PTR X+2
	  ADD AX,WORD PTR Y  ;X+Y低字部分
	  ADC DX,WORD PTR Y+2;X+Y高字部分
	  ADD AX,24
	  ADC DX,0
	  SUB AX,WORD PTR Z
	  SBB DX,WORD PTR Z+2
	  MOV WORD PTR W,AX
	  MOV WORD PTR W+2,DX ;结构存入W

乘法指令

  • 无符号数乘法指令:MUL SRC
  • 有符号数乘法指令:IMUL SRC

执行操作:

(根据SRC类型判断执行哪种操作,结果为双倍字长)

  • 字节操作:(AX)<-(AL)X(SRC)
  • 字操作:(DX,AX)<-(AX)x(SRC)

注意:

  • SRC若为存储器操作数时,注意ptr明确类型;SRC不能为立即数和段寄存器

  • 除了CF与OF外,对其他标志位没有定义(执行后标志是任意的,不可预测)

  • 乘法指令对CF/OF的影响:(高半位有无有效数字)

    MUL指令:\(CF,OF=\left\{\begin{array}{rcl}00 &乘积的高一半为0\\11&否则\end{array}\right.\)

    IMUL指令:\(CF,OF=\left\{\begin{array}{rcl}00 &乘积的高一半是低一半的符号扩展\\11&否则\end{array}\right.\)

除法运算

  • 无符号数除法运算:DIV SRC
  • 有符号数除法运算:IDIV SRC

执行操作:(被除数是除数的双倍)

  • 字节操作:

    (AL)<-(AX)/(SRC)的商

    (AH)<-(AX)/(SRC)的余数

  • 字操作

    (AX)<-(DX,AX)/(SRC)的商

    (DX)<-(DX,AX)/(SRC)的余数

注意:

  • SRC若为存储器操作数时,注意ptr明确类型;SRC不能为立即数
  • 对所有的状态标志位均无定义
  • 两N位数相除,应首先把被除数符号扩展为2N位

位运算类指令

逻辑运算指令

  • 非:NOT OPR
  • 与:AND DST,SRC
  • 或:OR DST,SRC
  • 异或:XOR DST,SRC
  • 测试:TEST OPR1,OPR2 ;(OPR1)与(OPR2)

注意:

  • NOT指令不影响标志位;除了NOT外,其他均影响
  • CF,OF标志位清0;SF,PF,ZF根据运算结果的特征设置;AF无定义

应用:

  • OR:有选择地使操作数置1

  • AND:有选择地清0

  • TEST:位测试,与条件转移指令一起完成对特定位的判断,实现相应的程序转移

    判断偶数:

    TEST AL,1 ;若为0则为偶数,则ZF=1
    JZ EVEN
    
  • XOR:

    • 有选择地取反(和1异或取反,和0异或不变)
    • 寄存器清0(与自身进行逻辑异或,且执行速度快)

移位指令

  • 逻辑左移:SHL OPR,CNT

    CF<-左 右<-0

  • 逻辑右移:SHR OPR,CNT

    0->左 右->CF

  • 算术左移:SAL OPR,CNT

    CF<-左 右<-0

  • 算术右移:SAR OPR,CNT

    左->左 右->CF

  • 循环左移:ROL OPR,CNT

    CF<-左 右<-左

  • 循环右移:ROR OPR,CNT

    右->左 右->CF

  • 带进位循环左移:RCL OPR,CNT

    CF<-左 右<-CF(初始)

  • 带进位循环右移:RCR OPR,CNT

    CF(初始)->左 右->CF

操作数:

  • OPR可用除立即数以外的任何寻址方式
  • \(\left\{\begin{array}{rcl}CNT=1,&SHL&OPR,1\\CNT>1,&MOV&CL,CNT\\&SHL&OPR,CL\end{array}\right.\)

状态标志位:

  • CF=移除的值

  • \(OF=\left\{\begin{array}{rcl}1&CNT=1时,最高有效位的值发生变化\\0&CNT=1时,最高有效位的值不变\end{array} \right.\)

    当CNT>1时,OF不确定

  • 除此之外,移位指令SF、ZF、PF根据移位结果设置,AF无定义

  • 循环移位指令:不影响SF、ZF、PF、AF

用移位指令实现:AX<-(AX)x10

SHL AX,1
MOV BX,AX
SHL AX,1   ;AX<-4(原AX)
SHL AX,1   ;AX<-8(原AX)
ADD AX,BX  ;AX<-(8AX)+(2AX)

将DX,AX中32位数值左移一维

SHL AX,1
RCL DX,1

表达式计算(应用)

X、Y、Z、V、W均为16位有符号数,计算W<-(V-(X*Y+Z-1234))/X

MOV AX,X
IMUL Y    ;X*Y
MOV CX,AX 
MOV BX,DX ;(BX,CX)为X*Y
MOV AX,Z
CWD       ;(DX,AX)为Z
ADD CX,AX
ADC BX,DX ;(BX,CX)为X*Y+Z
SUB CX,1234
SBB BX,0  ;(BX,CX)为X*Y+Z-1234
MOV AX,V
CWD       ;(DX,AX)为V
SUB AX,CX
SBB DX,BX ;(DX,AX)为V-(X*Y+Z-1234)
IDIV X	  ;(V-(X*Y+Z-1234))/X,商在AX,余数在DX
MOV W,AX  ;保存结果

转移控制类指令

指令寻址方式(确定下一条将要执行指令地址的方法)

  1. 顺序寻址

  2. 跳转寻址:通过转移控制类指令实现(主要是改变CS:IP的值)

    如何确定转移控制类指令的转向地址?

    • 直接寻址(用标号表达)

      指令代码中直接给出地址差(目标地址相对于当前ip的位移量),将要转移到的目标地址就是当前IP值加上地址差。

    • 间接寻址方式(用存储器或存储器操作数表达)

      代码中指示寄存器或存储单元,目标地址从中获得

根据跳转范围不同,采用不同的转移方式:

  • 段内寻址

    • 近转移(near)

      • 在当前代码64kB范围内注意

      • 不需要修改CS段地址,只要改变IP偏移地址

    • 短转移(short)

      • 转移范围可以用一个字
  • 段间寻址

    远转移(far)

    • 在1MB范围内
    • 需要更改CS段地址和IP偏移地址
    • 目标地址必须用一个32位数表达,即逻辑地址

实际编程过程中,汇编程序会选择处理转移方式,也可以人为规定。

无条件转移指令

JMP OPR; 程序无条件转向OPR指令的目标地址开始执行指令

JMP 指令支持段内、段间转移:

  1. 段内转移

    JMP 标号

    • IP<-(IP)+标号(IP值的偏移量)

    • (CS)不变

  2. 段间转移

    JMP FAR PTR 标号

    • (IP)<-标号转移地址
    • (CS)<-标号段地址

条件转移指令

有二十多个,将Jcc当做条件转移指令的一个统称:

JCC label;条件满足,发生转移

  • 若转移:IP<-IP+8位位移量;否则顺序执行

  • 只支持短转移

  • 不影响标志位,但要利用标志位

根据利用的标志位不同,分为4种情况:

  1. 根据单个条件标志的设置情况转移

    测试条件
    JZ(JE) ZF=1
    JNZ(JNE) ZF=0
    JS SF=1
    JNS SF=0
    JO OF=1
    JNO OF=0
    JP PF=1
    JNP PF=0
    JC CF=1
    JNC CF=0
  2. 测试CX的值为0则转移

    JCXZ OPR ;(CX)=0

  3. 比较两个无符号数,根据比较结果转移

    指令 转移条件 说明
    JA/JNBE OPR CF=0且ZF=0 X>Y时,转移
    JAE/JNB OPR CF=0或ZF=1 X>=Y时,转移
    JNAE/JBOPR CF=1且ZF=0 X<Y时,转移
    JNA/JBE OPR CF=1或ZF=1 X<=Y时,转移
  4. 比较两个有符号数,根据比较结果转移

    指令 转移条件 说明
    JG/JNLE OPR SF=OF且ZF=0 X>Y时,转移
    JGE/JNL OPR SF=OF或ZF=1 X>=Y时,转移
    JNGE/JL OPR SF!=OF且ZF=0 X<Y时,转移
    JNG/JLE OPR SF!=OF或ZF=1 X<=Y时,转移

循环类指令

  • 循环指令:

    LOOP OPR ;测试条件:(CX)!=0

  • 为0(相等)循环指令:

    LOOPZ(LOOPE) OPR ;测试条件:ZF=1且(CX)!=0

  • 不为零(不相等)循环指令:

    LOOPNZ/LOOPNE OPR ;测试条件:ZF=0且(CX)!=0

执行步骤:

  1. (CX)<-(CX)-1
  2. 检测是否满足测试条件,如果满足则(IP)<-(IP)+8位位移量,循环;不满足则退出循环,顺序执行。

注意:

  • CX为隐含计数器,存放循环次数

  • 只支持短转移

  • 使用LOOPZ/LOOPE,LOONZ/LOOPNE指令来控制循环时,既有计数(CX)控制又有条件(ZF)控制。有两种可能会结束循环。所以一般应用在循环结束后用条件转移指令分开这两种情况,分别处理。

	MOV CX,10
L1: ...
	...
	LOOP L1 ;L1到LOOP指令之间指令序列将重复执行10次

指令"MOV CX,10"称为"装载循环计数器",必须在循环前执行;若在循环中执行会造成死循环

计算1+2+3……+100,结果保存到SUM中

	  XOR AX,AX;累加器清0
	  MOV BX,1 ;BX<-1
	  MOV CX,100

AGAIN:ADD AX,BX
	  INC BX
	  LOOP AGAIN

	  MOV SUM,AX

子程序调用和返回指令


子程序是完成特定功能的一段程序

当主程序执行这个功能时,采用CALL调用指令转移到子程序起始处;完成子程序后,采用RET指令返回到主程序继续执行(利用堆栈保存返回地址)

子程序定义伪指令:

子程序名 PROC 属性
	... ;子程序体
子程序名 ENDP
  • 子程序名:子程序入口的序号地址,子程序名应为合法的标识符,子程序名不能与同一源程序中的标号、变量名、其他子程序名等相同
  • 属性:类型属性(NEAR(缺省),FAR)

  1. 段内调用与返回

    • 段内直接调用

      CALL 子程序名 ;NEAR属性

      操作:

      • (SP)<-(SP)-2
      • (SS:SP)<-(IP)
      • (IP)<-子程序入口偏移地址
    • 段内返回

      RET ;按NEAR属性返回

      操作:

      • (IP)<-(SS:SP) ;从堆栈中取出返回地址
      • (SP)<-(SP)+2
    • 带参数返回

      RET n ;带参数返回

      操作:

      • (IP)<-(SS:SP) ;从堆栈中取出返回地址
      • (SP)<-(SP)+2+n;调整栈顶位置,回到之前的值

  2. 段间调用与返回

    • 段间调用

      CALL 子程序名

      操作:

      • (SP)<-(SP)-2
      • (SS:SP)<-(CS) ;入栈
      • (SP)<-(SP)-2
      • (SS:SP)<-(IP) ;入栈
      • (IP)<-子程序入口的偏移地址
      • (CS)<-子程序入口的段地址
    • 段间返回

      RET ;按FAR属性返回

      • (IP)<-(SS:SP)
      • (SP)<-(SP)+2
      • (CS)<-(SS:SP)
      • (SP)<-(SP)+2
ZEROBYTES PROC
	PUSH AX
	PUSH CX		;保护现场
	XOR AX,AX	;AX清0
	MOV CX,128	;循环次数CX
ZEROLOOP: MOV [BX],AX ;将BX所对应的地址单元清0
	ADD BX,2	;修改地址
	LOOP ZEROLOOP
	POP CX		;恢复现场
	POP AX
ZEROBYTES ENDP

中断与中断返回指令

中断指令有三条:INT、IRET、INTO

8086CPU支持256个中断,每个中断用一个8位二进制编码标识(即中断类型码,也称中断向量号

中断向量:中断服务程序的入口地址(首地址),为含有段地址CS和偏移地址IP的32位逻辑地址。

中断向量与中断向量号的区别?

与子程序不同,中断指令程序不能用中断程序名标识中断地址,因为中断有随机性。

中断指令是统一管理的。

8086系统从物理地址0000H开始集中存放个中断向量。

  • 按照中断类型码从小到大的顺序依次存放
  • 每个中断向量占4个字节(32位),采用小端方式存储,其中高字为段地址,低字为偏移地址
  • 256个中断占1KB区域(256 * 4=210 字节)即中断向量表
  • 类型码为N的中断向量存放的物理地址为4N

中断指令:INT n

执行操作:

(SP)<-(SP)-2
((SP)+1,(SP))<-(FLAGS)
(SP)<-(SP)-2
((SP)+1,(SP))<-(CS)
(SP)<-(SP)-2
((SP)+1,(SP))<-(IP)
(IP)<-(n*4)
(CS)<-(n*4+2)

中断返回指令:IRET

执行操作:

(IP)<-((SP)+1,(SP))
(SP)<-(SP)+2
(CS)<-((SP)+1,(SP))
(SP)<-(SP)+2
(FLAGS)<-((SP)+1,(SP))
(SP)<-(SP)+2

注意:

  • n(0~255)是中断类型。由于类型码为N的中断向量存放的物理地址为4N,因而能找到它在中断向量表对应的中断向量,即段地址:偏移地址
  • INT会清零IF和TF,但不影响其他标准位
  • IRET影响标志位由堆栈中取出的值确定

一个指令:INT proc ;proc为23H

如何手动存储CS:IP值?

XOR AX,AX ;AX清零
MOV DS,AX
MOV SI,34H*4 ;DS:SI = 0:34H*4 该中断类型的逻辑地址
MOV WORD PTR [SI],offset proc
MOV WORD PTR [SI+2],SEG

溢出中断指令INTO

功能: 检测OF标志位

  • OF=1时产生中断类型为4的中断
  • OF=0时不起作用

指令完成操作(中断类型码为4):

  1. 标志寄存器入栈
  2. 断点地址入栈,CS先入,然后IP入
  3. 从中断向量表中获取中断服务程序入口地址(IP<-(0:11H,0:10H) CS<-(0:12H,0:13H)

处理机控制指令

用于修改标志寄存器的标志位或控制CPU的动作

  1. 标志位操作指令完成标志位的复位,置位等操作
  2. 外部同步指令用于控制CPU,不影响标志位
标志位操作指令格式 操作
STC CF<-1
CLC CF<-0
CMC CF取反
STD DF<-1
CLD DF<-0
STI IF<-1,开中断
CLI IF<-0,关中断

外部同步指令:

  1. 处理器暂停指令HLT:使处理器处于暂停,只有复位信号(RESET)、外部中断请求(NMI、INTR)可使其退出;常用于等待中断或多处理机的同步操作
  2. 处理机等待指令WAIT:处理检测\(\overline{\text{TEST}}\) 引脚信号。\(\overline{\text{TEST}}\) 为高电平时处理器空转;\(\overline{\text{TEST}}\) 为低电平时,处理器退出中转,执行后续操作
  3. 空操作NOP:占一个指令周期,用于调整延时


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM