数据传送类指令
数据传送是计算机中最基本、最重要的一种操作,数据传送指令的功能是把数据从一个位置传送到另一个位置。
1. 通用数据传送指令
(1) MOV指令
- 指令格式:MOV dest , src
- 指令功能:dest←src
将数据由源位置传送至目的位置,源操作数不变,不影响标志位。
对操作数的规定:
- src和dest的数据类型要一致
- 类型一致的操作数之一必须有明确的类型,否则要用PTR指明类型。
- 源操作数和目的操作数的寻址
(2) XCHG指令
- 指令格式:XCHG reg , reg/mem
- 指令功能:dest←src
将寄存器或存储器中的内容与目的寄存器中的内容相互交换。不影响状态标志位。
对操作数的规定:
- src和dest的数据类型要一致
- 两个存储器操作数之间不能实现直接交换
- 段寄存器和立即数不能作为操作数
(3) XLAT指令
- 指令格式:XLAT LABEL或 XLAT
- 指令功能:AL←DS: [BX+AL]
用于将BX指定的缓冲区中,AL指定的位移处的数据取出传送给AL 。
换码指令(也叫查表指令)的两种格式完全等效。操作数是隐含寻址,第一种格式中的LABEL表示首地址,第二种格式中的首地址隐含在BX中,位移在AL寄存器中。
2. 堆栈操作指令
堆栈操作:
- 堆栈是一个“先进后出”的主存区域,位于堆栈段中;
- 使用SS段寄存器存放段地址
有两种基本的操作:
- 数据压进堆栈PUSH
- 数据弹出堆栈操作POP
用SP指明当前栈顶。
- 数据进入堆栈,SP减小
- 数据弹出堆栈,SP增加
(1) 出栈指令POP :
- 指令格式 POP r16/m16/seg
- 指令功能:r16/m16/seg←SS: [SP],SP←SP+2
先将栈顶数据传送到目的操作数(通用寄存器、存储单元或段寄存器(CS除外)),然后堆栈指针SP加2。
(2) 进栈指令PUSH
- 指令格式:PUSH r16/m16/seg
- 指令功能:SP←SP-2,SS:[SP]←r16/m16/seg
先将SP减2作为当前栈顶,然后将源操作数(立即数、通用寄存器和段寄存器内容或存储器操作数)传送到当前栈顶。
堆栈指令应用注意
- 程序中有一个PUSH,必有一个对应的POP
- 遵循先入后出原则
- 按字或双字进行操作
- 出栈指令的操作数不能为CS
- 堆栈指令不影响标志位
3. 标志传送指令
标志位传送指令专门用于对标志寄存器(FR)的保护和更新操作。
(1) 标志寄存器传送
- 读标志寄存器:LAHF
用于将FR的低字节(含SF、ZF、AF、PF和CF)读出后传送到AH寄存器。这条指令不影响标志位。
- 写标志寄存器:SAHF
将寄存器AH中的内容写入FR的低字节,取代某些标志位(SF、ZF、AF、PF和CF)的原来状态 。影响标志位。
- 标志寄存器入栈:PUSHF
将FR内容压入堆栈,同时修改堆栈指针。 即: SP←SP-2 , SS:[SP]←FLAGS
- 标志寄存器出栈:POPF
将当前栈顶的一个字→ FR,同时修改堆栈指针。影响标志位。即:FLAGS←SS:[SP] , SP←SP+2
在子程序调用或中断子程序中,常用此保护和恢复需要的标志位。
4. 地址传送指令
地址传送指令将存储器的逻辑地址传送至指定的寄存器。
(1)有效地址传送指令
- 指令格式 LEA r16 , mem
- 指令功能 将存储器操作数的有效偏移地址传送至指定寄存器中。该指令不影响标志位。
例如
MOV BX , 0400H
MOV SI , 3CH
LEA BX , [BX+SI+0F62H]
执行结果:BX=139EH
(2)地址指针传送指令
- 指令格式 LDS r16 , mem 或 LES r16 , mem
- 指令功能 将内存中mem指定的字送至r16,并将mem的下一字送DS或ES寄存器。不影响标志位。
- 应用 利用这两条地址指针传送指令可以对串操作源操作数和目的操作数的地址指针进行初始化。
5. 输入输出指令
输入/输出指令用于完成输入/输出端口与累加器(AL/AX)之间的数据传送。
(1) 输入指令IN
- 指令格式 IN AL , i8;IN AX , i8;IN AL , DX;IN AX , DX
- 指令功能 将字节数据(或字数据)通过指定端口传送至累加器AL(或AX)中。不影响标志位。
8086CPU用于寻址外设端口的地址线是16条,寻址前256个端口时,可用00H~0FFH直接寻址,寻址的端口号大于256时,只能用DX寄存器间接寻址。
(2) 输出指令OUT
- 指令格式 OUT i8 , AL;OUT i8 , AX;OUT DX , AL;OUT DX, AX
- 指令功能 将字节数据(或字数据)通过累加器AL(或AX)传送至指定端口中。不影响标志位。
例 将数据80H送到3FCH端口。
MOV DX , 3FCH
MOV AL,80H
OUT DX , AL
算术运算指令
算术运算指令可以完成带符号和不带符号的8位/16位二进制的算术运算,以及BCD码表示的十进制数的算术运算。
1. 加法指令
执行字或字节的加法运算。包括ADD,ADC和INC三条指令。
(1) 不带进位加法指令ADD
- 指令格式 ADD reg , imm/reg/mem 或 ADD mem , imm/reg
- 指令功能 该指令将源操作数与目的操作数相加,结果送到目的操作数。该指令影响标志位CF、AF、PF、SF、OF和ZF 。
(2) 带进位加法指令ADC
- 指令格式 ADC reg , imm/reg/mem或 ADC mem , imm/reg
- 指令功能 该指令将源操作数与目的操作数相加再与进位CF相加,结果送到目的操作数。该指令影响标志位CF、AF、PF、SF、OF和ZF 。
ADC指令主要用于与ADD指令相结合实现多字节数相加。
例 分析用ADC指令完成的无符号双字长加法运算。
MOV AX , 4652H
ADD AX , 0F0F0H
MOV DX , 0234H
ADC DX , 0F0F0H
执行结果:
AX=3742H CF=1
DX=F325H CF=0
(3) 增量指令INC
- 指令格式 INC reg/mem
- 指令功能 该指令将目的操作数的内容加1,并将结果回送到目的操作数。 该指令影响标志位AF、PF、SF、OF和ZF,但不影响CF标志。
2. 减法指令
执行字或字节的减法运算。包括SUB,SBB,DEC,NEG和CMP五条指令。
(1) 不带借位减法指令SUB
- 指令格式 SUB reg , imm/reg/mem 或SUB mem , imm/reg
- 指令功能 该指令将目的操作数与源操作数相减,结果送到目的操作数。该指令影响标志位CF、AF、PF、SF、OF和ZF 。
(2) 带借位减法指令SBB
- 指令格式 SBB reg , imm/reg/mem 或SBB mem , imm/reg
- 指令功能 该指令将目的操作数与源操作数相减再与借位CF相减,结果送到目的操作数。该指令影响标志位CF、AF、PF、SF、OF和ZF 。
SBB指令主要用于与SUB指令相结合实现多倍字长数相减。
例 分析用SBB指令完成的无符号双字长减法运算。
MOV AX , 4652H
SUB AX , 0F0F0H
MOV DX , 0234H
SBB DX , 0F0F0H
执行结果:
AX=5562H CF=1
DX=1143H CF=1
(3) 减量指令DEC
- 指令格式 DEC reg/mem
- 指令功能 该指令将目的操作数的内容减1,并将结果回送到目的操作数。 该指令影响标志位AF、PF、SF、OF和ZF,但不影响CF标志。
(4) 求补指令NEG
- 指令格式 NEG reg/mem
- 指令功能 该指令将目的操作数求补运算,将其结果送回目的操作数。实际上是用零减去操作数,然后将结果返回操作数。 该指令影响标志位CF、AF、PF、SF、OF和ZF 。
例如
MOV AX,0FF64H
NEG AX
结果
AX = 009CH
CF=1
(5) 比较指令CMP
- 指令格式 CMP reg , imm/reg/mem或CMP mem , imm/reg
- 指令功能 该指令将目的操作数减去源操作数,结果不回送。 该指令影响标志位CF、AF、PF、SF、OF和ZF 。
3. 乘法指令
用来实现两个二进制操作数的相乘运算 。包括无符号数乘法指令MUL和有符号数乘法指令IMUL两条指令。
(1)无符号数乘法指令MUL
- 指令格式 MUL R8/M8 或MUL R16/M16
- 指令功能 (AX)←(AL)(SRC)或(DX,AX)←(AX)(SRC)
该指令实现两个无符号数的乘法运算,其中被乘数隐含在AL(或AX)中,运算结果要保存在AX(或DX和AX)中。
逻辑运算类指令
逻辑运算类指令用来对字或字节按位进行逻辑运算,包括:逻辑与AND,逻辑或OR,逻辑非NOT,逻辑异或XOR和测试TEST五条指令。
1. 逻辑与指令
指令格式 AND dest,src
指令功能
- 按位进行逻辑与,结果返回目的操作数
- 设置CF=OF=0
- 影响SF,ZF和PF
2.逻辑或指令
指令格式 OR dest,src
指令功能
- 按位进行逻辑或,结果返回目的操作数.
- 设置CF=OF=0
- 影响SF,ZF和PF
3. 逻辑非指令
指令格式 NOT reg/mem
指令功能
- 按位进行逻辑非,结果返回目的操作数.
- 不影响标志位
4. 逻辑异或指令
指令格式 XOR dest,src
指令功能
- 按位进行逻辑异或,结果返回目的操作数.
- 设置CF=OF=0
- 影响SF,ZF和PF
5. 逻辑测试指令
指令格式 TEST dest,src
指令功能
- 按位进行逻辑与,结果不返回目的操作数.
- 设置CF=OF=0
- 影响SF,ZF和PF
例 逻辑异或
MOV AL , 45H
XOR AL , 31H
执行结果:
AL= 74H,CF=OF=0,SF=0,ZF=0,PF=1
移位运算指令
这组指令可以对字节或字中的各位进行算术移位和逻辑移位。移位次数可以是1也可以大于1。若移位次数大于1时,必须将次数预先放入CL。
1. 非循环移位类指令
(1) 逻辑移位指令
- SHL REG/MEM , 1/CL
- SHR REG/MEM , 1/CL
(2) 算术移位指令 - SAL REG/MEM , 1/CL
- SAR REG/MEM , 1/CL
这组指令影响除AF以外的各个标志位。 - CF、SF、ZF、PF按移位结果设置。
- 移位次数为1时,按照目的操作数的最高位是否改变设置OF,改变时OF=1,否则为0。
2. 循环移位类指令
(1) 不带进位循环移位指令
-ROL REG/MEM , 1/CL
ROR REG/MEM , 1/CL
(2) 带进位循环移位指令
- RCL REG/MEM , 1/CL
- RCR REG/MEM , 1/CL
这组指令不影响SF、ZF、PF、AF标志位。- CF按移位结果设置。
- 移位次数为1时,按照目的操作数的最高位是否改变设置OF,改变时OF=1,否则为0。
例1 利用位移指令计算DX←3×AX+7×BX,假设为无符号数运算,没有进位。
算法实现: DX←(2×AX+AX)+(8×BX-BX)
MOV SI , AX
SHL SI , 1
ADD SI , AX
MOV DX , BX
MOV CL , 03H
SHL DX , CL
SUB DX , BX
ADD DX , SI
例2 对AL中的数据进行移位
MOV CL , 4
MOV AL , 0F0H
SHL AL,1
SHR AL,1
SAR AL,1
SAR AL,CL
执行结果:
AL= 03H,CF=1,SF=0,ZF=0,PF=1,OF不确定
程序控制类指令
- 在80X86CPU中,程序的执行序列是由代码段寄存器CS和指令指针IP确定的。
- 程序控制类指令通过修改CS和IP寄存器的值来改变程序的执行顺序,也是使用概率很高的指令。
1. 无条件转移指令 JMP
- 无条件转移,就是不需要任何条件就能使程序改变执行顺序。
- CPU只要执行无条件转移指令JMP,就可以使程序转到指令的目标地址处,从目标地址处开始执行新的指令。
在8086CPU中,使用JMP指令可以将程序转移到1MB存储空间的任何位置。根据跳转的距离,JMP指令分成了段内转移和段间转移。
- 段内转移是指在当前代码段64KB范围内转移,因此不需要更改CS段地址,只需要改变IP偏移地址。
- 段间转移是指从当前代码段跳转到另一个代码段,此时需要更改CS段地址和IP偏移地址,
JMP指令根据目标地址寻找方式的不同,可以分成四种格式。
(1)段内转移,相对寻址
JMP BABEL ;IP←IP + 位移量
- 位移量是指紧接着JMP指令后的那条指令的偏移地址到目标指令的偏移地址的地址位移
- 当向地址增大方向转移时,位移量为正
- 向地址减小方向转移时,位移量为负
(2)段内转移,间接寻址
JMP R16/M16 ;IP←R16/M16
这种形式的JMP指令,将一个16位寄存器或主存单元内容送入IP寄存器,作为新的指令指针,但不修改CS寄存器的内容。即寄存器或主存单元内容为转移地址。可在64KB的范围内转移。
(3)段间转移、直接寻址
JMP far ptr label ;IP←label的偏移地址,CS←label的段地址
段间直接转移指令,是将标号所在段的段地址作为新的CS值,标号在该段内的偏移地址作为新的IP值。
(4)段间转移、间接寻址
JMP far ptr mem ;IP←[mem],CS←[mem+2]
- 转移目标地址存放在主存中连续的两个字单元中,其中低位字送IP寄存器,高位字送CS寄存器。
- 段间转移用于复杂的、具有多个代码段的程序设计
- Far pat代表远程(段间),Near代表近程(段内)
段间转移、间接寻址举例:
MOV AX,OFFSET Label;获取标号的偏移地址
MOV [BX], AX
MOV AX,SEG Label;获取标号的段地址
MOV [BX+2], AX
JMP far ptr [BX] ;转移到标号Label指定的位置
偏移地址送IP;段地址送CS
段间转移目标地址在实际程序中,一般都以标号形式给出。
2. 条件转移指令
-
条件转移指令JCC(CC代表条件)用于分支程序设计,根据指令的条件确定程序是否发生转移。
-
如果满足条件,则程序转移到目标地址去执行程序;不满足条件,则程序将顺序执行下一条指令
通用格式: JCC label 条件满足,发生转移:IP←IP + 8位位移量 否则,顺序执行:IP←IP + 2 条件转移都是短转移,转移范围是-128到127
-
其中,label表示目标地址(8位位移量)
-
与其他控制转移指令一样,条件转移指令不影响标志位,但它要利用标志位。
-
条件转移指令共有16种,如表下表所示。表中斜线分隔了同一条指令的多个助记符形式 。即同一条指令可以有2到3种书写方式。
-
条件转移指令跳转的目标地址只能用段内相对短跳转,即目标地址只能在同一段内,且相对当前IP地址-128~+127 个单元的范围之内。
(1)通过判断单个标志位实现转移
例:X和Y是存放于X单元和Y单元的16位操作数,计算X-Y的绝对值,结果存入指定的RESULT单元。利用符号标志SF进行判断,使用指令JS或JNS实现转移。
MOV AX , X
SUB AX , Y ;AX←X-Y,下面求绝对值
JNS NONNEG ;结果为正数,转向保存结果
NEG AX ;为负数,进行求补得到绝对值
NONNEG: MOV RESULT , AX ;保存结果
例: X和Y为存放于X单元和Y单元的16位有符号操作数,计算X-Y。利用OF标志,判断是否溢出,使用指令JO或JNO实现转移
MOV AX , X
SUB AX , Y
JO OVERFLOW ;溢出转移到OVERFLOW
…… ;没有溢出,结果正确
OVERFLOW: …… ;溢出处理
例:记录BX中1的个数,利用进位标志进行判断,使用JC/JB/JNAE或JNC/JNB/JAE指令实现转移
1 XOR AL , AL
2 AGAIN: TEST BX , 0FFFFH ;等价于CMP BX , 0
3 JZ NEXT
4 SHL BX , 1 ;逻辑左移,最高位移入进位标志
5 JNC AGAIN
6 INC AL
7 JMP AGAIN
8 NEXT: MOV COUNT , AL ;AL保存1的个数
(2)通过判断多个标志位实现转移
- 为了和有符号数区分,无符号数的大小用高(Above)、低(Below)表示,它需要利用CF确定高低、利用ZF标志确定相等(Equal)。
- 两数的高低分成4种关系:低于(不高于等于)、不低于(高于、等于)、低于等于(不高于)、不低于等于(高于)
- 也就是分别对应四条指令:JB(JNAE),JNB(JAE),JBE(JNA),JNBE(JA)。
- A:高 B:低 E:等于 N:不
- J和这4个字母可以组合成用于无符号数判断大小的条件转移指令。
例:比较两个无符号数的大小,将较小的数存放在AX。
CMP AX , BX ;比较AX和BX
JBE NEXT ;检测CF和ZF,
;若 AX≤BX,则转移到NEXT
XCHG AX , BX ;若AX>BX,交换
NEXT: ……
例:比较两个有符号数的大小,将较大的存放在AX。
CMP AX , BX ;比较AX和BX
JNL NEXT ;检测SF和OF,
;若AX≥BX,则转移到NEXT
XCHG AX , BX ;若AX<BX,交换
NEXT: ……
3. 循环指令
循环指令有以下四条,用于循环程序设计。
(1)JCXZ LABEL
CX = 0,则转移;否则顺序执行
(2)LOOP LABEL
CX←CX-1;若CX≠ 0,循环:
IP←IP + 位移量,否则,顺序执行。用于循环次数已知
(3) LOOPZ/LOOPE LABEL
CX←CX-1 ;若CX ≠ 0且ZF = 1,循环;
IP←IP + 位移量;否则,顺序执行
(4) LOOPNZ/LOOPNE LABEL
CX←CX-1;
若CX ≠ 0且ZF = 0,循环 ,IP←IP + 位移量
否则,顺序执行
(3)和(4)可以用于有条件推出循环的程序。
例:记录附加段中STRING字符串包含空格字符的个数。假设字符串长度为X字节,结果存入指定的RESULT单元。
MOV CX , X ;X是常数,设置循环次数
MOV SI , OFFSET STRING
;提供字符串的偏移地址
XOR BX , BX ;BX清0,用于记录空格数
JCXZ DONE ;如果长度为0,退出
MOV AL , 20H ;空格的ASCII码
AGAIN: CMP AL , ES: [SI]
;判断一个字符是否为空格
JNZ NEXT ;ZF = 0,不是空格,转移
INC BX ;ZF = 1,是空格,空格个数加1
NEXT: INC SI ;地址指针指到下一个字符
LOOP AGAIN
;字符个数减1,不为0则继续循环
DONE: MOV RESULT , BX ;保存结果
4. 子程序调用和返回指令
- 子程序调用和返回指令用于调用子程序和从子程序返回。
- 子程序通常是与主程序分开的、完成特定功能的一段程序,可以反复使用。
- 主程序执行子程序调用指令CALL,可以转移到子程序,执行完后通过子程序返回指令RET,返回主程序继续执行
- CALL和RET指令均不影响标志位。
子程序调用指令CALL
子程序调用CALL指令也可以分成段内调用(近调用)和段间调用(远调用)。
有4种格式 (调用时下条指令地址要压入堆栈)
(1) CALL LABEL
;段内调用,相对寻址:SP←SP - 2,
;SS:[SP] ←IP,IP←IP + 16位位移量
(2) CALL R16/M16
;段内调用,间接寻址:SP←SP - 2,
;SS:[SP] ←IP,IP←R16/M16
(3)CALL far ptr label ;段间调用,直接寻址:
;SP←SP – 2,SS:[SP] ←CS,SP←SP - 2,
; SS:[SP] ←IP ;IP←label偏移地址,CS←label段地址
(4)CALL far ptr mem ;段间调用,间接寻址:
;SP←SP – 2,SS:[SP] ←CS,
;SP←SP - 2,SS:[SP] ←IP
;IP←[mem],CS←[mem+2]
从指定主存单元读出4个字节的地址,2个送IP,2个送段寄存器CS。
子程序返回指令RET
返回指令分为段内返回和段间返回,系统自动识别
格式:
RET ;无参数段内返回:IP←SS:[SP],
; SP←SP + 2
RET i16 ;有参数段内返回:IP←SS:[SP],
;SP←SP + 2,SP←SP + i16(可删除堆栈里的数)
RET ;无参数段间返回:IP←SS:[SP],
;SP←SP + 2 ;CS←SS:[SP],SP←SP+2
RET i16 ;有参数段间返回:IP←SS:[SP],
;SP←SP + 2,CS←SS:[SP],
;SP←SP+2,SP←SP + i16
例:利用子程序完成将AL低4位中的一位十六进制数转换成对应的ASCII码。
;主程序
MOV AL , 0BH ;提供参数给AL
CALL HTOASC ;调用子程序
……
;子程序
HTOASC: AND AL , 0FH ;只取AL的低4位
OR AL , 30H ;AL高4位变成3
CMP AL , 39H ;是0~9,还是A~F
JBE HTOEND ;小于等于39H转
ADD AL , 7
;是A~F,其ASCII还要加上7
HTOEND: RET ;子程序返回
注:由于子程序调用和返回均与堆栈有关,因此一定要正确使用堆栈,以免不能正确返回主程序。
5. 中断指令
在程序运行时,遇到某些紧急情况(如停电),或者一些重要错误(如溢出),CPU应当暂停当前程序,去做相应的处理。
- 处理器中止当前程序运行,转去执行处理这些紧急情况,计算机技术叫做“中断”;
- 而转去执行的处理中断的子程序叫做“中断服务程序”或“中断处理程序”。
- 当前程序被中断的地方称为“断点”。
- 计算机设计了中断指令可以执行中断程序
中断服务程序可以被认为是一种特殊的子程序,可以存放在主存的任何位置。中断服务程序的入口地址称为中断向量,被安排在中断向量表中。
对80X86 CPU,采用实地址方式时,中断向量表放在主存的最低1KB区域内,物理地址为000H~3FFH。向量表从0开始,每4字节对应一个中断,低字存放中断服务程序的偏移地址IP,高字存放其段地址CS。中断向量号n的中断服务程序存放在中断向量表4×n的物理地址处。
对32位的CPU,中断向量表可以放在主存的任意区域,由中断向量寄存器指明位置 ,根据中断号查找中断向量表,形成中断服务程序入口地址。
中断指令格式如下:
INT I8 ;中断调用指令:I8为8位的中断向量号
IRET ;中断返回指令:实现中断返回
INTO ;溢出中断指令:检查是否溢出(4号中断)
为保证中断服务程序正确返回原来的程序,要把被中断程序的断点处逻辑地址CS:IP压入堆栈保护,还要保存反映现场状态的标志寄存器FLAGS。然后,将从中断向量表中获取的中断服务程序的入口地址送CS和IP寄存器转去执行中断服务程序
执行中断指令时,获得中断向量号n之后,要做下列操作。
- 禁止新的可屏蔽中断和单步中断:IF=TF←0。
- 标志寄存器入栈保护:SP←SP–2, SS: [SP]←FLAGS。
- 断点地址入栈保存:SP←SP–2,SS: [SP]←CS;SP←SP–2,SS: [SP]←IP。
- 读取中断服务程序的起始地址:IP←[n×4],CS←[n×4+ 2]。
例如:INT 20H
将从80H开始的4个字节获取20H中断的服务程序入口地址。
中断返回指令IRET实现从中断服务程序返回原程序,要做下列操作:
- 断点地址出栈恢复:IP←SS: [SP],SP←SP + 2;CS←SS: [SP],SP←SP+2。
- 标志寄存器出栈恢复: FLAGS←SS: [SP],SP←SP+2。
中断指令提供了又一种改变程序执行顺序的方法,在计算机系统中,常利用它为用户提供硬件设备的驱动程序。个人计算机中的基本输入/输出系统BIOS和操作系统DOS都提供了丰富的中断服务程序让程序员调用。