第二章:8086/8088的指令系统(二)
注意: 本节都是比较难理解的指令
串操作指令
- 简介
- 计算机在处理数据时,经常要对一组数据进行处理,这样的一组数据称为数据串
- 由字节组成的数据串称为字节串;同理由字组成的数据串最长可达64KB。
- 针对数据块或者字符串的操作。
- 可实现存储器(内存)到存储器(内存)的数据传送
- 8086/8088指令系统中有专门的串操作指令,可以对数据串进行多种操作,但所有串操作指令必须遵循一些基本的规则。
- 无论是字节串还是字串,所处理数据的个数都存放在CX中,在有串前缀的前提下,每执行一次操作CX自动减1,直至减到0,串操作自动停止; 如果没有串前缀,需要有指令设置并判断CX。
- 串操作指令的源操作数src和目的操作数dest都在内存中,是唯一一条从内存到内存的指令。串所在的区域及首地址:
- 源串一般存放在数据段,偏移地址由SI指定,即DS:[SI],支持段超越
- 目的串必须在附加段,偏移地址有DI指定,即ES:[DI]
- 在串操作前要首先设置方向标志位DF。
- 当DF = 1,指示源和目的操作数位置的偏移地址(SI)和(DI)自动由高至低,减量进行串操作,当串为字节串时,每操作一次,(SI)和(DI)减1,当串为字串时,每操作一次,(SI)和(DI)减2;
- 当DF = 0时,指示源和目的操作数位置的偏移地址(SI)和(DI)自动由低至高,增量进行串操作,当串为字节串时,每操作一次,(SI)和(DI)加1,当串为字串时,每操作一次,(SI)和(DI)加2
- 串前缀:(重复前缀)
- 无条件重复
REP
- 当
CX != 0
时,REP
后的指令将继续重复执行 - 常用于传送类指令前:未传完则继续传送
- 条件重复
- 相等(相减为零)重复:
REPE(REPZ)
1.CX != 0 && ZF == 1
,则前缀后的指令将继续重复执行。 - 不相等(相减不为零)重复:
REPNE(REPNZ)
CX != 0 && ZF == 0
,则前缀后的指令将继续重复执行。
- 条件前缀常用于运算类指令前,两个数的比较
- 相等(相减为零)重复:
- 无条件重复
- 串操作指令实际流程
- 取源串地址
- 取目标串地址
- 设串长度
- 设操作方向
- 完成一个字节或字操作
- 修改地址指针
- 修改串长度值
- 判断是否完成
- 没完成回到第5步
- 完成结束
串传送指令
- 格式:
MOVSB ;字节传送 MOVSW ;字传送
- 指令功能:
- 将位于DS段,由(SI)所指出的存储单元的字节或字数据传送到位于ES段,由(DI)所指的存储单元中,即DS:[SI]->ES:[DI],若DF=1,(DI)-n->(DI),(SI)-n->(SI);若DF = 0,(DI)+n->(DI),(SI)+n->(SI).
- 其中,当使用指令MOVSW时,n=1;使用指令MOVSW时,n=2。
- 串传送指令常于无条件重复前缀连用
串比较指令
- 格式:
CMPSB;字节比较 CMPSW ;字比较
- 指令功能:(目标串-源串,结果丢弃)
- 将位于DS段由(SI)所指出的存储单元的字节或字数据与ES段由(DI)所指的字节或字数据相比较,比较结果仅影响标志位。
- 通过串前缀REPZ的控制,可以在两个数据串中寻找第一个不相等的字节或字数据;
- 通过串前缀PEPNZ的控制,可以在两个数据串中寻找一个相等的字节或字数据。
串检索指令
- 格式:
SCASB;字节 SCASW ;字
- 功能:
- 将AL或AX中的值与位于ES段由(DI)所指出的存储单元中的字节或字数据进行比较,比较结果仅影响标志位
- 通过串前缀REPZ的控制,可以在数据串中寻找第一个与AL或AX不相等的字节或字数据;
- 通过串前缀REPBZ的控制,可以在数据串中寻找第一个与AL或AX相等的字节或字数据;
- 比较之后自动按照串操作指令的规则修改操作数地址指针。即(AL)-ES: [DI]或(AX)-ES:[DI+1][DI],若DF = 1,(DI)-n->(DI);若DF = 0,(DI)+n->(DI),其中,字是n = 2,字节n = 1;
读数据串指令
- 格式:
LODSB;字节 LODSW ;字
- 功能:
- 将位于DS段由(SI)所指出的存储单元的字节或者字数据传送至(AL)或(AX),并自动按照串操作指令的规则修改操作数地址指针。
- 即: DS:[SI]->(AL)或 DS:[SI+1][SI]->(AX),若DF = 1,(SI)-n ->(SI); 若DF = 0,(SI)+n -> (SI) ; n 同上
写数据串指令
- 格式:
STOSB;字节 STOSW ;字
- 指令功能:
- 将AL或AX中的字节或字数据写入位于ES段由(DI)所指出的存储单元中,并自动按照串操作指令的规则修改操作数地址指针。
- 即 (AL)->ES:[DI] 或 (AX)->ES:[DI+1][DI],若DF=1,(DI)-n->(DI);若DF=0,(DI)+n->(DI).
程序控制类指令
- 简介:
- 指令存储在内存的代码段,8086、8088执行的指令地址是由代码寄存器CS和指令指针IP的内容确定的,CPU运行码段CS:IP所指向的那条指令。
- 一般情况下,CPU在执行完当前指令后会自动顺序执行下一条指令,此时,下一条指令的偏移地址IP是由控制器自动给出的。
- 控制转移类指令用来改变程序的正常执行顺序,这种改变是通过改变代码段的段基址CS和偏移地址IP的内容而实现的。
- 转移分为段内转移和段间转移两类。
- 段内转移,转移的目标地址与当前地址在同一个代码段内,即只需要改变指令指针IP的内容就可实现转移,而不用改变CS的值。转移的范围在64KB之内,即偏移地址IP的范围。也就是说转移的相对偏移量为16位二进制数,取值范围为-32768~32767
- 段间转移,转移的目标地址与当前地址不在同一个代码段内,需要同时改变CS和IP的内容才可寻址到新的指令地址。
- 转移的方式分为直接转移和间接转移两类
- 直接转移:在指令操作数中直接给出转移的目标地址(一般用标号的形式)。
- 间接转移: 转移的目标地址存放在寄存器或内存单元中。
- 注意: 所有的转移类指令均不影响状态标志位。
- 跳转或者转移的目标地址距离当前的正常指令的地址偏移量称为相对偏移地址
- 程序控制类指令的本质是:
- 控制程序的方向
- 决定程序执行方向的因素
- CS/IP
- 修改IP,会使程序改变在当前代码段中的执行顺序
- 同时修改CS和IP,会使程序走向另一个代码段执行
- 程序控制类指令以“隐含”的方式修改CS和IP,以实现控制程序走向的目的(Intel指令集不允许由指令直接修改CS和IP)
- 通过修改IP或CS和IP,实现程序的三种基本控制结构
- 顺序,选择(分支),循环
- 学习程序控制类指令需要重点关注:
- 如何实现对CS和IP的修改?
- 程序控制类指令类型:
- 转移指令
- 循环指令
- 过程调用
- 中断控制
转移指令
- 通过修改指令的偏移地址或段基地址+偏移地址实现程序转移。
- 分为2小类
- 无条件转移类指令
- 无条件转移到目标地址
- 条件转移类指令
- 一定条件才会转移(条件通常指状态标志位)
- 无条件转移类指令
- 无条件转移指令
- 无条件段内直接转移指令
- 指令格式:
JMP 目标地址标号
- 指令功能:代码段的基地址CS不变,偏移地址IP由当前地址变成目标指令处的偏移地址,从而实现程序的转移跳转
- 尽管改指令的操作数是语句标号或指令标号,但实际上的操作数是相对偏移量,即编译程序首先根据目标地址计算出距离当前指令的相对偏移量,然后将这个相对偏移量放在操作码后,所以改指令执行的操作是: (IP)+相对偏移量 -> (IP).
- 如果相对偏移量是8位二进制数的范围(-128~127),则该指令为二字节指令,即1字节为操作码0EBH和1字节操作数;如果相对偏移量是16位二进制数的范围(-32768~32767),则该指令为三字节指令,即1字节的操作码0E9H和2字节的操作数
- 注意: JMP指令的相对偏移量是有编译程序自动计算的,用户只需要把目标地址的标号写在程序中就可以了。
-
举例:
假设目标地址标号为LABLE,位于码段的2300H处,指令JMP LABLE 位于码段的2308H处,执行该指令后偏移地址IP的值是多少? 相对偏移量是多少? JMP LABLE 为段内直接转移指令,执行后(IP) = 2300H; 由于2300H距离2308H的相对偏移量不足1个字节的范围,故该指令是2个字节指令,按正常顺序执行JMP LABLE 后的IP 值应为(IP) = 230AH,故2者的相对偏移量是-10,即为1字节补码0F6H,通过符号扩展为0FFF6H,因此,(IP)+相对偏移量 = 230AH+ FFF6H = 2300H ->新(IP).
- 指令格式:
- 无条件段内间接转移指令
- 格式:
JMP dest
- 指令功能:码段的基地址CS不变,偏移地址IP由当前地址变成由寄存器或存储器寻址的目标偏移地址,从而实现程序的转移跳转。
- 其中dest是寄存器或存储器操作数。
- 格式:
- 无条件段间直接转移指令。
- 格式:
JMP 目标地址处标号(是远标号)
- 码段的基址CS变成目标地址处的段基址,偏移地址变成目标地址处的偏移地址,从而实现程序的跨段的转移跳转。
- 注意:该指令不计算相对偏移量,直接将目标地址的段属性和偏移地址属性赋值给CS和IP即可。
- 格式:
- 无条件段间间接转移指令
- 格式:
JMP dest
- 指令功能:目标地址的段基址和偏移地址存放于存储器的4个连续地址中,其中前2个字节为偏移地址,后2个字节为段基址,在指令中给出的是存放目标地址的4个连续字节的首地址的偏移地址。
- 注意: dest 只能有内存储器给出了,不能有寄存器给出了。
- 格式:
- 无条件段内直接转移指令
- 条件转移指令
- 8086、8088有18条条件转移指令,均是根据CPU的状态标志位的状态作为判断是否转移的依据。如果满足指令只给你所要求的条件,则产生转移,否则将继续向下执行后面的指令
- 所有条件转移指令具备以下特点:
- 所有条件转移指令都是相对转移的形式,其中转移范围在1个字节范围之内。
- 比较两数据的关系时,例如2个数是否相等、大于、小于,要区分数据是有符号数或无符号数,8086、8088对这两类型的数据各有一组比较指令。
- 有3小类
- 判断单一标志位置位转移指令
- 格式:
Jx rel
- 指令功能: 状态标志位x为1转移,其中rel是1字节的补码,在实际使用中常常用语句标号代替。如果满足转移条件,(IP)+rel -> (IP)
- 其中,状态标志位x可以是C(CF)/Z或E(ZF)/P(PE)/S(SF)和O(OF)
- 举例:
- JZ NNN : 如果ZF = 1,执行NNN标号处的语句。
- 格式:
- 判断单一标志位复位转移指令
- 格式:
JNx rel
- 判断条件与置位相反,即x的状态为为0时跳转。
- 格式:
- 多标志位综合判断指令
- 这类指令主要是比较2个数的关系,分为有符号数的比较和无符号数的比较两组指令,如下图:(看课本99页表3-2)
- 判断单一标志位置位转移指令
循环指令
- 有4条循环控制的指令
- 特点如下
- 循环控制指令的转移范围均在-128~127字节内
- 循环前必须将循环次数赋值给CX。
- 分别如下:
- LOOP指令
- 格式: LOOP 语句标号
- 功能:(CX)-1 ->(CX),若(CX)!= 0 ,则转移到语句标号处继续循环;否则,结束循环向下顺序执行程序
- LOOPE/LOOPZ指令:
- 格式: LOOPE 语句标号 或 LOOPZ 语句标号
- 功能:(CX)-1 ->(CX),若(CX)!= 0 且 ZF = 1 ,则转移到语句标号处继续循环;否则,结束循环向下顺序执行程序
- 注意: CX是否为0并不影响标志位ZF,ZF是否为1是由改循环控制指令前面的指令决定的。
- LOOPNE/LOOPNZ指令
- 格式: LOOPNE 语句标号 或 LOOPNZ 语句标号
- 功能:(CX)-1 ->(CX),若(CX)!= 0 且 ZF = 0 ,则转移到语句标号处继续循环;否则,结束循环向下顺序执行程序
- JCXZ 指令
- 格式: JCXZ 语句标号
- 功能: 若(CX)= 0,则转移到语句标号处;否则向下顺序执行程序。
- 该指令不对CX进行操作,且循环控制条件与LOOP指令相反。
- LOOP指令
过程调用和返回指令
- 简介
- 过程也称为子程序,是指能够完成某种独立功能的程序模块。
- 可以将一些常用的操作或计算定义为过程,供主程序调用,这样,既可以避免重复编程,同时也使程序结构清晰,便于阅读,修改
- 过程掉一共虽然也是改变了正常指令指针执行的顺序,但是与跳转指令JMP不同,CUP在运行完过程后还要返回到主程序的调用处,继续向下运行主程序的指令
- 过程如下:
- 在堆栈中保存主程序跳转处的地址
- 修改CS/IP为子过程的地址
- 执行子过程
- CS/IP恢复原来保存的值(根据第一步保存的地址)
- 继续执行主程序
- 因此,过程调用除了完成码段地址指针CS/IP的修改操作之外,还要负责将紧挨着调用指令后的下一条指令地址保存起来,以便执行完子过程后返回时对CS/IP重新进行复制,继续执行主程序未完成的指令。
- 过程调用的类型也与JMP指令一样,有段内调用和段间调用之分。段内调用时子程序与主程序位于同一个代码段,调用时只需修改偏移地址IP的值即可;段间调用对于子过程与主程序在不同的代码段,有不同的段基址,故调用时需同时修改CS和IP的值
- 段内直接过程调用指令
- 段内直接过程调用指令
- 格式: CALL 子过程名
- 指令功能: 在堆栈中保存调用语句的下一条语句的偏移地址,即(SP)-2 -> (SP),(IP)->((SP+1)(SP)),码段的基地址CS不变,偏移地址IP由当前地址变成子过程处的偏移地址,从而实现程序的调用
- 段内间接过程调用指令
- 指令格式: CALL dest
- 指令功能: 在堆栈中保存调用语句的下一条语句的偏移地址,即(SP)-2 -> (SP),(IP)->((SP+1)(SP)),码段的基地址CS不变,偏移地址IP由当前地址变成由寄存器或存储器寻址的目标偏移地址,从而实现程序的调用
- dest 是寄存器或存储器操作数,改指令为2字节指令。
- 段间直接过程调用指令
- 格式: CALL 过程名(是远过程)
- 指令功能:在堆栈中保存调用语句的下一条语句的地址,即(SP)-4 -> (SP),(IP)->((SP+1)(SP)),(CS)->((SP+3)(SP+2)),码段的基地址CS变成子过程处的段基址,偏移地址IP由当前地址变成子过程处的偏移地址,从而实现程序的调用
- 该指令为5字节指令,其中操作码1字节,操作数4字节,分别是子过程的段基址和偏移地址。
- 段间间接过程调用指令
- 格式: CALL dest
- 指令功能:在堆栈中保存调用语句的下一条语句的地址,即(SP)-4 -> (SP),(IP)->((SP+1)(SP)),(CS)->((SP+3)(SP+2)),子过程的段基址和偏移地址存放于存储器的4个连续地址中,其中前2个字节为偏移地址,为IP赋值,后2个字节为段基址,为CS赋值值,从而完成子过程的段间调用。在指令中给出的事存放目标地址的4个连续字节的首地址的偏移地址
- 过程返回指令RET
- 格式:
RET
- 指令功能: 将当前堆栈内容返回到IP(段内调用)或IP/CS(段间调用),具体是段内调用还是段间掉一共是有定义子程序的语句决定的。
- 具体执行步骤是:
- 段内调用: ((SP)+1)(SP)->(IP),(SP)+2->(SP)
- 段间调用: ((SP)+1)(SP)->(IP),(SP)+2->(SP),((SP)+1)(SP)->(CS),(SP)+2->(SP)
- 格式:
- 带立即数的返回指令
- 格式:
RET n
- 指令功能: 执行完RET指令后,(SP)+n -> (SP),其中,n为偶数
- 该指令相当于删除了堆栈中的n个字节的内容,一般这些字节存放的事主程序调用子程序时所带的参数或参数地址
- 格式:
- 段内直接过程调用指令
- 总结,以段间过程调用为例,调用过程如下:
- 将调用指令后的第一条指令地址的CS入栈;
- 将调用指令后的第一条指令地址的IP入栈;
- 将子过程的段地址赋值CS
- 将子过程的偏移地址复制IP
- 执行CS:IP,直至遇到RET指令
- 将堆栈当前内容复制IP
- 将堆栈当前内容复制CS;
- 执行CS:IP
中断控制指令
- 中断的概念
- 某种异常或者随机事件(又叫中断源)是处理器(CPU)暂时停止正在运行的程序,转去执行一段特殊处理程序,并在处理结束后返回源程序被中断处继续执行的过程。
- 中断指令
- 引起CPU产生一次中断的指令
- 中断与过程调用的区别:
- 相似点:
- 从一个正在执行的过程转向另一个过程(处理程序),并在执行完成后返回原程序继续执行。
- 区别:
- 中断是随机事件或者异常事件引起,调用是事先已在程序中安排好;
- 调用指令在指令中直接给出子程序入口地址,中断指令只给出中断向量码,入口地址则在向量码指向的内存单元中。
- 调用可以是近过程调用或者远过程调用,中断处理程序均为远过程。
- 响应中断请求不仅要保护断点地址(CS/IP),还要保护FLAGS(标志寄存器)内容
- 相似点:
- 中断指令:
- 格式:
INT n
- n: 中断类型码(n = 0~255)
- 功能:系统调用到这条指令之后首先要做一个
n*4
的运算,n*4
的意思是指向内存中的一个特殊的单元,内存的这个单元所在的区域称之为中断向量表区域,该区域从0开始一直到003FFH,共有1k个字节单元,每4个字节单元里就构成了一个中断子程序的入口地址或者称为中断向量,其中n*4/n*4+1
对应的地址为中断服务子程序入口的偏移地址,n*4+2/n*4+3
这两个单元存放的是中断子程序入口的段基地址,而且这个区域属于数据段,所以这个区域的段地址是DS的值。 - 中断指令的执行过程
- 将FLAGS压入堆栈
- 将INT指令的下一条指令的CS/IP压入栈
- 由n*4得到存放中断向量的地址
- 将中断向量(中断服务程序的入口地址)送CS和IP寄存器
- 转入中断服务子程序
- 注意:只有第5步是有程序员编写的,前4步都是有系统自己完成的。
-
如下图
- 格式:
- 中断返回指令
- 格式:
IRET
- 中断服务程序的最后一条指令,负责
- 回复断点
- 回复标志寄存器内容。
- 格式:
处理器控制类指令
- 简介
- 处理器类控制指令完成对CPU的简单控制操作,由于在指令职工已经确定了操作对象和操作过程,所以处理器控制类指令均没有操作数。
- 对CPU直接操作,比如: 修改标志寄存器、CPU暂停、CPU与外部设备同步等
- 该类指令的控制对象是CPU
-
标志位操作指令
置位:SET,对某标志位赋值1 清位: CLEAR,对某标志位赋值0 取补: COMPLEMENT,对进位标志位的当前值取反 还有如下图:
- 处理器暂停指令HLT
- 格式: HLT
- 功能: 用软件的方法使CUP处于暂停状态,等待硬件中断,硬件中断的进入,使CPU退出暂停状态,带硬件中断服务程序执行完后,CPU执行HLT后下一条指令。
- 等待指令 WAIT
- 格式: WAIT
- 功能: CPU进入等待状态,知道TEST(有上划线)引脚上的信号有效为止。
- 总线封锁指令 LOCK
- 格式;
LOCK
- 格式;
- 空操作指令
- 格式:
NOP
- 功能: 它并未使CPU完成任何有效的操作,只是每执行一次该指令要占用3个时钟周期的时间,常用来做延时。
- 格式: