1 无条件转移指令
JMP指令控制程序无条件地跳转到目的单元,使用JMP指令可有三种格式:
⑴ JMP SHORT label 短转移(short jump)
⑵ JMP NEAR PTR label 近转移(near jump)
● JMP label 直接转移(direct jump)
● JMP reg 寄存器间接转移(register indirect jump)
● JMP WORD PTR OPR 存储器间接转移(memory indirect jump)
⑶ JMP FAR PTR label 远转移(far jump)
分类
|
指 令
|
转 移 条 件
|
说 明
|
(Ⅰ)
|
JZ/JE
|
ZF=1
|
为零/相等, 则转移
|
JNZ/JNE
|
ZF=0
|
不为零/不相等, 则转移
|
|
JS
|
SF=1
|
为负, 则转移
|
|
JNS
|
SF=0
|
为正, 则转移
|
|
JO
|
OF=1
|
溢出, 则转移
|
|
JNO
|
OF=0
|
不溢出, 则转移
|
|
JP
|
PF=1
|
奇偶位为1, 则转移
|
|
JNP
|
PF=0
|
奇偶位为0, 则转移
|
|
JC
|
CF=1
|
进位位为1, 则转移
|
|
JNC
|
CF=0
|
进位位为0, 则转移
|
|
(Ⅱ)
|
JB/JNAE/JC
|
CF=1
|
低于/不高于等于, 则转移
|
JNB/JAE/JNC
|
CF=0
|
不低于/高于等于, 则转移
|
|
JBE/JNA
|
(CF ZF)=1
|
低于等于/不高于, 则转移
|
|
JNBE/JA
|
(CF ZF)=0
|
不低于等于/高于, 则转移
|
|
(Ⅲ)
|
JL/JNGE
|
(SF OF)=1
|
小于/不大于等于, 则转移
|
JNL/JGE
|
(SF OF)=0
|
不小于/大于等于, 则转移
|
|
JLE/JNG
|
((SF OF) ZF)=1
|
小于等于/不大于, 则转移
|
|
JNLE/JG
|
((SF OF) ZF)=0
|
不小于等于/大于, 则转移
|
|
(Ⅳ)
|
JCXZ
|
(CX)=0
|
CX的内容为0, 则转移
|
注: (Ⅰ)根据条件码的值转移 (Ⅱ)比较两个无符号数,根据比较的结果转移
(Ⅲ)比较两个带符号数,根据比较的结果转移 (Ⅳ)根据CX寄存器的值转移
例
1050:0000 B86610 MOV AX,1040
1050:0003 8ED8 MOV DS,AX
1050:0005 B90500 MOV CX,0005
1050:0008 BB0000 MOV BX,0000
1050:000D 0207 AGAIN: ADD AL,[BX]
1050:000F 43 INC BX
1050:0010 49 DEC CX
1050:0011 75FA JNZ 000D
1050:0013 A20500 MOV [0005],AL
1050:0016 B44C MOV AH,4C
1050:0018 CD21 INT 21
例 假设程序进行两个带符号数的比较,并根据比较结果转移,其中(AL)=80H,(BL)=01,请指出下面两组指令的转向地址。
⑴ CMP AL,BL ⑵ CMP AL,BL
JL XY JB XY
答:⑴ 转向目标地址XY;⑵不能实现转移。
执行CMP指令时,(AL)-(BL)=80-01=7F,条件码设置为:SF=0,OF=1,CF=0。执行JL指令时,测试转移条件:SFOF = 0 1 =1,说明满足(AL)<(BL)的转移条件,因此,(IP)←XY的偏移地址,程序即转移到XY单元执行新的指令。
JB指令的转移条件为CF=1,而CMP的执行结果使CF=0,所以不能引起转移。
3 循环指令
这一组指令在循环结构的程序中用来控制一段程序(称为循环体)的重复执行,在汇编指令中循环的转向地址用标号来表示,而在机器指令中给出的是位移量,所以执行循环指令时,若满足循环条件,CPU就计算转向地址:(IP)当前+8位位移量→(IP),即实现循环。
若不满足循环条件,即退出循环,程序继续顺序执行。
循环指令都是短转移格式的指令,也就是说,位移量是用8位带符号数来表示的,转向地址在相对于当前IP值的-128 ~ +127字节范围之内。
对条件循环指令LOOPZ(LOOPE)和LOOPNZ(LOOPNE),除测试CX中的循环次数外,还将ZF的值作为循环的必要条件,因此,要注意将条件循环指令紧接在形成ZF的指令之后。
在多重循环的程序结构中,如果各层循环都使用循环指令来控制,则应注意对CX中循环计数值的保存与恢复。
循环指令均不影响条件码。
LOOP label 循环(loop)
执行操作:① (CX)←(CX)-1
② 若(CX)≠0,则(IP)←(IP)当前+位移量,否则循环结束
LOOPZ/LOOPE label 为零/相等时循环(loop while zero,or equal)
执行操作:① (CX)←(CX)-1
② 若ZF=1且(CX)≠0,则(IP)←(IP)当前+位移量,否则循环结束
LOOPNZ/LOOPNE label 不为零/不等时循环(loop while nonzero,or not equal)
执行操作:① (CX)←(CX)-1
② 若ZF=0且(CX)≠0,则(IP)←(IP)当前+位移量,否则循环结束
例 编写程序,实现两个数据块BLOCK1和BLOCK2相加,结果存入BLOCK2。
DATA SEGMENT
BLOCK1 DW 100 DUP(?)
BLOCK2 DW 100 DUP(?)
DATA ENDS
; - - - - - - - - - - - - - - - - - -
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,ES:DATA
START:MOV AX,DATA
MOV DS,AX ; initialize the data segment
MOV ES,AX ; initialize the extra segment
CLD ; DF=0 for autoincrement
MOV CX,100 ; load the counter
MOV SI,OFFSET BLOCK1 ; address of block1
MOV DI,OFFSET BLOCK2 ; address of block2
NEXT: LODSW ; load the data of block1 into AX
ADD AX,ES:[DI] ; add the data of block2 to AX
STOSW ; store the sum to block2
LOOP NEXT ; repeat 100 times
MOV AX,4C00H ; return to DOS
INT 21H
CODE ENDS
END START
4 子程序调用与返回指令
子程序是一种非常重要的计算机编程结构,它存储在存储器中,可供一个或多个调用程序(主程序)反复调用。主程序调用子程序时使用CALL指令,由子程序返回主程序时使用RET指令。由于调用程序和子程序可以在同一个代码段中,也可以在不同的代码段中,因此,CALL指令和RET指令也有近调用、近返回及远调用、远返回两类格式。
⑴ CALL NEAR PTR SUBPROUT 近调用(near call)
近调用是CALL指令的缺省格式,可以写为"CALL subrotine"。它调用同一个代码段内的子程序(子过程),因此,在调用过程中不用改变CS的值,只需将子程序的地址存入IP寄存器。CALL指令中的调用地址可以用直接和间接两种寻址方式表示。
⑵ CALL FAR PTR SUBPROUT 远调用(far call)
远调用适用于调用程序(也称为主程序)和子程序不在同一段中的情况,所以也叫做段间调用。和近调用指令一样,远调用指令中的寻址方式也可用直接方式和间接方式。
⑶ RET 返回指令(return)
RET指令执行的操作是把保存在堆栈中的返回地址出栈,以完成从子程序返回到调用程序的功能。
● CALL SUBROUT 段内直接调用
执行操作:① (SP) ← (SP)-2,((SP)) ← (IP)当前
② (IP) ← (IP)当前+16位位移量(在指令的第2、3个字节中)
● CALL DESTIN 段内间接调用
执行操作:① (SP) ← (SP)-2,((SP)) ← (IP)当前
② (IP) ← (EA) ; (EA)为指令寻址方式所确定的有效地址
● CALL FAR PTR SUBROUT 段间直接调用
执行操作:① (SP) ← (SP)-2,((SP)) ← (CS)当前
(SP) ← (SP)-2,((SP)) ← (IP)当前
② (IP) ← 偏移地址(在指令的第2、3个字节中)
(CS) ← 段地址(在指令的第4、5个字节中)
● CALL WORD PTR DESTIN 段间间接调用
执行操作:① (SP) ← (SP)-2,((SP)) ← (CS)当前
(SP) ← (SP)-2,((SP)) ← (IP)当前
② (IP) ← (EA) ; (EA)为指令寻址方式所确定的有效地址
(CS) ← (EA+2)
从CALL指令执行的操作可以看出,第一步是把子程序返回调用程序的地址保存在堆栈中。对段内调用,只需将IP的当前值,即CALL指令的下一条指令的地址存入SP所指示的堆栈字单元中。对段间调用,保存返回地址则意味着要将CS和IP的当前值分别存入堆栈的两个字单元中。
CALL指令的第二步操作是转子程序,即把子程序的入口地址交给IP(段内调用)或CS:IP(段间调用)。对段内直接方式,调转的位移量,即子程序的入口地址和返回地址之间的差值就在机器指令的2、3字节中。对段间直接方式,子程序的偏移地址和段地址就在操作码之后的两个字中。对间接方式,子程序的入口地址就从寻址方式所确定的有效地址中获得。
● RET 段内返回(近返回)
执行操作:(IP) ← ((SP)),(SP) ← (SP)+2
● RET 段间返回(远返回)
执行操作:(IP) ← ((SP)),(SP) ← (SP)+2
(CS) ←((SP)),(SP) ← (SP)+2
● RET N 带立即数返回
执行操作:① 返回地址出栈(操作同段内或段间返回)
② 修改堆栈指针:(SP) ← (SP)+N
子程序的最后一条指令必须是RET指令,以返回到主程序。如果是段内返回,只需把保存在堆栈中的偏移地址出栈存入IP即可,如果是段间返回,则要把偏移地址和段地址都从堆栈中取出送到IP和CS寄存器中。
带立即数返回指令,除完成偏移地址出栈或偏移地址和段地址出栈的操作外,还要再使SP的内容加上一个立即数N,使堆栈指针SP移动到新的位置。指令中的N可以是一个常数,也可以是一个表达式。带立即数返回指令适用于C或PASCAL的调用规则,这些规则在调用过程(子程序)前先把参数压入堆栈,子程序使用这些参数后,如果在返回时丢弃这些已无用的参数,就在RET指令中包含一个数字,它表示压入到堆栈中参数的字节数,这样堆栈指针就恢复到参数入栈前的值。
CALL指令和RET指令都不影响条件码。
例 根据下面调用程序和子程序的程序清单,画出RET指令执行前和执行后的堆栈情况。假设初始的SS:SP=A000:1000。
0000 B8 001E MOV AX,30
0003 BB 0028 MOV BX,40
0006 50 PUSH AX ; push data1 into stack
0007 53 PUSH BX ; push data2 into stack
0008 E8 0066 CALL ADDM ; call subroutine
000B B4 02 MOV AH,2
… … …
0071 ADDM PROC NEAR ; entry point (IP)←0071=000b+0066
0071 55 PUSH BP ; save BP
0072 8B E4 MOV BP,SP ; addressing the stack with BP
0074 8B 46 04 MOV AX,[BP+4] ; get data2 from stack
0077 03 46 06 ADD AX,[BP+6] ; add data1
007A CD POP BP ; get back BP
007B C2 0004 RET 4 ; return and revert SP
007E ADDM ENDP
图 CALL指令和RET指令对堆栈的影响
如图3.12所示,主程序中的两条PUSH指令将数据30和40压入堆栈,CALL指令执行后,返回地址000B又压入堆栈,紧接着程序控制转移到子程序ADDM。子程序中的PUSH指令又使BP的值进栈,此时SP指向栈顶0FFA。MOV指令将0FFA传送给BP,使BP作为寻址堆栈数据的指针。(BP+4)指向的是40,(BP+6)指向的是30,取出数据后用POP指令恢复了BP原先的值,此时,(SP)=0FFC,这是RET 4指令执行前的堆栈状态。
执行RET 4指令时,先使返回地址出栈:(IP)←000B,(SP)←0FFC+2=0FFD,然后,(SP)+4=0FFD+4=1000,结果使SP跳过了堆栈数据而回到了原始位置。
5 中断及中断返回指令
INT n 中断指令(interrupt),n为中断类型号
IRET 中断返回指令(return from interrupt)
INTO 溢出则中断(中断类型为4)
INT n 中断指令(interrupt),n为中断类型号
执行操作:① 入栈保存FLAGS:(SP) ← (SP)-2,((SP)) ← (FLAGS)
② 入栈保存返回地址:(SP) ← (SP)-2,((SP)) ← (CS)
(SP) ← (SP)-2,((SP)) ← (IP)
③ 转中断处理程序:(IP) ← (n×4)
(CS) ← (n×4+2)
IRET 中断返回指令(return from interrupt)
执行操作:① 返回地址出栈:(IP) ← ((SP)),(SP) ← (SP)+2
(CS) ← ((SP)),(SP) ← (SP)+2
② FLAGS出栈:(FLAGS) ← ((SP)),(SP) ← (SP)+2
INTO 溢出则中断(中断类型为4)
执行操作:若OF=1(有溢出),则:
① 入栈保存FLAGS:(SP) ← (SP)-2,((SP)) ← (FLAGS)
② 入栈保存返回地址:(SP) ← (SP)-2,((SP)) ← (CS)
(SP) ← (SP)-2,((SP)) ← (IP)
③ 转中断处理程序:(IP) ← (4×4)= (10H)
(CS) ← (4×4+2)= (12H)
中断指令用于调用中断例行程序(又称中断服务程序),这是一种远调用。完成各种功能的中断例行程序都有一个编号,称为中断类型号。各种中断例行程序的入口地址按中断类型号的顺序存储在一个表中,这个表称为中断向量表。每个中断例行程序的入口地址占用4个字节,因此,它在中断向量表中的地址可用中断类型号乘4来求得。执行中断指令时,首先要入栈保存调用程序执行的现场,即当时的标志寄存器的值和断点的地址,然后,根据中断类型号(n×4)到中断向量表中取得中断例行程序的入口地址,分别送给IP和CS,以实现调用中断例行程序的功能。
中断返回指令IRET的操作和INT指令相反,即从堆栈中取出返回地址和标志位,然后返回到被中断的程序。
INTO指令隐含的中断类型号为4,因此保存断点地址和标志位后,从中断向量表的10H和12H两个字中取出中断例行程序的入口地址,从而转去运行中断例行程序。
INT指令(包括INTO)执行后,把IF和TF置0,但不影响其它标志位。
6 处理机控制指令
处理机控制指令包括一组置0或置1标志位的指令,还有一些控制处理机状态的指令。
6.1 标志位处理指令
这一组指令分别对标志位CF、DF、IF执行置0、置1或求反的操作,如,CLD指令执行的操作是:DF←0;STD执行的操作是:DF←1。
标志位处理指令只影响本指令指定的标志,而不影响其它标志位。
⑴ 标志位处理指令 ⑵ 处理机控制指令
CLC CF置0 NOP 无操作
STC CF置1 HLT 停机
CMC CF求反 WAIT 等待
CLD DF置0 ESC 转义
STD DF置1 LOCK 封锁
CLI IF置0
STI IF置1
6.2 处理机控制指令
NOP 无操作指令(no operation)
HLT 停机指令(halt)
WAIT 等待指令(wait)
ESC mem 转义指令(escape)
LOCK前缀封锁(lock)
NOP 无操作指令(no operation)
执行操作:不执行任何操作,其机器码占用1个字节单元,执行时间为3个时钟周期,因此,该指令的作用表现在时间和空间上。时间上它可使上下两条指令的执行有一点间隔,这使某些指令的执行,特别是控制硬件接口的指令因为有一点延时而增加可靠性。空间上它的位置可在调试指令时用其它指令来代替。
HLT 停机指令(halt)
执行操作:使处理机停止软件的执行并等待一次外部中断的到来,中断结束后处理机继续执行下面的程序。使用该指令的目的通常是为了保持外部硬件中断与软件系统的同步。
WAIT 等待指令(wait)
执行操作:测试微处理器的BUSY/TEST管脚,如果执行WAIT指令时,BUSY/TEST=1(指示不忙),则继续执行下一条指令。如果执行WAIT指令时,BUSY/TEST=0(指示忙),则微处理器等待直到BUSY/TEST管脚变为1。
ESC mem 转义指令(escape)
执行操作:mem指定存储单元,执行ESC指令时,从存储器取得指令或操作数通过总线送给8087~80387数值协处理器。协处理器能处理算术运算、函数运算、对数运算等数值运算,其运算速度比使用常规指令写的软件快的多。
LOCK前缀 封锁(lock)
执行操作:指令前加LOCK,使得在锁定指令期间保持锁存信号LOCK=0,以禁止外部总线上的主控制器或系统其它部件。例如,LOCK MOV AL,[SI]执行时,总线封锁直至MOV指令执行完毕。
【小结】
1、8086寻址方式
寻址方式
|
操作数地址(PA)
|
指令格式举例
|
立即寻址
|
操作数在指令中给出
|
MOV DX,100H ; (DX)←100H
|
寄存器寻址
|
操作数在寄存器中
|
ADD AX,BX ; (AX)←(AX)+(BX)
|
直接寻址
|
操作数的有效地址由指令直接给出
|
MOV AX,[100] ; (AX)←(100)
MOV AX,VAR ; (AX)←(VAR) |
寄存器
间接寻址 |
PA=(DS)×16+(BX)或(SI)或(DI)
PA=(SS) ×16+(BP) |
MOV AX,[BX] ;
(AX)←((DS)×16+(BX)) |
寄存器
相对寻址 |
PA=(DS)×16+(BX)或(SI)或(DI)+位移量
PA=(SS) ×16+(BP)+位移量 |
MOV AL,MESS[SI];
(AL)←((DS)×16+(SI)+OFFSET MESS) |
基址变址
寻址 |
PA=(DS)×16+(BX)+(SI)或(DI)
PA=(SS) ×16+(BP) +(SI)或(DI) |
MOV AX,[BX+DI];
(AX)←((DS)×16+(BX)+(DI)) |
相对基址
变址寻址 |
PA=(DS)×16+(BX)+(SI)或(DI)+位移量
PA=(SS) ×16+(BP) +(SI)或(DI)+位移量 |
MOV AX,BUFF(BX+DI);
(AX)←((DS)×16+(BX)+(DI)+OFFSET BUFF) |