第3章 80x86汇编语言程序设计(上) 16位汇编版本 时间不够的情况下只讲16位汇编
3.1 80x86的寻址方式 有效地址(effective address EA) —— 操作数在段内的偏移地址 寻址方式 —— 产生有效地址的方法 80x86指令的一般汇编语言格式: [标号:]指令助记符[[目的操作数][,源操作数]][;注释] 其中[ ]表示可选项; 3.1.1 操作数寻址 80x86的操作数寻址方式有: 1、立即寻址 2、寄存器寻址 3、存储器寻址 4、端口寻址
我们首先讨论两种与存储器无关的寻址方式: 1、立即寻址 操作数以常量形式直接放在指令中,紧跟在操作码之后 机器码存放形式如下: 代码段 代码段 低地址 OP 操作码 OP 操作码 D8 D16低8位 8位操作数 高地址 16位操作数 D16高8位 立即寻址示例 MOV AH, -40 ; -40AH MOV AX, 34D8H ; 34HAH, D8HAL MOV AX, -40 ; 0FFD8H(-40)AX
MOV AH, BL ;(BL)-->AH MOV DS, AX ;(AX)-->DS 2、寄存器寻址 操作数存放在某个寄存器中,指令指定寄存器号 指令 寄存器 寄存器号 操作数 寄存器寻址示例 MOV AH, BL ;(BL)-->AH MOV DS, AX ;(AX)-->DS MOV SI, AX ;(AX)-->SI 说明:立即寻址和寄存器寻址方式不需访问存储器即可得到操作数,速度快
下面我们来讨论余下的几种与存储器有关的寻址方式,先介绍几个概念: 有效地址(EA)的4种组成成分: 有效地址的计算: EA=基址 +(变址*比例因子)+ 位移量 位移量(displacement) 存放在指令中的8位、16位或32位的数,是一个地址 基址(base) 存放在基址寄存器中的内容,用于指向数组的首地址 变址(index) 存放在变址寄存器中的内容,用于访问数组的某个元素 比例因子(scale factor) 32位汇编才有 其值可为1,2,4或8,386及其后继机型新增加的
16/32位寻址时有效地址四种成分的组成 四种成分 16位寻址 32位寻址 位移量 0, 8, 16位 0, 8, 32位 基址寄存器 BX, BP 任何32位通用寄存器(包括ESP) 变址寄存器 SI, DI 除ESP以外的32位通用寄存器 比例因子 无 1, 2, 4, 8
除相对于堆栈以及串处理的目的串以外的所有数据访问 默认段选择规则 访存类型 所用段及寄存器 缺省选择规则 指令 代码段 CS 用于取指 堆栈 堆栈段 SS 所有的堆栈的进栈和出栈 任何用ESP或EBP或BP作为基址寄存器的访存 目的串 附加数据段 ES 串处理指令的目的串 局部数据 数据段 DS 除相对于堆栈以及串处理的目的串以外的所有数据访问
访问非默认段数据的方法——段超越 数据的存放比较灵活,除了放在默认的DS段,还可以存放在别的段,此时访问他们需要使用段超越前缀,可用的段超越前缀有CS:, DS:, ES:, SS:, FS:, GS:。 段超越举例: MOV AX, [10H] ;DS段10H处的一个字的数据赋给AX寄存器 MOV AX, ES:[10H]; ES段10H处的一个字的数据赋给AX寄存器 不允许使用段超越前缀的情况: (1)串操作指令的目的串必须用ES段 (2)PUSH指令的目的和POP指令的源必须用SS段 (3)程序的指令必须存放在CS段
3、直接寻址 操作数地址的偏移量(EA)在指令中 段基地址 存储器 指令 操作数 EA + 物理地址=指定段的段基地址×16+偏移量(EA) 系统默认,操作数在数据段 MOV AX, 2000H ; 立即寻址 MOV AX, [2000H] ; 直接寻址
直接寻址示例1 MOV AX, [1000H] 物理地址 设(DS)=10A0H 代码段 + OP 00H 10H 数据段 代码段 + OP 00H 10H 数据段 11A00H 30H 50H 1000H 10A0H 10A00H 1000H 低地址 11A00H 11A00H 主意提醒段地址×16(左移4位) 30H 50H AX 50H 30H (本章中图示存储器地址从上到下递增)
直接寻址示例2 MOV BL, ES:[0100H] 物理地址 设(ES)=3000H 30000H (DS)=2000H + 0100H 30100H 4B 00 BL 0100H 3000H 30100H 30100H 4B 4B 在汇编语言指令中,可以用符号地址代替数值地址 如:MOV AX, BUFF 或 MOV AX, [BUFF] 其中BUFF为存放数据单元的符号地址。
段基地址 指令 寄存器 存储器 基址或变址寄存器号 EA + 操作数 寄存器间接寻址示例 MOV AL, [BX] 4、寄存器间接寻址 操作数在存储器中,操作数地址的偏移量(EA)在寄存器中 段基地址 指令 寄存器 存储器 基址或变址寄存器号 EA + 操作数 寄存器间接寻址示例 MOV AL, [BX] MOV AX, CS:[SI] MOV [BP], AH
… MOV AH, [BP] MOV BX, [SI] MOV CX, SI 设 (SS)=1000H, (DS)=2000H , (BP)=0B10H, (SI)=032AH 物理地址 物理地址 10000H 20000H + 0B10H + 032AH 40H 00H 3EH 46H 1000H 2000H 0B10H 032AH 10B10H 10B10H 2032AH 2032AH AH 10B10H 40H 032AH 40H 032AH SI 10B11H … 032AH CX 2032AH 3EH 463EH BX 2032BH 46
5、基址寻址 指 令 段基地址 基址寄存器号 位移量 存储器 EA + + 操作数 基址寄存器 地址 可用于数组元素的访问 操作数的有效地址是基址寄存器的内容加上指令中指定的位移量 指 令 段基地址 基址寄存器号 位移量 存储器 EA + + 操作数 基址寄存器 地址 可用于数组元素的访问
基址寻址示例 MOV AX, 3000H[BX] (或[BX+3000H]) MOV AX, COUNT[BX] ; COUNT是符号地址 (或 MOV AX,[COUNT+BX]) 若(DS)=3000H, (BX)=2000H,COUNT=4000H 30000H 2000H + 4000H 3000H 2000H 4000H 36000H 36000H 36000H 34H 12H 34H 12 1234H AX
6、变址寻址 操作数的有效地址是变址寄存器的内容加上指令中指定的位移量 指 令 段基地址 变址寄存器号 位移量 存储器 操作数 + + 变址寄存器 EA 地址
变址寻址示例 MOV CX, 6020H[SI] (或[SI+6020H]) MOV DX, COUNT[SI] ; COUNT是符号地址 (或 MOV AX,[COUNT+SI]) 若(DS)=3000H, (SI)=2000H,COUNT=1000H 30000H 2000H + 1000H 3000H 2000H 1000H 33000H 33000H 33000H 34H 67H 34H 67 6734H DX
7、基址变址寻址 1)无位移量的基址变址寻址 操作数的有效地址是一个基址寄存器和一个变址寄存器的内容之和 指 令 变址寄存器 段基地址 基址寄存器变址寄存器 变址值 存储器 操作数 + + 基址寄存器 EA 基址值
无位移量基址变址寻址示例 MOV AX, [BX+DI] MOV AX, [BX][DI] 若 (DS)=2100H, (BX)=0158H, (DI)=10A5H, 2100H 0158H 物理地址 21000H 0158H + 10A5H 10A5H 221FDH 221FDH 221FDH 34H 12H 34H 12 1234H AX
2)基址变址相对寻址 操作数的有效地址是一个基址寄存器的内容、 一个变址寄存器的内容及位移量之和 指 令 基址寄存器变址寄存器位移量 段基地址 存储器 变址寄存器 EA 变址值 + + 操作数 基址值 基址寄存器
基址变址相对寻址示例 MOV AX, MASK[BX+SI];MASK是符号地址 若 (DS)=3000H, (BX)=2000H, (SI)=1000H, MASK=0250H 物理地址 30000H 2000H 1000H + 0250H 33250H 20H 43H 3000H 2000H 1000H 0250H 33250H 33250H 20H 43 4320H AX
8、端口寻址 1)直接寻址(I/O Port Direct Addressing) 直接寻址是使用一字节立即数寻址,因此I/O端口的寻址范围为00H~FFH,最多为256个。 IN AL, 20H ;从20H端口读入1个字节 OUT 60H, AX ;将AX中1个字送到60H端口 2)间接寻址(I/O Port Indirect Addressing) 间接寻址由DX寄存器间接给出I/O端口地址,为两个字节,所以最多可寻址216=64K个端口地址。 MOV DX, 3FCH IN AL, DX ;从3FCH端口读入1个字节
3.1.2 转移操作寻址 段内直接寻址 转向的有效地址是当前IP/EIP寄存器的内容和指令中指定的位移量之和。位移量在条件转移以及短转移中只有8位,其它情况下为16位。 偏移量 机器码 程序 0000 0405 PROG_S: ADD AL,05H 0002 90 NOP 0003 EBFB JMP SHORT PROG_S 0005 该程序在判断跳转偏移的时候,当前IP值已经是0005,所以跳转偏移为-5 (FBH) 机器码是16进制
段内间接寻址 转向有效地址是一个寄存器或是一个存储单元的内容 。所得到的转向的有效地址用来取代IP/EIP寄存器的内容。 设:(DS)=2000H,(BX)=1000H,变量TABLE的有效地址为1000H,(21000H)=0040H,(22000H)=5678H,则下列三条指令分别执行后结果如下: JMP BX ;执行后IP=1000H JMP [BX] ;执行后IP=0040H JMP TABLE[BX] ;执行后IP=5678H
段间直接寻址 指令中直接提供了转向段地址和偏移地址,用指令中提供的偏移地址取代IP/EIP寄存器,用指令中提供的段地址取代CS寄存器的内容就完成从一个段到另一个段的转移操作。 JMP FAR PTR NEXT_PRO 段间间接寻址 用存储器中的相继字的内容来取代IP/EIP和CS寄存器中的原始内容以达到段间转移的目的。 设:(DS)=2500H,(SI)=1300H,(26300H)=4500H,(26302H)=32F0H, 则执行以下指令后结果如下: JMP DWORD PTR [SI];执行后CS=32F0H,IP=4500H
3.2 80x86的指令系统 数据传送指令 算术运算指令 逻辑运算与移位指令 串操作指令 控制转移指令 处理器控制指令
3.2.1数据传送指令 通用数据传送指令 地址传送指令 标志寄存器传送指令 输入输出指令 类型转换指令
1、通用数据传送指令 MOV(move) 传送 MOVSX(move with sigh-extend) 带符号扩展传送 MOVZX(move with zero-extend) 带零扩展传送 PUSH(push onto the stack) 进栈 POP(pop from the stack) 出栈 PUSHA/PUSHAD (push all registers) 所有寄存器进栈 POPA/POPAD (pop all registers) 所有寄存器出栈 XCHG(exchange) 交换 XLAT(translate) 换码
MOV 传送指令 格式:MOV DST, SRC 操作:DST<--(SRC) 即把源操作数的内容送入目的操作数 说明:1)可以进行8位、16位或32位数据的传送 2)SRC可为立即数、寄存器、存储器操作数 3)DST可为寄存器、存储器操作数 4)该指令不影响任何状态标志位 段寄存器 CS DS SS ES 通用寄存器 AX BX CX DX BP SP SI DI 立即数 存储器
MOV指令示例1 MOV AL, BL ;寄存器之间传送 MOV BP, SI MOV AX, [BX+DI] ;存储器操作数 MOV AX, ARRAY[SI] ;传送到寄存器 MOV AX, 0B00H ;立即数传送到寄存器 MOV CL, 10000000B MOV VALUE, 100H ;立即数传送到存储单元 MOV ES:[BX], 4BH MOV [BX], CX ;寄存器内容传送到存储器 MOV BUFF [BP][DI], AX
设(DS)=3000H, (SI)=2000H, ARRAY=8000H 物理地址 30000H 2000H + 8000H 3A000H MOV指令示例2 MOV AX, ARRAY[SI] 设(DS)=3000H, (SI)=2000H, ARRAY=8000H 物理地址 30000H 2000H + 8000H 3A000H 3A000H 45H 0BH 0B45H AX
MOV指令注意事项: (1)两个操作数长度必须一致 MOV AL, BX ;不合法 例外:源是16进制立即数,位数小于目的操作数时,高位按0扩展,源是10进制立即数,位数小于目的操作数时,高位按符号位扩展 MOV AX, 0D8H 执行后,(AX)=00D8H MOV AX, -40 执行后,(AX)=FFD8H (2)不允许用立即数为段寄存器赋值 例:MOV ES, 10A0H ;不合法
(3)不允许两个操作数均是存储器操作数 MOV X, Y ;不合法 可以通过一个寄存器传送: MOV AX, Y MOV X, AX (4)不允许两个操作数均为段寄存器 MOV ES, DS ;不合法 (5)不允许CS、IP和立即数做目标操作数 MOV CS, AX ;不合法 MOV 100H, AX ;不合法 MOV IP, BX ;不合法
PUSH 压栈指令 举例:PUSH AX 格式:PUSH SRC PUSH DAT[BX][SI] 操作: PUSH 1234H 16位指令: SP<--(SP)-2 ((SP)+1,(SP))<--(SRC) 32位指令: ESP(ESP)-4 ((ESP)+3,(ESP)+2,(ESP)+1,(ESP))(SRC) 举例:PUSH AX PUSH DAT[BX][SI] PUSH 1234H PUSH 87654321H PUSH EAX 说明:1) 源操作数可以是寄存器或存储器操作数 2) 必须以字或双字为单位操作 3) 32位指令允许SRC是16位或32位立即数,也容许是32位寄存器和存储器操作数
压栈指令示例 PUSH AX 执行前 AX AX 25H 31H SP 52500H 执行后 31 25H 3125H 3125H 低地址 低地址 524FEH 524FFH SP 52500H 进栈方向
POP 出栈指令 格式:POP DST 操作: 16位指令: DST<--((SP)+1,(SP)) SP<--(SP)+2 32位指令: DST((ESP)+3,(ESP)+2,(ESP)+1,(ESP)) (ESP)(ESP)+4 举例:POP AX POP DAT[BX][SI] POP DS POP ECX
出栈指令示例 POP BX 执行前 执行后 BX BX 75C1H 低地址 低地址 SP 6Bh 51000H 6Bh 51000H 48h 1H 48h 1H 9Ah 2H 9Ah 2H 28h 3H 28h 3H 48h 6Bh SP 6Bh 48h 48h 出栈方向
PUSHA/PUSHAD 所有寄存器进栈 格式:PUSHA PUSHAD 操作: PUSHA: (286及其后继机型) 16位通用寄存器依次进栈,次序为: AX,CX , DX,BX,指令执行前的SP,BP,SI,DI 指令执行后 SP(SP)-16 仍指向栈顶 PUSHAD: (386及其后继机型, 32位汇编 ) 32位通用寄存器依次进栈,次序为:EAX,ECX, EDX,EBX,指令执行前的ESP,EBP,ESI,EDI 指令执行后 ESP(ESP)-32 仍指向栈顶
PUSHA指令示例 执行前 执行后 (DI) -16 (SI) -14 (BP) -12 (SP)原 -10 (BX) -8 (DX) -6 (CX) -4 (AX) -2 (SP)原
POPA/POPAD 所有寄存器出栈 格式:POPA POPAD 操作: POPA: (286及其后继机型) 16位通用寄存器依次出栈,次序为: DI,SI,BP,SP,BX,DX,CX , AX 指令执行后 SP(SP) +16 仍指向栈顶 POPAD: (386及其后继机型, 32位汇编 ) 32位通用寄存器依次出栈,次序为:EDI,ESI, EBP,ESP,EBX,EDX,ECX , EAX 指令执行后 ESP(ESP) +32 仍指向栈顶
XCHG 交换指令 格式:XCHG OPR1, OPR2 操作:(OPR1) (OPR2) 如: XCHG AX, BX ;寄存器之间交换 XCHG BX, [BP+DI] ;寄存器与存储器之间交换 XCHG [SI], DX 说明: 1)操作数不允许为段寄存器 2)两个操作数长度必须相同 3)本指令不影响状态标志位 4)两个操作数不能同时为存储器操作数
交换指令示例 XCHG DX, DATA[BP] 设(SS)=5000H, (BP)=0400H, DATA=1800H 物理地址=5000H×16+0400H+1800H=51C00H 执行前 执行后 DX DX 37CDH 51C00H 42H 51C00H 1H 6DH 1H 6D42H CDH 37H
XLAT查表指令(换码指令) 格式:XLAT TABLE 或 XLAT 操作:AL<--((BX)+(AL)) 或 AL((EBX)+(AL)) 将AL中的当前内容转换为表中某一种代码。执行前一定要将表(TABLE)的EA赋给BX(或EBX)寄存器,将代码在表中距首址的偏移放在AL寄存器中。 XLAT指令示例 TABLE 30H LEA BX, TABLE +1 31H ;表首址给BX +2 32H MOV AL, 4 +3 33H ;待转换内容到AL +4 34H XLAT +5 35H +6 36H +7 37H 34H AL
2、地址传送指令 LEA (load effective address) 有效地址送寄存器 LDS (load DS with pointer) 指针送寄存器和DS LES (load ES with pointer) 指针送寄存器和ES LFS (load FS with pointer) 指针送寄存器和FS LGS (load GS with pointer) 指针送寄存器和GS LSS (load SS with pointer) 指针送寄存器和SS
LEA 装载有效地址指令 格式: LEA DST, SRC 操作:DST<--SRC的有效地址EA 说明:SRC必须是存储器操作数,而DST则必须是一个16位或32位的通用寄存器(AX..DI..) LEA指令示例 设(DS)=2000H, (BX)=1234H LEA DI, [BX] MOV SI, [BX] 执行后 执行后 21234H 78H 5H 56H Offset只能返回标号的EA,不如LEA能返回任何寻址方式下的内存数据的EA 如:LEA AX,MYDAT[SI] 是对的,但是,mov AX, OFFSET MYDAT[SI]就是错的 SI 5678H SI 1234H 78H 56 BX 1234H 1234H
LEA DI, BUFFER ; 将变量BUFFER的 ; 有效地址送到DI, ;而不是将BUFFER ;变量的值送DI MOV DI, BUFFER ; 将变量BUFFER的 ; 有效地址送到DI, ;而不是将BUFFER ;变量的值送DI 执行后 执行后 SI 1234H SI 5678H BUFFER 21234H 1234H 78H 78H 5H 56 56
LDS 装载数据段指针指令 操作:DST(SRC) DS(SRC+2) 或 DS(SRC+4) LES 、LFS、LGS、LSS 格式:同LDS,目标分别是ES,FS,GS,和SS寄存器 说明: 1) 源操作数必须是存储器操作数 2) 目的操作数必须是寄存器 3) 完成一个逻辑地址的传送,该逻辑地址须用伪指令预先定义在当前数据段中
LDS指令示例 LDS DI, [BX] 设(DS)=2000H, (BX)=1000H 执行前 执行后 DI DI 7659H D645H H 45H H D6H H 00H H 50H DS DS 2000H 5000H 再比如:LDS BX, BUFF[SI] LDS DI, BUFF
LEA与LDS的区别 LEA SI, BUFF LDS DI, BUFF 设(DS)=2000H EABUFF=1000H 执行后: BUFF(21000H) 45H +1 D6H +2 00H +3 50H 设(DS)=2000H EABUFF=1000H 执行后: SI=1000H DI=D645H DS=5000H 不合法,SRC必须是存储器操作数 思考: LDS DI, BX是合法指令吗?
3、标志寄存器传送指令 LAHF(load AH with flags) 标志送AH SAHF(store AH into flags) PUSHF/PUSHFD(push the flags or eflags) 标志进栈 POPF/POPFD(pop the flags or eflags) 标志出栈
LAHF 标志寄存器送AH指令 SAHF 送标志寄存器指令 格式:LAHF 操作:AH<--FLAGS 7-0 操作:FLAGS 7-0<--(AH) 即将AH寄存器内容送FLAGS低8位 说明:1) 无操作数 2) FLAGS中含若干标志位,但LAHF指令本身不影响标志位
PUSHF/PUSHFD 标志进栈指令 格式:PUSHF PUSHFD 操作: PUSHF:SP<--(SP)-2 ((SP)+1,(SP))<--(FLAGS) 32位汇编 PUSHFD: (ESP)(ESP)-4 ((ESP)+3,(ESP)+2,(ESP)+1,(ESP)) (EFLAGS AND 0FCFFFFH) (清除VM和RF位) 说明:无操作数
POPF/POPFD 标志出栈指令 格式:POPF POPFD 操作: POPF:FLAGS<--((SP)+1,(SP)) 32位汇编 POPFD: EFLAGS((ESP)+3,(ESP)+2,(ESP)+1,(ESP)) ESP(ESP)+4
4、输入输出指令 IN(input) 输入 OUT(output) 输出
IN 输入指令 (从接口电路的端口输入数据) 格式1:IN AL, Port(字节) (Port是0-FFH的立即数) IN AX, Port(字) (Port是0-FFH的立即数) 32位汇编 IN EAX, Port(双字) (Port是0-FFH的立即数) 格式2:IN AL, DX (字节) IN AX, DX(字) 32位汇编 IN EAX, DX (双字) 操作: AL/AX/EAX<--(Port) 从外设读入字节或字或双字数据 AL/AX/EAX<--(DX) 以DX内容为端口地址,读入数据 说明:用Port指明8位端口地址时,地址范围为00H-FFH 以DX间接给出端口地址时,最大地址为0FFFFH
OUT 输出指令 (向接口电路的端口输出数据) 格式1:OUT Port, AL (字节) OUT Port, AX(字) 32位汇编 OUT Port, EAX(双字) 格式2:OUT DX, AL (字节) OUT DX, AX(字) OUT DX, EAX(双字) 操作: (Port)<--(AL)/(AX)/(EAX) 传送数据到Port端口 (DX)<--(AL)/(AX)/(EAX) 传送数据到DX指出的端口 说明:用Port指明8位端口地址时,地址范围为00H-FFH 以DX间接给出端口地址时,最大地址为0FFFFH
IN AX, 48H ;从端口48H读入字数据-->AX MOV DX, 3FCH IN AL, 20H ;从端口20H读入字节数据-->AL IN AX, 48H ;从端口48H读入字数据-->AX MOV DX, 3FCH IN EAX, DX ;从端口03FCH读入双字数-->EAX OUT指令示例 OUT 32H, AX ;传送字数据到32H端口 MOV DX,400H MOV AL, 86H OUT DX, AL ;传送字节数据到DX指出的端口
5、类型转换指令 CBW(convert byte to word) 字节转换为字 CWD/CWDE(convert word to double word) 字转换为双字 CDQ(convert double to quad) 双字转换为4字 BSWAP(byte swap) 字节交换
CBW 字节转换为字 CWD/CWDE 字转换为双字 格式:CBW 操作:扩展AL中的符号至AH中, 将8位数扩展成等效的16位数 操作:扩展AX中的符号至DX中,将16位数扩展成 等效的32位数 32位汇编 格式:CWDE 操作:AX的内容符号扩展到EAX 说明: 用于在符号数除之前,形成双倍长度的被除数
数据传送指令小结 1、数据传送指令不影响标志位(除SAHF) 2、除XCHG指令外,都是从源到目的的单向传送 3、注意MOV指令与 LEA指令的区别 4、堆栈的存取在16位指令中必须以字为单位, 在32位指令中必须以双字为单位 5、8086 不允许PUSH指令使用立即数寻址方式 如:PUSH 12 ;8086中不合法 但286及其后继机型中允许 6、POP 指令不允许使用立即数寻址方式, 不允许使用CS寄存器 例: POP 12 ;不合法 POP CS ;不合法
7、段寄存器只能在MOV、PUSH、POP 指令中作为操作数出现 例:MOV ES, AX PUSH CS POP DS 但下列指令不合法: MOV CS, reg POP CS 8、指令有多种格式,一般都遵循以下规则: 双操作数指令中不允许两个操作数均为存储器操作数 单操作数指令不允许立即寻址方式 目的操作数不允许使用立即寻址方式
3.2.2 算术运算指令 加法指令 ADD ADC INC XADD 减法指令 SUB SBB DEC NEG CMP CMPXCHG CMPXCHG8B 乘法指令 MUL IMUL 除法指令 DIV IDIV
算术运算指令可对4种类型操作数运算: 1、无符号二进制数 字节可表示范围:0----255 字可表示范围:0----65535 1、无符号二进制数 字节可表示范围:0----255 字可表示范围:0----65535 2、有符号二进制数 字节可表示范围:-128----+127 字可表示范围:-32768----+32767 3、非压缩十进制数 一个字节存放一位十制进数的BCD 码,高4位为0000。 例:十进数57表示为: 00000101 00000111 (0507H) 4、压缩十进制数 一个字节存放两位十进制数的 BCD码 例:十进数57表示为: 01010111 (57H)
以8位数加法为例讨论溢出 1、无符号数,有符号数都不溢出 无符号数 有符号数 04H 4 4 +0BH + 11 + 11 无符号数 有符号数 04H 4 4 +0BH + 11 + 11 0FH 15 15 CF=0 OF=0 2、无符号数溢出,有符号数不溢出 无符号数 有符号数 07H 7 7 +FBH +251 +(-5) 1 02H 258 +2 (>255) CF=1 OF=0 学时紧张的话可以直接给结论
3、有符号数溢出,无符号数不溢出 4、无符号数,有符号数都溢出 结论:OF——表示有符号数的溢出 CF——表示无符号数的溢出(进位) 无符号数 有符号数 09H 9 9 +7CH +124 +124 85H 133 133 (>127) CF=0 OF=1 4、无符号数,有符号数都溢出 87H 135 -121 +F5H +245 +( -11) 1 7CH 380 -132 (>255) (<-128) CF=1 OF=1 结论:OF——表示有符号数的溢出 CF——表示无符号数的溢出(进位)
ADD 常规加指令 格式:ADD DST, SRC 操作:DST<--(DST)+(SRC) 指令构成方式: ADD reg,imme ;寄存器与立即数相加 ADD reg,reg ;寄存器之间 ADD reg,mem ;寄存器加存储器操作数 ADD mem,imme ;存储器加立即数 ADD mem,reg ;存储器操作数加寄存器 说明:运行结果对CF、SF、OF、PF、ZF、AF都会影响
ADD指令示例1 ADD DX, BX 设(DX)=4652H, (BX)=0F0F0H 0100 0110 0101 0010 + 1111 0000 1111 0000 1 0011 0111 0100 0010 4652H + F0F0H 1 3742H 进位 进位 执行后 (DX)=3742H ZF=0 结果不为0 SF=0 结果为正 CF=1 有进位 OF=0 不溢出
ADD指令示例2 ADD WORD PTR[BX], 9F76H 设(DS)=2000H, (BX)=1000H 执行前: 21000 88H A988H A9H + 9F76H 1 48FEH 执行后: 21000 FEH CF=1 有进位 48H OF=1 溢出 ZF=0 结果不为0 SF=0 结果为正 进位
ADC 带进位加指令 INC 增1指令 格式:ADC DST, SRC 操作:DST<--(DST)+(SRC)+(CF) 说明:该指令除了多一个进位标志外,同ADD指令。 常用于多字节运算 INC 增1指令 格式:INC DST 操作:DST<--(DST)+1 说明: 1)DST可以是寄存器或存储器操作数 2)DST不允许是立即数 3)运行结果对SF、OF、PF、ZF、AF都会影响,但不影响CF
+ ADC指令示例——双字加法 设32位的目的操作数存放在DX和AX中,DX存放高位字,32位源操作数存放在BX和CX中,BX存放高位字 CF ADC ADD DX AX + BX CX DX AX 指令序列为: ADD AX, CX ;低位加 ADC DX, BX ;高位加
如:DX:AX=37A1FFFFH, 则DX:AX+1能否用: INC AX ADC DX,0 来实现? 执行前(DX)=0418H, (AX)=0F365H (BX)=1005H, (CX)=0E024H 0418H DX 0F365H AX 1005H BX + 0E024H CX + 1 CF 141EH DX 1D389H AX CF=1 不能,因为INC不影响CF 如:DX:AX=37A1FFFFH, 则DX:AX+1能否用: INC AX ADC DX,0 来实现?
8088中,执行INC BYTE PTR[BX]指令(指令已在指令队列中)需要 个总线周期。 2 LEA BX, ARRAY MOV AL, [BX] …… INC BX ARRAY a1 +1 a2 +2 a3 +3 a4 MOV BX, 0 MOV AL, ARRAY[BX] …… INC BX 先从内存中取出来是1个总线周期,加1后在存入内存又一个总线周期 8088中,执行INC BYTE PTR[BX]指令(指令已在指令队列中)需要 个总线周期。 2
SUB 常规减指令 格式:SUB DST, SRC 操作:DST<--(DST)-(SRC) 指令构成如下: SUB reg, imme ;寄存器减立即数 SUB reg, reg ;寄存器之间相减 SUB reg, mem ;寄存器减存储器操作数 SUB mem, imme ;存储器操作数减立即数 SUB mem, reg ;存储器操作数减寄存器 说明:运行结果对CF、SF、OF、PF、ZF、AF都会影响
SUB指令示例 SUB BX, CX 执行前: (BX)=9543H (CX)=28A7H 9543H - 28A7H 6C9CH 执行后: (BX)=6C9CH CF=0 OF=1 ZF=0 SF=0
SBB带进位减指令 格式:SBB DST, SRC 操作:DST<--(DST)-(SRC)-(CF) 说明:该指令除了多一个进位标志外,同SUB指令。 常用于多字节运算 SBB指令示例——双字减法 SUB AX, CX ;低16位减 SBB DX, BX ;高16位减 7456H AX 0012H DX - 9428H CX 0010H BX 1 E11EH - 1H CF 0001H CF=1
DEC 减1指令 NEG 求补指令 格式:DEC DST 操作:DST<--(DST)-1 说明:用法同INC指令 格式:NEG DST 操作:DST <-- -(DST) 说明:1)-(DST)表示操作数按位求反后末位加1。 2)执行时,用零减去操作数
NEG指令示例1 NEG DX 执行前: (DX)=6780H 0000 - 6780 1 9880 执行后: (DX)=9880H CF=1 借位 NEG指令示例2 NEG AL ;AL求补 ADD AL, 100 ;(AL)+100-->AL 实现的功能为: 100-(AL)
CMP 比较指令 格式 :CMP DST, SRC 操作:(DST)-(SRC) 说明: 1、两个操作数相减,但结果不回送 2、影响标志位的值,下一指令常是条件转移指令 3、必须区分无符号数比较与有符号数比较 如 比较 11111111B 与 00000000B 无符号数比较: 255 > 0 有符号数比较: -1 < 0 4、比较两数是否相等,根据标志位ZF判断 若相等,则ZF=1;否则ZF=0 5、指令构成同SUB指令
结论:用标志位CF判断无符号数的大小 CF=0,则 DST ≥ SRC CF=1,则 DST < SRC 比较两数的大小 CMP DST, SRC 1、无符号数比较 DST≥SRC DST<SRC DST=80H SRC=58H DST=58H SRC=80H 80H 58H -58H -80H 28H D8H CF=0 够减 CF=1 不够减 结论:用标志位CF判断无符号数的大小 CF=0,则 DST ≥ SRC CF=1,则 DST < SRC
(1)DST>0, SRC>0 (必不溢出,OF=0) DST=5AH, SRC=46H DST=46H, SRC=5AH 2、有符号数比较 (1)DST>0, SRC>0 (必不溢出,OF=0) DST=5AH, SRC=46H DST=46H, SRC=5AH 5AH 46H - 46H - 5AH 14H ECH SF=0, DST>SRC SF=1, DST<SRC (2)DST>0, SRC<0 (必有DST>SRC) DST=10H SRC=95H DST=62H SRC=95H 10H 62H - 95H - 95H 7BH CDH SF=0, OF=0 SF=1, OF=1 学时不够的时候直接给结论
(3)DST<0, SRC>0 (必有DST<SRC) DST=D3H SRC=38H DST=BFH SRC=55H D3H BFH - 38H - 55H 9BH 6AH SF=1, OF=0 SF=0, OF=1 (4)DST<0, SRC<0 (必不溢出,OF=0) DST=B5H SRC=9CH DST=9CH SRC=B5H B5H 9CH - 9CH - B5H 19H E7H SF=0, DST>SRC SF=1, DST<SRC 结论:用标志位SF和OF判断有符号数的大小 SF、OF值相同,则 DST>SRC SF、OF值不同,则 DST<SRC
CMP指令示例1 CMP AL, BL 令 (AL)= -64 (BL)=10 - 64 - 10 - 74 OF=0 SF=1 结论: (DST)<(SRC) CMP指令示例2 CMP CL, [100H] 令 (CL)= -100 (DS:100)= -110 -100 - (-110) 10 OF=0 SF=0 结论: (DST)>(SRC)
32位汇编 CMPXCHG 比较并交换指令 格式:CMPXCHG DST, SRC 操作:累加器AC与DST比较 如 (AC)=(DST) 则 ZF1,DST(SRC) 否则 ZF0,AC(DST) 说明:1) 只用于486及其后继机型 2) 累加器可为AL、AX或EAX寄存器 3) SRC只能用寄存器,DST可用寄存器或存储器寻址方式
CMPXCHG指令示例 CMPXCHG CX, DX (1)若 执行前(AX)=2300H,(CX)=2300H, (DX)=2400H 则 执行后 将 DX 复制到 CX: (CX)=2400H, ZF=1 (2)若执行前(AX)=2500H, (CX)=2300H, (DX)=2400H 则执行后将 CX 复制到AX: (AX)=2300H, ZF=0
MUL 无符号数乘指令 IMUL 有符号数乘指令 格式: MUL SRC 格式: IMUL SRC 操作: 字节数乘, AX<--(AL)×(SRC)byte 字数据乘, DX:AX<--(AX)×(SRC)word 32位汇编 双字数乘,EDX:EAX(EAX)×(SRC)DW 说明: 1)SRC可用寄存器或存储器寻址方式 2)无符号数乘与有符号数乘不同 如 (11111111B)×(11111111B) 无符号数乘: 255×255 有符号数乘: (-1)×(-1) 3)本指令影响标志位CF和OF
硬件上怎么判断有符号数乘法结果符号 MUL, IMUL指令示例 MUL BL (AL)=0B4H=180 IMUL BL (BL)=11H=17 IMUL BL (AL)=0B4H= -76, (BL)=11H=17 -76补=4CH 1011 0100 × 0001 0001 101111110100 0100 1100 × 0001 0001 0111 1100 0101 0000 1100 乘数与被乘数的符号位异或 (AX)=0BF4H=3060 (AX)=(-050C)补 =FAF4H= -1292 硬件上怎么判断有符号数乘法结果符号
格式:IMUL REG, SRC或IMM 操作:REG16(REG16)*(SRC或IMM) 32位汇编 REG32(REG32)*(SRC或IMM) 格式:IMUL REG, SRC, IMM 操作:REG16(SRC)*IMM 32位汇编 REG32(SRC)*IMM 说明:1)乘积的字长和源、目的操作数的字长一致 2)可能溢出 3)SRC可用寄存器或存储器寻址方式 REG只能是寄存器寻址方式 IMM是立即数 4)这些指令是80186后新增加的
DIV 无符号数除指令 IDIV 符号数除指令 格式:DIV SRC 格式:IDIV SRC 操作:AL(商), AH(余数)<--(AX)/(SRC)byte AX(商), DX(余数)<--(DX:AX)/(SRC)word 32位汇编 EAX(商), EDX(余数)<--(EDX:EAX)/(SRC)DW 说明: 1) 被除数的长度是指令中操作数的两倍 2) 源操作数可用除立即数以外的寻址方式 3) 如果SRC=0或者商大于存放商的寄存器的最大数值范围,都会引发“Divide error”错误。因此,当被除数为AX, DX:AX时,商最大是255和65535
DIV指令示例 MOV DX, 0001H MOV BX, 100H ;装入除数 DIV BX ;10000H/100H MOV AX, 0000H ;装入被除数 10000H MOV DX, 0001H MOV BX, 100H ;装入除数 DIV BX ;10000H/100H MOV N1, AX ;存商 MOV N2, DX ;存余数
IDIV指令示例 CBW ;字节扩充到字 MOV BL, 15 ;装入除数 IDIV BL ;-127/15 计算-127/15,商存入RESULT单元 MOV AL, -127 ;装入被除数(81H) CBW ;字节扩充到字 MOV BL, 15 ;装入除数 IDIV BL ;-127/15 MOV RESULT, AL ;存商
算术运算指令综合例 计算(V-(X*Y+Z))/X,其中X,Y,Z,V均为16位有符号数,要求商存入AX,余数存入DX MOV AX, X IMUL Y ; X*Y MOV CX, AX MOV BX, DX ;积存 BX, CX MOV AX, Z CWD ;Z扩展 ADD CX, AX ;X*Y+Z ADC BX, DX MOV AX, V CWD ;V扩展 SUB AX, CX ;相减 SBB DX, BX IDIV X ;除以X
为什么需要调整?BCD码的1010~1111是无意义的。 例:非压缩十进数6和7相加 0000 0110 + 0000 0111 + 0000 0111 0000 1101 + 110 ;调整 0001 0011 调整指令有两类: 1、非压缩BCD码调整指令 AAA AAS AAM AAD 2、压缩BCD码调整指令 DAA DAS
AAA 非压缩BCD码加调整 格式:AAA 操作:将AL中的两个非压缩BCD码的和 进行调整, 正确和在AX中 调整过程: 如果 (AL&0FH)>9 或 (AF)=1 则 (AL)+6-->AL (AH)+1-->AH 1-->AF, AF-->CF (AL)&0FH-->AL 否则 (AL)&0FH-->AL 0-->AF, (AF)-->CF 说明: 该指令放在二进制加法指令ADD之后
AAA指令示例 计算十进制数9+4 MOV AL, 9H 09H MOV BL, 4H + 04H ADD AL, BL 0DH ;>9 AAA + 06 H ;调整 13H & 0FH 03H (AH)+ 1-->AH 结果: (AH)=01H (AL)=03H CF=AF=1
AAA指令示例 计算十进制数9+9 MOV AL, 9H 09H MOV BL, 9H + 09H ADD AL, BL 12H ;AF=1 AAA + 06 H ;调整 18H & 0FH 08H (AH)+ 1-->AH 结果: (AH)=01H (AL)=08H CF=AF=1
AAS 非压缩BCD码减调整指令 格式:AAS 操作:将AL中的两个非压缩BCD码的差 进行调整,正确结果送AX中 调整过程: 如果 (AL&0FH)>9 或 (AF)=1 则 (AL)-6-->AL (AH)-1-->AH (AL)&0FH-->AL 1-->AF, AF-->CF 否则 (AL)&0FH-->AL 0-->AF, (AF)-->CF
(AH)-1-->AH AAS指令示例 计算十进制数16-7 MOV AX, 0106H 06H MOV BL, 7H - 07H SUB AL, BL FFH ; (AL)&0FH>9 AAS - 6 H ;调整 F9H & 0FH 09H (AH)-1-->AH 结果: (AL)=09H CF=AF=1 (AH)=00H
AAM 非压缩BCD码乘调整指令 格式:AAM 操作:将AX中的两个非压缩BCD码之积进行调整 调整过程: 将AL除以10, 商送AH, 余数送AL AAM指令示例 MOV AL, 07H ;取被乘数 MOV CL, 09H ;取乘数 0111 MUL CL × 1001 AAM ;调整 0111 0000 0111 00111111 调整后,(AH)=6 (AL)=3
AAD 非压缩BCD码除调整指令 格式:AAD 操作:在除法运算前,用该指令将AX中的非压缩BCD码形式的被除数调整为二进制数,然后做除法运算 调整过程: (AL)+(AH)×10-->AL 0-->AH (AX)/除数,商-->AL,余数-->AH
AAD指令示例 MOV AX, 0208H ;AX<--被除数 MOV CL, 4 ;除数 AAD ;调整,(AX)=28 DIV CL 结果:(AL)=7 (AH)=0
DAA 压缩的BCD码加调整 格式:DAA 操作:对AL寄存器中的压缩BCD码之和 进行调整 调整过程: 如果 (AL & 0FH)>9 或 (AF)=1 则(AL)+6-->AL 1-->AF 如果(AL)>9FH 或 (CF)=1 则(AL)+60H-->AL 1-->CF
DAA指令示例1 计算十进制数29+18 MOV AL, 29H 29H MOV BL, 18H + 18H ADD AL, BL 41H ;AF=1 DAA + 6 ; 调整 47H DAA指令示例2 计算十进制数54+63 MOV AL, 54H 54H MOV BL, 63H + 63H ADD AL, BL B7 H ;>9F DAA + 60H ; 调整 1 17H
DAS 压缩的BCD码减调整 格式:DAS 操作:对AL中的压缩BCD码差进行调整 调整过程: 如果 (AL&0FH)>9 或 (AF)=1 则 (AL)-6-->AL 1-->AF 如果(AL)>9FH 或 (CF)=1 则 (AL)-60H-->AL 1-->CF
DAS指令示例 计算十进数A-B A=4612 B=3576 MOV AL, A 12H SUB AL, B - 76H DAS 1 9CH ;AF,CF均=1 MOV D, AL - 66H ;所以用-66H调整 MOV AL, A+1 36H D SBB AL, B+1 CF=1 DAS MOV D+1, AL 46H 35H - 1 10H D+1 结果=1036
3.2.3 逻辑运算指令 逻辑非指令 NOT 逻辑与指令 AND 逻辑或指令 OR 逻辑异或指令 XOR 测试指令 TEST
NOT 逻辑非指令 格式: NOT OPR 操作: OPR按位取反后送回原处 说明:本指令不影响标志位 NOT指令示例1 NOT指令示例2 MOV AL, 52H NOT AL 执行前 AL 01010010 执行后 AL 10101101 NOT指令示例2 MOV AL, 1 ;1-->AL NOT AL ;求反 INC AL ; -1-->AL
AND 逻辑与指令 格式: AND DST, SRC 操作: (DST)<--(DST)&(SRC) 说明:本指令影响标志位PF、SF、ZF,使CF=0、OF=0 AND指令示例1 MOV AL , 32H AND AL, 0FH ;屏蔽高四位操作 执行前 AL 00110010 (2的ASCII码) 执行后 AL 00000010 AND指令示例2 AND AX, AX 执行后 AX内容不变, CF=0
OR 逻辑或指令 格式: OR DST, SRC 操作:(DST)<--(DST)或(SRC) 说明:本指令影响标志位PF、SF、ZF,使CF=0、OF=0 OR指令示例1 MOV AL, 02H OR AL, 0F0H ; 高四位置位 执行前 AL 00000010 执行后 AL 11110010 OR指令示例2 MOV AL, 02H OR AL, 30H 执行前 AL 00000010 执行后 AL 00110010 ;’2’的ASCII码
XOR 异或指令 格式: XOR DST, SRC 操作: (DST)<--(DST)与(SRC)按位异或 说明:本指令影响标志位PF、SF、ZF,使CF=0、OF=0 XOR指令示例1 MOV AL, 0B6H 1011 0110 XOR AL, 0FH 0000 1111 1011 1001 不变 变反 思考题的背景资料: 1.MOV AX, 0 ;在8088、286、386、486、Pentium中时钟数分别为: 4、3、2、1、1 指令长度 2字节 2.AND AX, 0 ;在8088、286、386、486、Pentium中时钟数分别为: 4、3、2、1、1 指令长度 3字节 3.XOR AX, AX ;在8088、286、386、486、Pentium中时钟数分别为:3、2、2、1、1 指令长度 2字节 4.SUB AX, AX ;在8088、286、386、486、Pentium中时钟数分别为:3、2、2、1、1 指令长度 3字节 5.MOV BL, 0; 在8088、286、386、486、Pentium中时钟数分别为: 4、3、2、1、1 指令长度 2字节 MUL BL ; 在8088、286、386、486、Pentium中时钟数分别为:143、21、38、42、11 指令长度 3字节 显然,使用XOR是合适的 XOR指令示例2 XOR AL, AL ;清零操作,且CF=0 思考:让AX寄存器清0,有几种办法,在X86不同的CPU中,哪种方案最好?
指令 时钟数 指令字节数 8088 286 386 486 Pentium MOV AX, 0 4 3 2 1 AND AX, 0 XOR AX, AX SUB AX, AX MOV BL, 0 MUL BL 143 21 38 42 11 1.MOV AX, 0 ;在8088、286、386、486、Pentium中时钟数分别为: 4、3、2、1、1 指令长度 2字节 2.AND AX, 0 ;在8088、286、386、486、Pentium中时钟数分别为: 4、3、2、1、1 指令长度 3字节 3.XOR AX, AX ;在8088、286、386、486、Pentium中时钟数分别为:3、2、2、1、1 指令长度 2字节 4.SUB AX, AX ;在8088、286、386、486、Pentium中时钟数分别为:3、2、2、1、1 指令长度 3字节 5.MOV BL, 0; 在8088、286、386、486、Pentium中时钟数分别为: 4、3、2、1、1 指令长度 2字节 MUL BL ; 在8088、286、386、486、Pentium中时钟数分别为:143、21、38、42、11 指令长度 3字节
TEST 测试指令 格式:TEST OPR1, OPR2 操作:(OPR1)&(OPR2) 说明:本指令影响标志位PF、SF、ZF,使CF=0、OF=0 TEST指令示例1 测试AL最低位是否为1,若是1则转移 TEST AL, 01H JNZ NEXT ;ZF=0转 TEST指令示例2 测试AX最高位是否为1,若不是1则转移 TEST AX, 8000H JZ THERE ;ZF=1转
3.2.4 移位指令 格式1:OP DST, CNT 操作1:对目的操作数移动CNT指定的次数, 移位结果送DST, 移出的位进入标志位CF 2)8086/8088中CNT为1或CL寄存器的内容,其他机型中CNT为1~31或CL寄存器的内容 32位汇编 格式2:OP DST, REG, CNT 操作2:对操作数DST和REG移动CNT指定的次数,移位后REG内容保持不变 说明:1)格式2用于双精度移位指令 2)格式2用于32位机器
3、双精度移位指令:SHLD——双精度左移 SHRD——双精度右移 移位指令有10条,分三类: 1、移位指令:SHL——逻辑左移 SHR——逻辑右移 SAL——算术左移 SAR——算术右移 2、循环移位指令:ROL——循环左移 ROR——循环右移 RCL——带进位循环左移 RCR——带进位循环右移 3、双精度移位指令:SHLD——双精度左移 SHRD——双精度右移
SHL/SAL 逻辑/算术左移 SHR 逻辑右移 SAR 算术右移 CF bn b0 bn b0 CF bn b0 CF
CF ROL 循环左移 RCL 带进位循环左移 ROR 循环右移 RCR 带进位循环右移 CF CF CF
已知(AL)=0B4H, (CF)=1, 分析下列指令执行后的结果 CF AL (1) SAL AL, 1 (2) SAR AL, 1 (3) SHL AL, 1 (4) SHR AL, 1 算术左移与逻辑左移的结果相同 算术右移与逻辑右移的结果不同 执行前 1 10110100 1 01101000 11011010 1 01101000 01011010
通常:算术右移N位相当于有符号数除以2N(有例外) 逻辑右移N位相当于无符号数除以2N 算术/逻辑左移N位相当于无符号数乘以2N 移位指令示例2 MOV CL, 5 SAR AL, CL 执行前 AL 01100000 (60H=96) 执行后 AL 00000011 (03H=3) 通常:算术右移N位相当于有符号数除以2N(有例外) 逻辑右移N位相当于无符号数除以2N 算术/逻辑左移N位相当于无符号数乘以2N 01100000 00000011 移位指令示例3 设(AX)=0012H, (BX)=0034H, 要求装配成(AX) = 1234H MOV CL, 8 ROL AX, CL ADD AX, BX 算术右移的例外是操作数为负数且最低位有1移出的时候,SAR指令产生的结果会与等效的IDIV指令的结果不同
移位指令示例4 已知变量Y中为一字节无符号数,计算(Y)*10, 积放在AX中。 变换:(Y)*10=(Y)*(8+2)=(Y)*2+(Y)*8 (为什么要这样变换?) MOV AL, Y ; AL<--(Y) MOV AH, 0 SHL AX, 1 ; (Y)*2 MOV BX, AX SHL AX, 1 ; (Y)*4 SHL AX, 1 ; (Y)*8 ADD AX, BX ; (Y)*10 思考题:利用移位指令计算DX=3×AX+7×BX
MOV AL, ASC+1 ;AL<--36H (‘6’) AND AL, 0FH ;AL<--06H 综合应用例1 将ASCII码转换成BCD码 如: ASC ‘9’ BCD ‘6’ 96H MOV AL, ASC ; AL<--39H (‘9’) MOV CL, 4 SHL AL, CL ;左移4位 39H->90H MOV BL, AL ;BL<--90H MOV AL, ASC+1 ;AL<--36H (‘6’) AND AL, 0FH ;AL<--06H OR BL, AL ;BL<--96H MOV BCD, BL
综合应用例2 分析下列指令序列的功能 MOV CL, 4 SHL DX,CL MOV BL, AH DX AX SHL AX, CL SHR BL, CL OR DL, BL 4 4 BL 4 结论: DX:AX双字左移4位
关于移位指令的几点说明: SHL与SHR均会影响OF、PF、SF、ZF、CF 如果SAL将DST的最高位移到CF,改变了CF的值,则OF=1。 循环移位指令操作结果只对CF和OF有影响,CF由移入CF的内容决定,OF取决于移位一次后符号位是否改变,如改变,则OF=1。
3.2.5 串操作指令 串——存储器中一序列字或字节单元,单元中的内 容是字符或数据 串操作——对序列字或字节单元中的内容进行某种 操作 串操作指令有7条: 1、MOVS——串传送指令 2、CMPS——串比较指令 3、SCAS——串扫描指令 4、LODS——装入串指令 5、STOS——存储串指令 6、INS——串输入 7、OUTS——串输出
说明: 每条指令有三种形式,分别对应于字节操作、 字操作和双字操作 如 MOVSB 字节操作 MOVSW 字操作 32位汇编 MOVSD 双字操作 与此配合使用的指令前缀有: REP 重复 REPE/REPZ 相等/为零则重复 REPNE/REPNZ 不相等/不为零则重复
目的区首偏址-->DI,串长-->CX 例:将字节串从源区传送到目的区 源区首偏址-->SI 目的区首偏址-->DI,串长-->CX Y CX=0 N 结束 按SI所指取一字节 按DI所指存此字节 (SI)+1-->SI 用一般传送指令实现 的流程图 (DI)+1-->DI (CX)-1-->CX
源区首偏址-->SI 目的区首偏址-->DI 串长-->CX,0-->DF 源区首偏址-->SI CX=0 Y 源区首偏址-->SI 目的区首偏址-->DI 串长-->CX,0-->DF CX=0 N 串传送指令 结束 带前缀REP的 串传送指令 (CX)-1-->CX 用串传送指令实现 的流程图 用带前缀的串传送指令实现的流程图
使用串操作指令时微处理器设计有若干约定: 1、源串地址由DS:SI指定 目的串地址在ES:DI中 2、串长送CX寄存器 3、设置方向标志位DF(在EFLAG寄存器中) 当DF=0(指令CLD)时为增量修改 (+1 或 +2 或 +4) 当DF=1(指令STD)时为减量修改 (-1 或 –2 或 -4)
方向标志对应的指针移动示意 正向传送 反向传送 DF=0 DF=1 低地址方向 ‘A’ ... 源串 ‘A’ ‘J’ … 1 n 源串 n 高地址方向 1 n 源串 n 1 ‘J’ ... 目的串 … 目的串 正向传送 反向传送 DF=0 DF=1
MOVS 串传送 ES:DI<--(DS:SI) REP SI<--(SI)(+/-)1 DI<--(DI)(+/-)1 符号 功能 操作 相关前缀 MOVS 串传送 ES:DI<--(DS:SI) REP SI<--(SI)(+/-)1 DI<--(DI)(+/-)1 CMPS 串比较 (DS:SI)-(ES:DI) REPZ/REPNZ SCAS 串扫描 (ES:DI)-(AL) REPZ/REPNZ LODS 装入串 AL<--(DS:SI) 一般不联用 STOS 存入串 (ES:DI)<--(AL) REP
INS 串输入 ES:DI((DX)) REP DI(DI)(+/-)1 OUTS 串输出 ((DX))(DS:SI) REP 符号 功能 操作 相关前缀 INS 串输入 ES:DI((DX)) REP DI(DI)(+/-)1 OUTS 串输出 ((DX))(DS:SI) REP SI(SI)(+/-)1 其中DX寄存器中存放的是接口电路的端口号
REPZ CX=0 或 ZF=0 CX<--(CX)-1,继续 REPE SI,DI指向下一元素 串未结束且串相等时继续 重复前缀 终止条件 否则 REP CX=0 CX<--(CX)-1,继续 SI,DI指向下一元素 REPZ CX=0 或 ZF=0 CX<--(CX)-1,继续 REPE SI,DI指向下一元素 串未结束且串相等时继续 REPNZ CX=0 或 ZF=1 CX<--(CX)-1,继续 REPNE SI,DI指向下一元素 串未结束且串不相等 时继续
例:REP MOVSB 传送过程如下: (1)(CX)=0? 若等于0,中止传送, 否则执行下一步 (2)CX(CX)-1 (3)串传送 (4)修改指针 (5)转到(1)
MOVS指令示例 MOV DI, 0100H ; (ES)=3000H MOV CX, 5 CLD REP MOVSB MOV SI, 0050H ; (DS)=2000H MOV DI, 0100H ; (ES)=3000H MOV CX, 5 CLD REP MOVSB 执行前 执行后 ‘A’ 20050 00 30100 ‘A’ 20050 ‘A’ 30100 ‘B’ 1 00 1 ‘B’ 1 ‘B’ 1 ‘C’ 2 00 2 ‘C’ 2 ‘C’ 2 ‘D’ 3 00 3 ‘D’ 3 ‘D’ 3 ‘E’ 4 00 4 ‘E’ 4 ‘E’ 4 ‘F’ 5 00 5 ‘F’ 5 00 5 源区 目的区 源区 目的区 SI=0050 DI=0100 SI=0055 DI=0105
串String1和String2分别定义在数据段和附加段中。 比较两串,如相等则转移到标号NEXT处。 CMPS指令示例 串String1和String2分别定义在数据段和附加段中。 比较两串,如相等则转移到标号NEXT处。 String1 DB ‘HELP’ ;定义String1 String2 DB ‘HEPP’ ;定义String2 …… CLD ;DF=0 LEA SI, String1 ;源串地址-->SI LEA DI, String2 ;目的串地址-->DI MOV CX, 4 ;重复次数-->CX REPZ CMPSB ;重复比较 JZ NEXT ;串相等转移 .... NEXT:
在串“That is CAI”中查找字符‘a’,找到,则转到标号FOUND处 SCAS指令示例 在串“That is CAI”中查找字符‘a’,找到,则转到标号FOUND处 String DB ‘That is CAI’ ;定义串 …… CLD ;DF=0 LEA DI, String ;串地址-->DI MOV AL, ‘a’ ;查找字符-->AL MOV CX, 11 ;重复次数-->CX REPNZ SCASB ;重复扫描 JZ FOUND ;找到目的串元素转移 FOUND:
比较SOURCE和DESTIN (串长度为100个字节),并将串中的第一个不匹配元素装入AL寄存器中。 LODS指令示例 比较SOURCE和DESTIN (串长度为100个字节),并将串中的第一个不匹配元素装入AL寄存器中。 …… LEA SI, SOURCE ;源串偏移量-->SI LEA DI, DESTIN ;目的串偏移量-->DI CLD ;DF=0 MOV CX,100 ;重复比较次数-->CX REPZ CMPSB ;重复串比较 JCXZ MATCH ;没有不匹配元素跳转 DEC SI ;指向不匹配元素 LODSB ;装入不匹配元素到AL ... MATCH:
给首地址为BUF,长度为1000个字节的存储器区域清零。 STOS指令示例 给首地址为BUF,长度为1000个字节的存储器区域清零。 BUFF DB 1000 DUP(?) ;定义缓冲区 …… CLD ;DF=0 LEA DI, BUFF ;缓冲区首地址-->DI MOV CX, 1000 ;重复次数 MOV AL, 0 ;0-->AL REP STOSB ;重复存储串
将存储区A到A+i中的数据传送到存储区B到B+i中,要求存放的顺序与原先的顺序相反。 综合应用例1 将存储区A到A+i中的数据传送到存储区B到B+i中,要求存放的顺序与原先的顺序相反。 B +1 +2 ‘b’ B+i ‘a’ A ‘a’ +1 ‘b’ +2 ‘c’ A+i
LEA SI, A LEA DI, B ADD DI, I ;DI指向存储区B的末尾 MOV CX, I+1 ;串的长度 LP: CLD ;DF=0 LODSB ;从源区取一数据 STD ;DF=1,改变方向 STOSB ;存入目的区 DEC CX JNZ LP
3.2.6 控制转移指令 循环指令 LOOP LOOPZ LOOPNZ 无条件转移指令 JMP 条件转移指令 子程序调用(返回)指令 CALL RET 中断指令 INT 条件设置指令
循环指令 格式:指令码 标号; (CX中存放循环次数) 操作符 操 作 功 能 LOOP CX<--(CX)-1 循环 若(CX)<>0,则循环 LOOPZ CX<--(CX)-1 当CX不为零且 LOOPE 若(CX)<>0且ZF=1,则循环 相等时循环 LOOPNZ CX<--(CX)-1 当CX不为零且 LOOPNE 若(CX)<>0且ZF=0,则循环 不相等时循环
循环指令示例1 求长度为10的字节数组ARRAY之和,并将和存入TOTAL中 LEA SI, ARRAY ;数组首地址-->SI MOV CX, 10 ;数组长度-->CX MOV AX, 0 AGAIN: ADD AL, [SI] ;求数组和 ADC AH, 0 INC SI ;修改指针 LOOP AGAIN MOV TOTAL, AX ;存和 其中 语句 LOOP AGAIN 相当于: DEC CX JNZ AGAIN
循环指令示例2 在某一字节串中寻找第一个非0字节 设串首地址在DI中,串末地址在BX中 SUB BX, DI ;串长度在BX中 INC BX MOV CX, BX ; 串字节数-->CX DEC DI AGAIN: INC DI ;修改指针 CMP BYTE PTR [DI], 0 ;串元素=0? LOOPZ AGAIN ;循环查找 JNZ FOUND ;找到非0字节跳转 …… FOUND:
综合运用例 有一个首地址为ARRAY的N字数组,将其中正数的个数放在DI中,0的个数放在SI中,负数个数放在AX中
MOV CX, N MOV BX, 0 ;初始化 MOV DI, BX ; 正数个数计数器初始化 MOV SI, BX ; 0的个数计数器初始化 AGAIN:CMP ARRAY[BX], 0 ;数组当前元素与0比较 JLE LEEQ ;小于等于0转移 INC DI ;正数计数 JMP NEXT LEEQ: JL NEXT ;小于0转移 INC SI ;0计数 NEXT: ADD BX, 2 ;数组表指针指向下一元素 LOOP AGAIN MOV AX, N ;负数个数=N-DI-SI SUB AX, DI SUB AX, SI
JMP 无条件转移指令 1、段内转移 格式1:JMP SHORT OPR ;段内直接短转移 操作1:IP<--(IP)+disp8 段内直接短转移示例 指令JMP SHORT ADDT 存放在CS:0200H 中, 标号ADDT对于IP指针的偏移量为1DH, 则转移地址为0202H+001DH=021FH JMP SHORT ADDT 0200 E8 … 1 1D ADDT: MOV AL, 40H 2 ADD AL, BL +1DH 021F B0 0220 1D
格式2:JMP OPR JMP NEAR PTR OPR ;段内直接近转移 操作2:IP<--(IP)+disp16 说明:转移范围-32KB至+32KB, 操作数OPR为段内某个标号。 格式3:JMP WORD PTR OPR ;段内间接转移 操作3:IP<--(OPR) 说明:OPR是基址/变址寄存器或存储器操作数。 段内间接转移示例 ADDRESS DW 2000H ;定义转移地址 ... LEA SI, ADDRESS ;偏移量-->SI JMP WORD PTR[SI] ;转移到CS:2000
格式4:JMP FAR PTR OPR ;段间直接转移 操作4:IP<--OAopr CS<--(CS)opr 2、段间转移 格式4:JMP FAR PTR OPR ;段间直接转移 操作4:IP<--OAopr CS<--(CS)opr C1段 EA OP码 段间直接转移示例 50 新IP=0250H ;代码段C1 02 …… 00 新CS=2000H JMP FAR PTR NEXT 20 …… ;代码段C2 C2段 20000H NEXT: MOV AL,10H … NEXT 20250H
格式5:JMP DWORD PTR OPR ;段间间接转移 操作5:IP<--((DS)*16+OPR) CS<--((DS)*16+OPR+2) 段间间接转移示例 JMP DWORD PTR [4000H] 设 (DS)=1000H (14000H)=0010H (14002H)=5000H 执行后 (CS)=5000H (IP)=0010H
说明: 386及其后继机型,用EIP代替IP
CALL 子程序调用指令 格式1: CALL 子程序名 ;段内直接调用 操作1: SP<--(SP)-2 ((SP)+1,(SP))<--(IP) IP<--(IP)+disp16 格式2:CALL reg/mem ;段内间接调用 操作2:SP<--(SP)-2 ((SP)+1,(SP))<--(IP) IP<--(reg) 或 IP<--(mem) 说明:1)类似于段内无条件转移指令,不同的是需要将返回地址IP入栈 2)也可以在子程序名前使用near ptr 前缀
格式3:CALL FAR PTR 子程序名 ;段间直接调用 操作3:SP<--(SP)-2 ((SP)+1,(SP))<--(CS) SP<--(SP)-2 ((SP)+1,(SP))<--(IP) IP<--子程序名对应的偏移量 CS<--子程序所在的段地址
格式4:CALL DWORD PTR mem ;段间间接调用 操作4: SP<--(SP)-2 ((SP)+1,(SP))<--(CS) IP<--(SP)-2 ((SP)+1,(SP))<--(IP) IP<--(EA) CS<--(EA+2) 说明:段间调用须保存返回地址IP和CS 386及其后继机型,用EIP代替IP
RET 子程序返回指令 格式 功能 操作 RET 段内返回 IP<--((SP)+1,(SP)) SP<--(SP)+2 格式 功能 操作 RET 段内返回 IP<--((SP)+1,(SP)) SP<--(SP)+2 RET 段间返回 IP<--((SP)+1,(SP)) CS<--((SP)+1,(SP)) RET EXP 带立即数返回 在上述操作之后再做 SP<--(SP)+EXP
CALL、RET指令示例 C1段 MAIN …… CALL FAR PTR PRO_A 0500:1000 C2段 PRO_A CALL NEAR PTR PRO_B 2000:2500 CALL NEAR PTR PRO_C 2000:3700 …... RET PRO_B …… CALL NEAR PTR PRO_C 2000:4000 RET PRO_C 转1 转2 转3
(1) MAIN调用PRO_A之前 2500 1000 0500 4000 SP (3) PRO_A调用PRO_B之后 0100 00FA (2) MAIN调用PRO_A之后 (4) PRO_B调用PRO_C之后 SP 00F8 00FC 1000 0500 转
(5) PRO_C返回PRO_B之后 SP 4000 2500 1000 0500 (6) PRO_B返回PRO_A之后 00FA (7) PRO_A调用PRO_C之后 SP 00FA 4000 3700 1000 0500 00FC 转
(8) PRO_C返回PRO_A之后 SP 00FC 4000 3700 1000 0500 (9) PRO_A返回MAIN之后 SP 4000 3700 1000 0500 0100 转
条件转移指令 格式:J条件 标号 操作:测试条件,若满足,则跳转到标号处执行, 即 IP<--(IP)+disp8 ; 否则,执行后续指令 说明:根据上一条指令所设置的条件码判别测试条件 转移范围在-128到+127字节
条件转移指令(1) 操作符 功能 测试条件 JC 进位标志为1转移 CF=1 JNC 进位标志为0转移 CF=0 JZ/JE 等于0/相等转移 ZF=1 JNZ/JNE 不等于0/不相等转移 ZF=0 JS 符号标志为1转移 SF=1 JNS 符号标志为0转移 SF=0 JO 溢出转移 OF=1 JNO 无溢出转移 OF=0 JP/JPE 偶状态转移 PF=1 JNP/JPO 奇状态转移 PF=0 JCXZ CX=0转移 CX=0 JECXZ ECX=0转移 ECX=0
条件转移指令(2) 比较情况 无符号数 有符号数 指令 判断条件 指令 判断条件 A>B JA ZF=0,CF=0 JG SF=OF JNBE JNLE 且 ZF=0 A>=B JAE ZF=1或 JGE SF=OF JNB CF=0 JNL 或ZF=1 A<B JB ZF=0,CF=1 JL SF<>OF JNAE JNGE 且ZF=0 A<=B JBE ZF=1或 JLE SF<>OF JNA CF=1 JNG 或ZF=1
条件转移指令示例1 将DAT字节单元中的数据变为偶数 TEST DAT, 01H ;测试数的奇偶性 JE NEXT ;若是偶数,转移 INC DAT ;是奇数,加1 NEXT: ……
条件转移指令示例2 将X中十六进制的ASCII码转换成其所对应的数值,存放到HEX中。如‘A’应转换为10。 注意ASCII中‘0’~‘9’是30H~39H,’A’~’F’是41H~46H MOV AH, X CMP AH, 39H JBE NEXT ;≤39H则转 SUB AH, 7 ;是‘A’--’F’,减7 NEXT: SUB AH, 30H ;减30H MOV HEX, AH
如果条件转移目标地址超出-128~+127的范围怎么办? 条件转移指令示例3 CMP AX, 0FFFFH JLE P3 CMP AX,1 JL P2 MOV AX, 1 JMP DONE P2: MOV AX, 0 P3: MOV AX,-1 DONE: Y AX≤(-1) N N Y AX<1 AX<--1 AX<--0 AX<--(-1) 如果条件转移目标地址超出-128~+127的范围怎么办?
中断指令 指令 格式 操 作 中断 INT N SP<--(SP)-2 ((SP)+1,(SP))<--(FLAGS) 指令 格式 操 作 中断 INT N SP<--(SP)-2 ((SP)+1,(SP))<--(FLAGS) SP<--(SP)-2 ((SP)+1,(SP))<--(CS) ((SP)+1,(SP))<--(IP) IP<--(0000:OA) ;OA=4*N CS<--(0000:OA+2) 中断返回 IRET IP<--((SP)+1,(SP)) SP<--(SP)+2 CS<--((SP)+1,(SP)) FLAGS<--((SP)+1,(SP))
常用的软件中断 中断号 功 能 10H 视频服务中断 13H 软硬盘控制中断 14H 串行口中断 15H 各种IO设备中断 16H 键盘中断 功 能 10H 视频服务中断 13H 软硬盘控制中断 14H 串行口中断 15H 各种IO设备中断 16H 键盘中断 17H 并行打印口中断 20H 返回DOS 21H DOS功能调用 23H Ctrl+Break处理 24H DOS严重错误 33H 鼠标中断 2FH 31H DOS保护方式接口 BIOS、DOS、自由中断的汇编调用方式: INT n ; n为中断向量号,如 INT 10H、INT 21H
常用的DOS系统功能调用 功能号 功能 入口参数 出口参数 01H 键盘输入 (AH)=1 (AL)=输入字符 02H 显示器输出 (AH)=2 无 (DL)=欲输出字符 09H 显示字符串 (AH)=9 无 (DS:DX)=字符串首址 字符串以‘$’结束 0AH 输入字符串 (AH)= 0AH (DS:DX)所指 (DS:DX)=输入缓 缓冲区中为 冲区首址 输入的字符串 4CH 返回调用 (AH)=4CH 无 进程
软中断调用的基本方法如下: 1、子功能号送AH寄存器; 2、按要求设置所有入口参数; 3、发送 INT n 软中断指令。 BIOS中断调用示例 设置屏幕显示方式为640×480 16色图形方式 MOV AH, 0 ; 子功能号 MOV AL, 12H ; 调用参数 INT 10H ; BIOS 的视频服务中断
BIOS中断调用示例 欲打印字符‘S’,相应的系统调用如下: MOV AH,1 ;初始化打印机子功能号 MOV DX,0 ;打印机号 INT 17H ;初始化打印机 MOV AH, 0 ;打印机子功能号 MOV DX, 0 ;打印机号 MOV AL, 'S' ;欲打印的字符 INT 17H ;打印‘S’
单个字符输入示例 INT 21H ;DOS功能调用 CMP AL, ‘Y’ ;比较 JZ ADDT MOV BX, X SUB BX, Y 读入一个字符,若是‘Y’,则Z<--X+Y;否则 Z<--X-Y MOV AH, 01H ;输入字符 INT 21H ;DOS功能调用 CMP AL, ‘Y’ ;比较 JZ ADDT MOV BX, X SUB BX, Y JMP NEXT ADDT: MOV BX, X ADD BX, Y NEXT: MOV Z, BX
单个字符输出示例 MSG DB ‘How are you!’,’$’ LEN EQU $-MSG ;$表示本语句的有效地址 MOV CX, LEN ;序列长度 MOV SI, 0 MOV AH, 02H ;输出一个字符 LP: MOV DL, MSG[SI] INT 21H INC SI ;修改指针 LOOP LP 字符串输出示例 MOV AX, SEG MSG MOV DS, AX LEA DX, MSG MOV AH,09H INT 21H 如何输出的更简单?
STRING DB N DUP(?) ;N个字符空间 …… MOV AH, 0AH LEA DX, MAXLEN INT 21H 说明: 字符串输入示例 该子功能调用前,在数据段中必须定义一个缓冲区: N EQU 20 MAXLEN DB N ;缓冲区最大长度 ACTLEN DB ? ;缓冲区实际字符个数 STRING DB N DUP(?) ;N个字符空间 …… MOV AH, 0AH LEA DX, MAXLEN INT 21H 说明: 1)缓冲区可接受的字符个数为1~255 2)缓冲区的第3个字节开始存放输入的字符,前2个字节位置分别放缓冲区长度和字符串实际字符数
3.2.7 处理器控制指令 1、标志处理指令 CLC —— 进位标志CF置0 CMC ——进位标志CF求反 STC —— 进位标志CF置1 CLD ——方向标志DF置0 STD —— 方向标志DF置1 CLI —— 中断标志 IF置0 STI —— 中断标志 IF置1
2、其他处理器控制指令 NOP —— 空操作 HLT —— 停机 WAIT —— 等待 ESC —— 换码 LOCK —— 封锁 BOUND——界限(286及其后继机型用) ENTER——建立堆栈帧(286及其后继机型用) LEAVE——释放堆栈帧(286及其后继机型用)