第3章 16位/32位微处理器指令系统 所谓指令,就是要求计算机执行各种特定操作的命令。微机能够识别和执行的全部指令集合称为该微机的指令系统。不同的微处理器所对应的指令系统也不相同。 按功能分,指令系统的指令一般分为数据传送类指令、算术运算类指令、逻辑运算与移位类指令、字符串处理类指令、控制转移类指令、处理器控制类指令等。本章首先给出指令的一般格式,然后介绍指令中操作数的寻址方式,最后详细分析各类指令的功能及其使用方法。 视频讲解 3.1指令的基本格式 3.1.1指令的构成 指令包括两部分内容: 一部分是表示操作性质或类型的编码——操作码; 另一部分是操作对象——操作数。具体构成与微处理器有关。 现以8086/8088机器指令为例,说明它的指令构成规则。该指令系统的指令由1~6字节组成,如图3.1所示。一般来说,第一字节(即图3.1中的字节1,下同)表示操作码,第二字节表示寻址方式,第三、四字节表示操作数在内存的位移量或者是立即数(在指令中没有位移量时),第五、六字节表示立即数。 图3.18086/8088指令构成 指令第一字节的7~2位为操作码,由该字段规定指令的操作类型。第一字节的1位为D位,由其指定操作数的传输方向。D=0,表示REG字段(第二字节的5~3位)给出的寄存器为源操作数寄存器,操作数应从这个寄存器中取得。D=1,表示REG字段给出的寄存器为目的操作数寄存器,运算结果应存放这个寄存器中。第一个字节的0位为W位。W位指出参加运算的操作数是字(16位)还是字节(8位)。W=0,表示参加运算的数是字节操作数; W=1,表示参加运算的数是字操作数。 指令的第二字节给出指令中使用的两个操作数存放在什么地方和存储器操作数的有效地址如何求得。第二字节的7、6位为MOD(方式)字段。由MOD给出指令中使用的两个操作数都是寄存器操作数,还是一个是寄存器操作数,而另一个是存储器操作数,如表3.1所示。 表3.1MOD字段编码 MOD 说明 00存储器方式,没有位移量 01存储器方式,有8位位移量 10存储器方式,有16位位移量 11寄存器方式(无位移量) 指令第二字节的5~3位为REG字段。REG字段给出指令中使用的一个操作数所在寄存器的编码。表3.2为寄存器编码。 表3.2REG字段编码 REG W=0 W=1 000ALAX 001CLCX 010DLDX 011BLBX 100AHSP 101CHBP 110DHSI 111BHDI 第二字节的2~0位称为R/M(存储器/寄存器)字段。R/M字段和MOD字段共同确定寻址方式。当MOD=11时为寄存器方式,由R/M字段给出第二个操作数所在的寄存器编码。当MOD≠11时为存储器寻址方式。R/M字段和MOD字段用来指出应如何计算存储器操作数的有效地址,如表3.3所示。 表3.3R/M和MOD字段编码及有效地址计算方法 存储器寻址方式MOD≠11 寄存器寻址方式MOD=11 R/M MOD=00 MOD=01 MOD=10 R/M W=0 W=1 000 (BX)+(SI) (BX)+(SI)+D8 (BX)+(SI)+D16 000 AL AX 001 (BX)+(DI) (BX)+(DI)+D8 (BX)+(DI)+D16 001 CL CX 010 (BP)+(SI) (BP)+(SI)+D8 (BP)+(SI)+D16 010 DL DX 011 (BP)+(DI) (BP)+(DI)+D8 (BP)+(DI)+D16 011 BL BX 100 (SI) (SI)+D8 (SI)+D16 100 AH SP 101 (DI) (DI)+D8 (DI)+D16 101 CH BP 110 16位直接寻址 (BP)+D8 (BP)+D16 110 DH SI 111 (BX) (BX)+D8 (BX)+D16 111 BH DI 指令中的第三~六字节根据不同的指令有不同的安排。一般由它们给出存储器操作数地址的位移量或立即操作数的值。指令中给出的位移量,可以是8位的也可以是16位的。一条指令中有一字节还是两字节的位移量由指令码中的MOD字段定义。8086系统规定,如果位移量为两字节,那么位移量的高位字节存放在高地址,低位字节存放在低地址。如果指令中有立即操作数,那么立即操作数位于位移量的后面。也就是如果三、四字节有位移量(LOWDISP、HIGHDISP),立即数就位于五、六字节(LOWDATA、HIGHDATA)。若指令中无位移量,立即数位于指令码的三、四字节。总之,指令中缺少的项要由指令后面存在的项向前顶替,以减少指令的长度。 上述介绍的是8086/8088指令构成的一般情况,在个别指令中也有例外的情况。 3.1.28086/8088的指令格式 指令格式是指令在源程序中的书写格式,其基本格式为: [标号:]操作码助记符目的操作数,源操作数 [;注释] [标号:]操作码助记符目的操作数 [;注释] 第一条格式为双操作数指令格式,第二条为单操作数指令格式; 方括号部分为可选项,可有可无。 其中,标号为该条指令所在内存单元的符号地址,后面要跟冒号。标号一般由字母开头,后跟字母、数字或特殊字符。注意,不允许使用保留字,例如MOV、SEGMENT、END等。 操作码助记符指示CPU执行什么样的操作。 操作数分目的操作数和源操作数两种,目的操作数是指令结果存放的位置,源操作数是指令操作的对象。目的操作数应放在源操作数前,并以逗号隔开。 注释用来说明本条指令或一段程序的功能,使程序可读性强。注释由分号(;)开始,汇编程序对其不进行处理。 3.28086/8088的寻址方式 一条汇编语言指令有两个问题需要关注: 一个是该条指令将进行什么操作; 另一个是操作的对象和操作后结果的存放位置。操作数的寻址方式就是指寻找操作数位置的方式。 1. 立即寻址 在8086指令系统中,有一部分指令所用的8位或16位操作数直接在指令中给出,故称为立即寻址。以这种寻址方式表示的操作数也简称立即数。 例如: MOV AL, 80H;将十六进制数80H送入AL MOV AX, 306AH;将十六进制数306AH送入AX,其中AH中为30H ;AL中为6AH 立即数可以为8位,也可以为16位。但规定立即数只能作为源操作数。 立即寻址方式常用于给寄存器赋值,操作数直接在指令中取得,不需要使用另外的总线周期,故执行时间短、速度快。 2. 寄存器寻址 如果操作数在CPU的内部寄存器中,那么可在指令中指出该寄存器名,这种寻址方式称为寄存器寻址。 对于8位操作数来说,寄存器可以是 AH、AL、 BH、BL、CH、CL、DH、DL。 对于16位操作数来说,寄存器可以是AX、BX、CX、DX、SI、DI、SP、BP等。 例如: MOVAL, BL ;将BL的内容传送到AL中 MOVBX, AX ;将AX的内容传送到BX中 采用寄存器寻址的指令在执行时,操作数就在CPU中,不需要访问存储器来取得操作数,执行速度快。另外寄存器名比内存地址短,指令所占内存空间少。 3. 直接寻址 通常把操作数的偏移地址称为有效地址(Effective Address,EA),EA可通过不同的寻址方式得到。 在直接寻址方式中,指令中直接给出操作数的有效地址。注意,如果用数字形式提供有效地址,可在指令中直接给出16位有效地址并加方括号([]),但必须加上段前缀,以便和立即数相区分。 例如: MOV AX, DS:[1000H];若 (DS) = 2000H,则将数据段21000H ;21001H两个单元的内容送到AX中 如果有效地址是以符号地址形式提供的,则可不加方括号。 例如: MOV AX,BUFA BUFA为符号地址,这时可不加跨段前缀,默认为DS数据段。如果BUFA变量在附加段中,就必须书写如下: MOV AX,ES: BUFA 需要说明的是,有些宏汇编程序规定,指令中直接给出的是16位常量的有效地址时也默认操作数在DS数据段,这时可以不加段前缀DS。 例如,MOV AX,DS: [1000H]可写为MOV AX,[1000H]。 4. 寄存器间接寻址 操作数在存储器中,操作数有效地址存放在指定寄存器中,被用来存放操作数的有效地址的寄存器称为间址寄存器。间址寄存器必须是BX、BP、SI和DI之一。 书写时,该寄存器必须加方括号。如果没有加方括号,则为寄存器寻址。 当指令中使用BX、SI和DI作间址寄存器时,默认操作数在数据段中; 如果使用BP做间址寄存器,则默认操作数在堆栈段中,否则应该加段前缀。 例如: MOVAX, [BX];若(DS) = 2000H,(BX) = 1000H,则将数据段21000H ;21001H两个单元的内容送到AX中 MOVCX, [BP];若(SS) = 4000H,(BP) = 1000H,则将堆栈段41000H ;41001H两个单元的内容送到CX中 MOVAX, ES:[SI] ;若(ES) = 3000H,(SI) = 1000H,则将附加段31000H ;31001H两个单元的内容送到AX中 5. 基址寻址和变址寻址 操作数在存储器中,操作数的有效地址是基址寄存器或变址寄存器的内容与指令中指定的8位或16位位移量之和。可以选用 BX、BP作为基址寄存器,选用SI、DI作为变址寄存器。指令中使用BX、SI和DI时,默认操作数在数据段中; 指令中使用BP寄存器时,则默认操作数在堆栈段中。可以用段前缀来改变默认段基址。 例3.1MOV AX,[SI+3000H]的执行结果。 设(DS)=4000H,(SI)=2000H,内存单元(45000H)=34H,(45001H)=12H。 首先求操作数的物理地址: 物理地址=(DS)×16+(SI)+3000H=40000H+2000H+3000H=45000H 然后根据该物理地址从内存得到操作数,也即内存单元45000H、45001H的内容。将该内容送入AX,故(AX)=1234H。 6. 基址变址寻址 操作数在存储器中,操作数的有效地址是一个基址寄存器和一个变址寄存器内容以及8位或16位位移量三者之和,两个寄存器均由指令指定。可以选用 BX、BP作为基址寄存器; 选用SI、DI作为变址寄存器。如果选用BX做变址寄存器,则默认操作数在数据段中,如果选用BP做变址寄存器,则默认操作数在堆栈段中。也可以用段前缀来改变默认段基址。 例如: MOV AX, 8[BX+SI];默认操作数在数据段中 MOV BX, -6[BP+DI] ;默认操作数在堆栈段中 MOV BX, ES:[BP+DI];操作数在附加段中 基址变址寻址方式适用于表格或数组的存取,可以将表格或数组的首地址放入基址寄存器中,将表格或数组中的数据的相对位移放在变址寄存器中,灵活实现表格或数组中数据的存取。 7. 固定寻址 固定寻址又称隐含寻址,指令码中不包含指明操作数地址的部分,而其操作码本身隐含地指明了操作数地址。例如,十进制数调整指令DAA,该指令的功能是AL寄存器的内容进行十进制调整,调整后的内容仍放入AL中。DAA指令没有书面指明AL,而是将AL隐含在操作码中,也就是说只要是DAA指令,它的操作数就一定在AL中。这样的指令还有很多,例如乘法指令、除法指令和换码指令等。 3.38086/8088的指令系统 8086/8088指令系统中包含133条基本指令,如果考虑其中寻址方式的组合,以及数据类型(字节或字),则可构成上千条指令。 8086/8088的指令分以下几类: ①数据传送类指令; ②算术运算类指令; ③逻辑运算与移位类指令; ④串操作类指令; ⑤控制转移类指令; ⑥处理器控制类指令。 在学习过程中,要正确理解每条指令的助记符、寻址方式、数据类型,并理解指令对标志位的影响,掌握每条指令的功能及其使用注意事项,奠定第4章汇编语言程序设计的基础。 3.3.1数据传送类指令 视频讲解 数据传送指令包括通用数据传送指令、标志寄存器传送指令、目标地址传送指令、输入输出指令等。它们的功能是用于控制数据在计算机各部分之间的传送。具体可实现寄存器与存储器之间、寄存器与外设端口之间以及寄存器与寄存器之间的数据传送等。它们的共同特点是不影响标志寄存器的内容。 为了方便叙述和学习,本章符号约定如下。 OPD: 表示目的操作数(8/16位)。 OPS: 表示源操作数(8/16位)。 1. 通用数据传送指令 通用数据传送指令包括MOV指令、XCHG指令、XLAT指令、PUSH指令与POP指令。 1) MOV指令 格式: MOVOPD,OPS MOV指令是形式简单但使用最多的指令,它可以完成CPU内寄存器之间、寄存器与存储器之间的数据传送,还可以将立即数送入寄存器或内存。 例如: MOVAL, BL ;将寄存器BL的内容传送到寄存器AL中 MOV[DI], AX ;将寄存器AX的内容传送到DI和DI+1所 ;指的内存字单元中 MOVCX, DS:[1000H];将数据段中偏移地址1000H和1001H单元的 ;内容送到CX中 MOVBL, 40;将立即数40传送到寄存器BL中 MOV指令在使用时应该注意以下几点。 (1) 立即数、CS和IP不能作为目的操作数,CS和IP的内容不能任意改变,程序是通过转移指令来修改CS和IP的内容。 (2) 两个段寄存器之间不能相互传送数据。确要传送,可以参考下面方法: MOVAX,DS MOVES,AX (3) 两个存储单元之间不能直接传送。确要传送,可以参考下面方法: MOVAX,[SI] MOV[DI],AX (4) 不能将立即数直接传送到段寄存器。 如 MOVDS,2000H为错误指令,可以通过以下两条指令实现: MOVAX, 2000H MOVDS, AX (5) MOV指令的两个操作数的类型和长度必须一致。例如下列指令是错误的,书写时应该注意: MOVAX, BL;类型不一致 MOVAL, 256;长度不一致 例3.2试用MOV指令实现数据段中偏移地址2035H和2045H两内存字节单元内容的交换。 (1) 用直接寻址方式实现。 MOV BL, DS:[2035H] MOV CL, DS:[2045H] MOV DS:[2045H], BL MOV DS:[2035H], CL (2) 用寄存器间接寻址方式实现。 MOV SI, 2035H MOV DI, 2045H MOV AH, [SI] MOV AL, [DI] MOV DS:[2035H], AL MOV DS:[2045H], AH 2) XCHG指令 格式: XCHG OPD,OPS 功能: 交换操作数OPD、OPS的值,即OPDOPS,操作数的类型可以为字节或字。交换只能在通用寄存器之间、通用寄存器与存储器之间进行。 例如: XCHGAX,BX;AX 和BX寄存器的内容互换 XCHGAX,[SI];AX和数据段中SI所指字单元的内容互换 3) XLAT指令 格式: XLAT或XLAT 表首址 功能: 使AL中的值变换为内存表格中的对应值。它是一条隐含寻址方式的指令,将数据段内有效地址为(BX)+(AL)的内存字节单元中数据送入AL。该指令常用来查表,即将表头地址赋予BX,再将需求的表内位移地址赋予AL,最后运用XLAT指令即可以将该地址处的表值送到AL。 例3.3在内存数据段中偏移地址1000H处存放了如图3.2所示的字节类型的数据表,则换码指令可如下列使用方法。 … ;省略 MOVBX, 1000H;BX中填写表格的起始地址 MOVAL, 03H;表内位移地址赋予AL XLAT 图3.2字节类型的数据表 上述指令执行后结果为: (AL)=0CH。 4) PUSH指令与POP指令 这两条指令是堆栈操作指令。所谓堆栈,是以先进后出管理的一段存储区域,常用于子程序调用和中断处理过程。为了能够在子程序返回或中断返回后,程序继续使用子程序调用前或中断发生前各通用寄存器的内容,就必须在子程序或中断程序开始处保护子程序执行过程中要改变的寄存器(包括标志寄存器)的值(称为保护现场),然后在子程序结束前或中断返回前再恢复这些寄存器的值(称为恢复现场)。 堆栈的存取操作都发生在栈顶,而堆栈指针SP一直指向堆栈的栈顶。每执行一个PUSH指令,SP的内容减2; 每执行一个POP指令,SP的内容加2。 (1) 入栈指令PUSH。 格式: PUSH OPS 功能: 修改指针,(SP)-2→SP, 将OPS指明的寄存器、段寄存器或存储器中的一个字数据压入堆栈的顶部。 例3.4假设在指令执行前,(SP)=1000H; (AX)=1234H。 PUSHAX 指令执行后,12H被压入堆栈段偏移地址为0FFFH单元,34H被压入堆栈段偏移地址为0FFEH单元,栈顶指针(SP)=0FFEH。 PUSH指令在使用时应该注意: ① 源操作数只能是16位的,而不能是8位的,例如PUSHAL就是错误的。 ② 源操作数不能为立即数。 (2) 出栈指令POP。 格式: POP OPD 功能: 将栈顶的一个字数据送至OPD指明的寄存器、段寄存器(CS除外)或存储器中; 修改指针,(SP)+2→SP。 例3.5假设在指令执行前,(SP)=0FFEH,(BX)=2004H,并且堆栈段栈顶(0FFEH)单元内存放34H,(0FFFH)单元内存放12H。 POPBX 指令执行后,1234H被弹出放入BX中,栈顶指针(SP)=1000H。 POP指令在使用时应该注意: ① 目的操作数只能是16位的,而不能是8位的。 ② 立即数、CS不能作为目的操作数。 2. 标志寄存器传送指令 1) 取标志寄存器指令 格式: LAHF 功能: 将标志寄存器FR的低8位送入AH中。 2) 设置标志寄存器指令 格式: SAHF 功能: 将AH内容送入标志寄存器FR的低8位。 3) 标志进栈指令 格式: PUSHF 功能: 将16位标志寄存器FR内容进栈保存。 4) 标志出栈指令 格式: POPF 功能: 将当前栈顶两字节内容弹出送到标志寄存器FR中。 3. 目标地址传送指令 1) 取偏移地址指令LEA 格式: LEAOPD,OPS 功能: 将源操作数的偏移地址送到目的操作数。该指令不影响标志位,源操作数必须是存储器操作数,目的操作数必须是16位通用寄存器。 例如: LEASI,TABLE; TABLE为存储器操作数的符号地址 该指令等效于MOV SI,OFFSET TABLE(OFFSET取偏移地址算符,详见第4章)。 例如: LEAAX,[SI] 该指令等效于MOV AX,SI指令,与MOV AX,[SI] 指令的效果不同,注意区别。 2) 传送偏移地址及数据段首址指令LDS 格式: LDSOPD,OPS 功能: 从源操作数所指定的存储单元中取出某变量的地址指针(共4字节),将低地址两字节(偏移量)送到目的操作数,将高地址两字节(段首址)送到DS中。该指令对标志位不影响,源操作数是双字类型存储器操作数,目的操作数必须是16位通用寄存器。 例3.6设数据段中某双字存储单元的偏移地址为3000H,双字数据为12345678H。 LDSSI,DS:[3000H] 上述指令执行后,(DS)=1234H,(SI)=5678H。 3) 传送偏移地址及附加段首址指令LES 格式: LESOPD,OPS 功能: 从源操作数所指定的存储单元取出某变量的地址指针(共4字节),将低地址两字节(偏移量)送到目的操作数,将高地址两字节(变量的段首址)送到ES中。 4. 输入输出指令 输入输出指令用于完成输入输出端口与累加器(AL/AX)之间的数据传送,指令中给出输入输出端口的地址。 1) 输入指令IN 格式: INOPD,OPS 功能: 从端口OPS(地址为n或在DX中)输入8位数据到AL或输入16位数据到AX。 例如: INAL, 40H;从40H端口读入一字节送入AL IN AX, 80H ;从80H端口读入一字节送入AL,从81H端口 ;读入一字节送入AH MOVDX, 8F00H;将端口地址8F00H送入DX IN AL, DX;从8F00H端口读入一字节送入AL 2) 输出指令OUT 格式: OUTOPD,OPS 功能: 从AL输出8位数据或从AX输出16位数据到端口(地址为n或在DX中)。 例如: OUT40H, AL ;将AL内容送入40H端口 OUT80H, AX ;将AL内容送入80H端口,将AH的内容送入81H端口 MOVDX, 8F00H;将端口地址8F00H送入DX OUT DX, AL;将AL内容送入8F00H端口 输入输出指令在使用应该注意以下两点。 (1) 输入输出指令对标志寄存器没有影响。 (2) 端口地址大于255时,必须用DX指定端口地址。 3.3.2算术运算类指令 视频讲解 在8086/8088指令系统中,具有完备的加、减、乘和除运算,可以完成有符号和无符号8位/16位二进制数的算术运算,以及BCD码表示的十进制数的算术运算。 1. 加法指令 1) 不带进位加法指令ADD 格式: ADDOPD,OPS 功能: 将源操作数和目的操作数相加,结果存入目的操作数,即OPS+OPD→OPD。 影响标志位CF、AF、PF、SF、OF和ZF。 2) 带进位加法指令ADC 格式: ADCOPD,OPS 功能: 将源操作数和目的操作数相加,并加上CF的值,结果存入目的操作数,即OPS+OPD+CF→OPD。影响标志位CF、AF、PF、SF、OF和ZF。 ADC指令常用于多字的加法。 例3.7将X1(56781234H)、X2(9F887AB4H)相加,结果存入SUM(低字在前,高字在后)。 DSEGSEGMENT X1DW 1234H,5678H X2DW 7AB4H,9F88H SUMDW 0,0,0 DSEGENDS … MOVAX, X1 ADDAX, X2 ;低字加用ADD指令 MOVSUM, AX MOVAX, X1+2 ADCAX, X2+2;高字加用ADC指令 MOVSUM+2, AX MOVAX, 0 ADC AX, 0 ;处理相加发生进位情况 MOVSUM+4, AX 3) 加1指令 格式: INCOPD 功能: 将目的操作数OPD的内容加1,并将结果回送到目的操作数。影响标志位AF、PF、SF、OF和ZF,但不影响CF标志。 例如: INCAX ;AX中内容加1,结果送回AX INCBL;BL中内容加1,结果送回BL INCBYTE PTR [SI];将SI所指内存字节单元内容加1,并回存 2. 减法指令 1) 不带借位的减法指令SUB 格式: SUBOPD,OPS 功能: 目的操作数减去源操作数,结果回送到目的操作数,即OPD-OPS→OPD,结果影响标志位CF、AF、PF、SF、OF和ZF。 例如: SUBBX,CX; BX的内容减去CX的内容,结果送入BX 2) 带借位的减法指令SBB 格式: SBBOPD,OPS 功能: 目的操作数减去源操作数,再减去CF的值,结果回送到目的操作数,即OPD-OPS-CF→OPD,结果影响标志位CF、AF、PF、SF、OF和ZF。 例如: SBB[SI], AL;SI所指字节单元内容减AL的值,再减CF ;结果存回原内存单元 3) 减1指令 格式: DECOPD 功能: 将目的操作数OPD的内容减1,并将结果回送到目的操作数。影响标志位AF、PF、SF、OF和ZF,但不影响CF标志。 例如: DECAX ;AX的内容减1,结果送回AX DECCL;CL的内容减1,结果送回CL 4) 比较指令CMP 格式: CMPOPD,OPS 功能: 目的操作数OPD减去源操作数OPS,结果不送回。但影响标志位CF、AF、PF、SF、OF和ZF。 例如: CMPAL,09H;将AL的内容和09H比较,结果影响标志位 可以根据标志位的变化,来判断比较结果。 通过ZF的值来判断两数是否相等。若ZF=1,则说明两数相等; 否则,两数不等。 通过CF、OF和SF的变化来判断无符号数或有符号数的大小: (1) 对于无符号数,如果CF=0,则目的操作数比源操作数大; 如果CF=1,则目的操作数比源操作数小。 (2) 对于有符号数,如果OF=SF,则目的操作数比源操作数大; 如果OF≠SF,则目的操作数比源操作数小。 5) 求补指令 格式: NEGOPD 功能: 由目的操作数OPD求补,将其结果送回目的操作数。需要注意的是,它实际做0-OPD→OPD运算。影响标志位CF、AF、PF、SF、OF和ZF。 例3.8 MOVAL, 05H NEG AL ;(AL)=0FBH,CF=1 MOVAL, -05H NEG AL ;(AL)=05H,CF=1 3. 乘法指令 1) 无符号数乘法指令 格式: MULOPS 功能: 字节乘法,(AL)×(OPS)→AX。 字乘法,(AX)×(OPS)→(DX,AX)。 例如: MULBL 指令执行前,(AL)=0B4H=180,(BL)=11H=17。 指令执行后,(AX)=0BF4H=3060,CF=1,OF=1。 MUL指令在使用时应该注意: ① OPS不能是立即数。例如,MUL 20H 为错误指令。 ② MUL指令影响CF、OF标志,不影响SF、ZF、AF和PF。对于字节乘法,若AH≠0,也即AH存在有效位,则CF=1,OF=1; 否则CF=0,OF=0。对于字乘法,若DX≠0,也即DX存在有效位,则CF=1,OF=1; 否则CF=0,OF=0。 2) 有符号数乘法指令 格式: IMULOPS 功能: 字节乘法: (AL)×(OPS)→AX。 字乘法: (AX)×(OPS)→(DX,AX)。 例如: IMULBL 指令执行前,(AL)=0B4H=-76,(BL)=11H=17。 指令执行后,(AX)=0FAF4H =-1292,CF=1,OF=1。 IMUL指令在使用时应该注意的内容参见MUL指令。 4. 符号扩展指令 1) 字节扩展为字指令 格式: CBW 功能: 将AL的内容从字节扩展为字,存放到AX中。若AL中数据的最高位为0,则(AH)=00H; 若AL中数据的最高位为1,则(AH)=0FFH。该指令不影响标志位。 例3.9 MOVAL, -7 CBW 执行后,(AX)=0FFF9H。 2) 扩展为双字指令 格式: CWD 功能: 将AX的内容从字扩展为双字,存放到DX、AX中。若AX中数据的最高位为0,则(DX)=0000H; 若AX中数据的最高位为1,则(DX)=0FFFFH。该指令不影响标志位。 例3.10 MOV DX, 0 MOV AX, 0FFABH CWD 指令执行后,(DX)=0FFFFH; (AX)=0FFABH。 5. 除运算指令 1) 无符号数除法指令 格式: DIVOPS 功能: 字节除法,(AX)/(OPS)→AL(商),AH(余数)。 字除法,(DX,AX)/(OPS)→AX(商),DX(余数)。 例3.11 DSEGSEGMENT A DW0400H B DW00B4H C DW? D DW? DSEGENDS 在以上数据段定义的基础上,求无符号数 A/B,商放入C,余数放入D。 … MOVAX, A MOVDX, 0 DIV B MOVC, AX MOVD, DX DIV指令在使用时应该注意: ① OPS不能是立即数。 ② 除法指令不影响标志位,除0会导致结果溢出,产生溢出中断。 2) 有符号数除法指令 格式: IDIVOPS 功能: 字节除法,(AX)/(OPS)→AL(商),AH(余数)。 字除法,(DX,AX)/(OPS)→AX(商),DX(余数)。 例3.12以下指令序列实现了有符号除法-4001H/4。 MOVAX, -4001H CWD MOVCX, 4 IDIVCX 结果: (AX)=0F000H; (DX)=0FFFFH。 6. 十进制调整指令 上述算术运算指令都是二进制运算指令,如何利用它们来进行BCD 码十进制运算?一般方法是: 首先对BCD码表示的十进制数进行二进制运算,然后再使用调整指令对运算结果进行调整,得出正确的BCD码表示的十进制运算结果。下面分别介绍这些调整指令。 1) 加法的BCD码调整指令 (1) 压缩的BCD码调整指令。 格式: DAA 功能: 将AL中二进制加法运算的结果调整为两位压缩BCD码,结果仍保留在AL中。 调整的方法: 若AL的低4位大于9,则AL的内容加06H,并AF位置1; 若AL的高4位大于9,则AL的内容加60H,并CF位置1; 若AF=1,则低4位要加6; 若CF=1,则高4位要加6。 例3.13 MOVBL, 35H MOVAL, 85H ADDAL, BL DAA 上述指令序列执行后,(AL)=20H,CF=1,AF=1。 (2) 非压缩的BCD码调整指令。 格式: AAA 功能: 将AL 中二进制加法运算结果调整为一位非压缩BCD码,调整后的结果仍保留在AL中,如果向高位有进位(AF=1,CF=1),AH的内容加1。 调整的方法: 若AL的低4位大于9或AF=1,则自动将AL的内容加06H,AH内容加1并置AF=CF=1,将AL的高4位清0; 若AL的低4位小于或等于9,则仅将AL的高4位清0,并且AF→CF。 例3.14两个BCD码数(AX)=0807H、(BX)=0905H,要求将(AX)+(BX)的结果存放 到BCDBUF开始的单元(低字节在前)。 PUSH AX;暂存AX MOV AH, 0 ;AH清0 ADD AL, BL;低字节直接相加 AAA;调整 MOVBCDBUF, AL ;存放和的低字节 POP AX ;恢复AX MOVAL, AH MOVAH, 0;AH清0 ADCAL, BH ;带进位的加法 AAA;调整 MOVBCDBUF+1, AL ;存放和的高字节 MOVBCDBUF+2, AH ;存放和的高字节的进位 DAA、AAA指令在使用时应该注意: ① DAA、AAA指令一般是紧跟在ADD或ADC指令后使用,单独使用没有意义。 ② 调整指令只对AL的内容进行调整,故在调整前,务必保证待调整结果出现在AL中。 2) 减法的BCD码调整指令 (1) 压缩的BCD码调整指令。 格式: DAS 功能: 将AL中二进制减法运算的结果调整为两位压缩BCD码,结果仍保留在AL中。 调整的方法: 若 AF=1或AL的低4位大于9,则自动(AL)-06H→AL,1→AF; 若 CF=1或AL的高4位大于9,则自动(AL)-60H→AL,1→CF。 例3.15 SUBAL, BL ;先使用二进制减运算指令 DAS;在使用调整指令,可得BCD码运算结果 (2) 非压缩的BCD码调整指令。 格式: AAS 功能: 将AL 中二进制减法运算结果调整为一位非压缩BCD码,如果有借位,则保留在CF中。 调整的方法: 若AL的低4位大于9或AF=1,则自动将AL的内容加06H,AH内容减1并置AF=CF=1,将AL的高4位清0; 若AL的低4位小于或等于9,则仅将AL的高4位清0,并且AF→CF。 DAS、AAS指令在使用时应注意点可参考加法调整指令。 3) 乘法的非压缩BCD码调整指令 格式: AAM 功能: 将AL 中二进制乘法运算结果调整为两位非压缩BCD码,高位放在AH,低位放在AL。影响标志位PF、SF和ZF。该指令必须紧跟在MUL之后,且被乘数和乘数必须用非压缩的BCD码表示。 例3.16 ANDAL, 0FH ;确保被乘数为非压缩的BCD码 ANDBL, 0FH ;确保乘数为非压缩的BCD码  MULBL AAM 4) 除法的非压缩BCD码调整指令 格式: AAD 功能: 用在两位非压缩的BCD码相除之前,将AX内容调整为二进制数。 例3.17 MOV CL, 08H ;送非压缩BCD码除数,由于二进制数也是08H ;没有用调整指令,否则也要调整 MOV AX, 0309H;送非压缩BCD码被除数 AAD ;调整被除数为二进制数 DIVCL ;结果商和余数为二进制数 视频讲解 3.3.3逻辑运算与移位类指令 1. 逻辑运算指令 逻辑运算指令包括“非”“与”“测试”“或”“异或”指令,可以对字或字节按位进行逻辑运算。 1) 非运算指令 格式: NOTOPD 功能: 将目的操作数的内容按位取反后,再送回目的操作数。该指令不影响标志位。 例如: NOTAX 执行前: (AX)=0AAAAH。 执行后: (AX)=5555H。 2) 与运算指令 格式: ANDOPD,OPS 功能: 将目的操作数的内容与源操作数按位相与,结果送回目的操作数。影响标志位SF、ZF、PF,使OF=0,CF=0,对AF无定义。 例如: ANDAL,0FH 执行前: (AL)=39H。 执行后: (AL)=09H。 AND指令常用于屏蔽不需要的位,上例中将AL高4位屏蔽,取得低4 位。 3) 测试指令 格式: TESTOPD,OPS 功能: 将目的操作数的内容与源操作数按位相与,但结果不送回目的操作数。影响标志位SF、ZF、PF,使OF=0,CF=0,对AF无定义。 例如: TESTAL,80H 执行前: (AL)=39H。 执行后: ZF=1。 该指令可以用于判断目的操作数的某个数位是否为1,上例中可以根据ZF=1,判断出AL内容的最高位为0。 4) 或运算指令 格式: OROPD,OPS 功能: 将目的操作数的内容与源操作数按位相或,结果送回目的操作数。影响标志位SF、ZF、PF,使OF=0,CF=0,对AF无定义。 例如: ORAX,55H 执行前: (AX)=0749H。 执行后: (AX)=075DH。 该指令常用来将目的操作数的某一位或几位置1。 5) 异或运算指令 格式: XOROPD,OPS 功能: 将目的操作数的内容与源操作数按位异或,结果送回目的操作数。影响标志位SF、ZF、PF,使OF=0,CF=0,对AF无定义。 例如: XORAX,0101H 执行前: (AX)=0749H。 执行后: (AX)=0648H。 由于某个操作数和同一个数异或结果为0,故异或运算常被用来比较两数是否相等或初始化某数为0。 2. 移位指令 这组指令可以对字节或字中的各位进行算术移位和逻辑移位。移位次数可以是1,也可以大于1。若移位次数大于1,必须将次数预先放入CL。也就是说,移位指令中的移位次数的源操作数只能是1或CL。这组指令影响除AF以外的各个标志位。 图3.3移位指令操作过程 1) 算术左移指令 格式: SALOPD,OPS 功能: 根据源操作数OPS中的移位次数,将目的操作数的内容连续进行左移操作,每次高位进入CF,最低位补0,如图3.3(a)所示。 例3.18 MOVCL, 3 SALAL, CL 执行前: (AL)=01H。 执行后: (AL)=08H,CF=0。 无符号数的算术左移一位相当于目的操作数乘以2。 2) 逻辑左移指令 格式: SHLOPD,OPS 功能: 与算术左移指令SAL完全相同。 3) 算术右移指令 格式: SAROPD,OPS 功能: 根据源操作数OPS中的移位次数,将目的操作数的内容连续进行右移操作,每次低位进入CF,最高位用移位前的值填补,如图3.3(b)所示。 例如: SARBH,CL 执行前: (BH)=84H,(CL)=2。 执行后: (BH)=0E1H,CF=0。 4) 逻辑右移指令 格式: SHROPD,OPS 功能: 根据源操作数OPS中的移位次数,将目的操作数的内容连续进行右移操作,每次低位进入CF,最高位补0,如图3.3(c)所示。 例如: SHRAL,CL 执行前: (AL)=9AH,(CL)=4。 执行后: (AL)=09H,CF=1。 3. 循环移位指令 8086/8088指令系统中有4条循环移位指令,其中2条为不带进位的循环移位指令,另2条为带进位的循环移位指令。源操作数OPS的循环移位次数的设置和移位指令相同。这组指令只影响CF、OF标志位。 1) 循环左移指令 格式: ROLOPD,OPS 功能: 根据源操作数OPS中的移位次数,将目的操作数的内容连续进行循环左移操作,如图3.4(a)所示。 例如: ROLDL,CL 执行前: (DL)=0FAH,(CL)=4。 执行后: (DL)=0AFH,CF=1。 2) 循环右移指令 格式: ROROPD,OPS 功能: 根据源操作数OPS中的移位次数,将目的操作数的内容连续进行循环右移操作,如图3.4(b)所示。 例如: RORAL,1 执行前: (AL)=0FAH。 执行后: (AL)=07DH,CF=0。 3) 带进位的循环左移指令 格式: RCLOPD,OPS 功能: 根据源操作数OPS中的移位次数,连续对目的操作数的内容带CF循环左移操作,如图3.4(c)所示。 4) 带进位的循环右移指令 格式: RCROPD,OPS 功能: 根据源操作数OPS中的移位次数,连续对目的操作数的内容带CF循环右移操作,如图3.4(d)所示。 图3.4循环移位指令的操作过程 例3.19有一无符号32位二进制数存放在DX、AX中,其高16位在DX中,低16位在AX中,以下指令序列实现对该数的除2操作。 SHR DX, 1 RCR AX, 1 循环移位指令常用于按位检查某单元的内容或实现某单元的半字或半字节互换等。 3.3.4串操作类指令 视频讲解 字符串是指存储器中顺序存放、类型相同的字节或字的序列。串操作是指对串中每个元素都执行同样的操作,如串传送、比较以及查找等。规定一个字符串的长度最长不能超过64KB,字符串常设置在数据段或附加段中。 串操作指令约定源串存放在数据段,并必须用SI提供源串的偏移地址; 目的串存放在附加段,并必须用DI提供目的串的偏移地址; 当方向标志DF=0,地址指针SI、DI自动增加1(字节串)或2(字串),当方向标志DF=1,地址指针SI、DI自动减少1(字节串)或2(字串)。串操作指令前不加重复前缀,串操作只执行一次。如果重复执行串操作,可以用CX存放重复的次数,每重复执行一次,CX内容减1。当CX内容减为0时,串操作停止。 在介绍串操作指令前,首先介绍和串操作指令配合使用的几个重复前缀指令。 1. 重复指令前缀 1) 无条件重复前缀 格式: REP 功能: 用于一个串操作指令的前缀,每重复执行一次串操作指令,CX的内容减1,直到(CX)=0 为止。 执行步骤如下: (1) 先判断CX的内容,如(CX)=0,则串操作停止,否则执行第(2)步; (2) (CX)-1→CX; (3) 执行其后的串操作指令,转第(1)步。 2) 相等/为零重复前缀 格式: REPE 功能: 用于一个串操作指令的前缀,每重复执行一次串操作指令,CX的内容减1,直到(CX)=0 或ZF=0为止。 执行步骤如下: (1) 先判断CX的内容,如(CX)=0或ZF=0,则串操作停止,否则执行第(2)步; (2) (CX)-1→CX; (3) 执行其后的串操作指令,转第(1)步。 3) 不相等/不为零重复前缀 格式: REPNE 功能: 用于一个串操作指令的前缀,每重复执行一次串操作指令,CX的内容减1,直到(CX)=0 或ZF=1为止。 执行步骤如下: (1) 先判断CX的内容,如(CX)=0或ZF=1,则串操作停止,否则执行第(2)步; (2) (CX)-1→CX; (3) 执行其后的串操作指令,转第(1)步。 2. 数据字节串/字串传送指令 格式: MOVSB/MOVSW 功能: 将数据段中由(DS:SI)指向的源串的一字节(字)传送到附加段由(ES:DI)指向的目的串中,且相应修改地址指针,使其指向下一字节(字)。 字节串: 当DF=0时,(SI)+1→SI,(DI)+1→DI; 当DF=1时,(SI)-1→SI,(DI)-1→DI。 字串: 当DF=0时,(SI)+2→SI,(DI)+2→DI; 当DF=1时,(SI)-2→SI,(DI)-2→DI。 例3.20将内存单元首地址3100H起的100字节传送到首地址2800H的内存单元。 CLD MOVSI, 3100H MOVDI, 2800H MOVCX, 100 REP MOVSB 3. 数据字节串/字串比较指令 格式: CMPSB/CMPSW 功能: 将数据段中由(DS:SI)指向源串的一字节(字)减去附加段由(ES:DI)指向的目的串的一字节(字),不回送结果,只根据结果影响标志位,并相应修改地址指针,使其指向下一字节(字)。 字节串: 当DF=0时,(SI)+1→SI,(DI)+1→DI; 当DF=1时,(SI)-1→SI,(DI)-1→DI。 字串: 当DF=0时,(SI)+2→SI,(DI)+2→DI; 当DF=1时,(SI)-2→SI,(DI)-2→DI。 例3.21检查内存单元首地址2200H起的50字节与首地址3200H起的50字节是否对应相等,如果相等,则BX=0; 如果不相等,BX指向第一个不相等的字节单元。AL存放第一个不相等的源串内容。 CLD MOVSI, 2200H MOVDI, 3200H MOVCX, 50 REPECMPSB JZ LP1 DEC SI MOVBX, SI MOVAL, [SI] JMP LP2 LP1:MOVBX, 0 LP2: 4. 数据字节串/字串检索指令 格式: SCASB/SCASW 功能: 将AL(AX)的内容减去附加段由(ES:DI)指向的目的串的一字节(字),不回送结果,只根据结果影响标志位,并相应修改地址指针,使其指向下一字节(字)。 字节串: 当DF=0时,(DI)+1→DI; 当DF=1时,(DI)-1→DI。 字串: 当DF=0时,(DI)+2→DI; 当DF=1时,(DI)-2→DI。 例3.22在内存附加段首地址为4300H起的100字节中,查找是否有*,如果有,则将偏移地址送入BX,否则BX=0。 CLD MOVDI, 4300H MOVAL, '*' REPNZSCASB JNZ LP1 DECDI MOVBX, DI;找到"*",偏移地址送入BX JMPLP2 LP1:MOV BX, 0 ;未找到 LP2: 5. 数据字节串/字串读出指令 格式: LODSB/LODSW 功能: 将数据段中由(DS: SI)指向源串的一字节(字)读出,放入AL(AX)中,并相应修改地址指针,使其指向下一字节(字)。 字节串: 当DF=0时,(SI)+1→SI; 当DF=1时,(SI)-1→SI。 字串: 当DF=0时,(SI)+2→SI; 当DF=1时,(SI)-2→SI。 6. 数据字节串/字串写入指令 格式: STOSB/STOSW 功能: 将AL(AX)的内容写入附加段中由(ES:DI)指向的目的串一字节(字)中,并相应修改地址指针,使其指向下一字节(字)。 字节串: 当DF=0时,(DI)+1→DI; 当DF=1时,(DI)-1→DI。 字串: 当DF=0时,(DI)+2→DI; 当DF=1时,(DI)-2→DI。 例3.23将内存数据段首地址为1800H起的100字节清0。 CLD MOVDI, 1800H MOVCX, 100 XORAL, AL REPSTOSB 3.3.5控制转移类指令 视频讲解 一般情况下指令是顺序地逐条执行的,但实际上程序不可能总是顺序执行,而经常要改变程序的执行流程。这里介绍的控制转移指令就是用来控制程序的执行流程的。程序执行顺序的改变实际是通过修改代码段寄存器CS和指令指针IP的内容来实现的。 8086有5种类型的转移指令,它们是无条件转移、条件转移、循环控制、子程序调用及返回和与中断有关的指令。 1. 无条件转移指令 无条件地转移到指令指定的地址去执行从该地址开始的指令。无条件转移可以分为段内转移和段间转移。具体有以下5种基本格式。 1) 段内直接短转移 格式: JMPSHORT 目标标号 功能: 无条件地转移到标号所指定的目标地址去执行程序。短转移时,目标地址与JMP指令的下一条指令地址之差为-128~+127字节。 2) 段内直接转移 格式: JMP目标标号 JMPNEAR PTR目标标号 功能: 无条件地转移到标号所指定的目标地址去执行程序,但转移的范围扩大到-32768~+32767字节,也即跳转地址的范围为16位带符号二进制数的范围。 3) 段内间接转移 格式: JMPWORD PTR OPD 功能: 无条件转移到OPD所指定的目标地址去执行程序。OPD只能是16位寄存器或两个连续存储的内存字节单元。转移范围为64KB。 例如: JMPDX 执行前: (DX)=2000H,(IP)=1260H,(CS)=3000H。 执行后: (IP)=2000H,CPU转到地址为32000H的单元执行程序。 4) 段间直接转移 格式: JMPFARPTR 目标标号 功能: 无条件转移到目标标号所指定地址去执行程序。将目标标号所在的段基址送入CS,将目标标号相对所在段的段内偏移地址送入IP。可以转移范围为1MB。 5) 段间间接转移 格式: JMPDWORDPTROPD 功能: 无条件转移到目的操作数OPD所指定地址去执行程序。目的操作数为双字,将目的操作数的第一个字送入IP,将目的操作数的第二个字送入CS。可以转移范围为1MB。 例如: JMPDWORDPTR[BX] 执行前: (BX)=2000H,(DS)=5000H,(52000H)=0200H,(52002H)=0400H。 执行后: (IP)=0200H,(CS)=0400H,CPU转到地址为04200H的单元执行程序。 2. 条件转移指令 测试上一条指令对标志位的影响,从而决定程序执行的流程。若满足条件则转移; 若不满足条件则顺序执行。注意,转移范围都只有-128~+127字节,如果需要转移的地址超出了该范围,可以将条件转移指令与无条件转移指令配合使用。所有条件转移指令对标志位均无影响。 1) 单标志位转移指令 单标志位条件转移指令如表3.4所示。 表3.4单标志位条件转移指令 指令 测试条件 含义 指令 测试条件 含义 JZ/JE ZF=1 0/相等则转移 JNZ/JNE ZF=0 非0/不相等则转移 JP/JPE PF=1 低8位中1的个数为偶数则转移 JS SF=1 结果为负则转移 JNS SF=0 结果非负则转移 JNP/JPO PF=0 低8位中1的个数为奇数则转移 JO OF=1 结果溢出则转移 JC CF=1 有进位则转移 JNO OF=0 结果不溢出则转移 JNC CF=0 无进位则转移 例3.24运用条件转移指令,判断AX的内容,如果(AX)=04H,则设置CX为0,否则设置CX为0FFFFH。 MOVBX, 04H CMPAX, BX JZ LP1 LP2: MOVCX, 0FFFFH JMP LP3 LP1: MOVCX, 0 LP3: 2) 无符号数的条件转移指令 该组转移指令用于无符号数的比较,并根据比较的结果进行转移。具体无符号数的条件转移指令如表3.5所示。 表3.5无符号数的条件转移指令 指令 测 试 条 件 说明(A,B两数关系) JA/JNBE CF=0 ∧ ZF=0 高于/不低于且不等于(即A>B)则转移 JAE/JNB CF=0 ∨ ZF=1 高于等于/不低于(即A≥B)则转移 续表 指令 测 试 条 件 说明(A,B两数关系) JB/JNAE CF=1 ∧ ZF=0 低于/不高于且不等于(即A<B)则转移 JBE/JNA CF=1 ∨ ZF=1 低于等于/不高于(即A≤B)则转移 例3.25以下指令完成判断AL的内容,如果低于60,则进行AL内容加5的操作。 CMPAL, 60 JAE LP1 ADDAL, 5 LP1: 3) 有符号数的条件转移指令 该组转移指令用于有符号数的比较,并根据比较的结果进行转移。具体转移指令如表3.6所示。 表3.6有符号数的条件转移指令 指令 测 试 条 件 说明(A,B两数关系) JG/JNLE SF=OF ∧ ZF=0 大于/不小于且不等于(即A>B)则转移 JGE/JNL SF=OF ∨ ZF=1 大于或等于/不小于(即A≥B)则转移 JL/JNGE SF≠OF ∧ ZF=0 小于/不大于且不等于(即A<B)则转移 JLE/JNG SF≠OF∨ ZF=1 小于或等于/不大于(即A≤B)则转移 例3.26 MOVAL, -40H;0C0H→AL CMPAL, 50H JGLP1 ; -40H <50H不转移 MOVCX, 0FFFFH JMP LP2 LP1: MOVCX, 0 LP2: 以上指令序列执行后,(CX)=0FFFFH。注意,指令序列中的JG若改为JA,CX的内容则为0。 4) 测试CX条件转移指令 格式: JCXZ目标标号 功能: 若(CX)=0,则转移到目标标号所指定地址去执行程序。 3. 循环控制指令 8086/8088指令系统有三条循环控制指令,一般用它们来实现程序循环,循环的次数必须放在CX寄存器中,这组指令也不影响标志位。 1) 计数循环指令 格式: LOOP标号 功能: 每执行一次LOOP指令,CX的内容减1,若CX≠0,则循环转移到标号所指定的目标地址去重复执行程序,直到CX=0,退出循环,接着执行LOOP指令的下一条指令。 例3.27以下为使用LOOP指令编写的延时程序段。 MOVCX, 0100H;设置循环次数 DELAY:LOOPDELAY LOOP指令执行转移时,用9个时钟周期,结束循环指向下一条指令时,用5个时钟周期,程序员可以设置循环次数来控制延迟的时间。 2) 相等/为零计数循环指令 格式: LOOPE/LOOPZ标号 功能: 每执行一次循环指令,CX的内容减1,若CX≠0且ZF=1,则循环转移到标号所指定的目标地址去重复执行程序,否则执行循环指令的下一条指令。 3) 不相等/不为零计数循环指令 格式: LOOPNE/LOOPNZ标号 功能: 每执行一次循环指令,CX的内容减1,若CX≠0且ZF=0,则循环转移到标号所指定的目标地址去重复执行程序,否则执行循环指令的下一条指令。 4. 子程序调用和返回指令 在8086/8088指令系统中,调用子程序或从子程序返回的指令分别为CALL和RET。 1) 子程序调用指令 (1) 段内直接调用。 格式: CALL标号 功能: 首先将返回地址(CALL指令的下一条指令,16位偏移地址)压入堆栈,然后将标号所指的子程序在本段中的偏移地址送入IP,转子程序执行。 (2) 段内间接调用。 格式: CALLWORDPTROPD 功能: 首先将返回地址(CALL指令的下一条指令,16位偏移地址)压入堆栈,然后将目的操作数的内容送入IP,转至同一段内的子程序执行。 (3) 段间直接调用。 格式: CALLFARPTR标号 功能: 首先将断点地址CS、IP顺序压入堆栈(共4字节),然后将标号所在的段基址送入CS,将标号相对所在段的偏移地址送入IP,转子程序执行。 (4) 段间间接调用。 格式: CALLDWORDPTROPD 功能: 首先将断点地址CS、IP顺序压入堆栈(共4字节),然后将有效地址指定的4字节送入IP、CS,低地址的两字节送入IP,高地址的两字节送入CS,转子程序执行。 2) 返回指令 子程序的最后一条指令为返回指令,用来控制程序返回断点地址处(相应CALL指令的下一条指令)继续执行下去。 (1) 返回指令。 格式: RET 功能: 把断点地址从堆栈弹出送入IP或IP、CS。如果该子程序为FAR类型,首先从堆栈弹出一个字送入IP(SP+2→SP),再从堆栈弹出一个字送入CS(SP+2→SP); 如果该子程序为NEAR类型,从堆栈弹出一个字送入IP(SP+2→SP),从而返回主程序。 (2) 带弹出值的返回指令。 格式: RETn 功能: n为偶数,在执行RET指令后,再修改指针SP+n→SP,也即先从堆栈弹出断点地址送IP或IP、CS,再废除栈顶的n字节。 CALL和RET指令在使用应该注意以下几方面。 ① CALL和RET指令不影响标志位。 ② CALL和RET指令必须成对使用,与无条件转移指令的不同之处,在于它含有将断点地址入栈和出栈的操作。 5. 中断和中断返回指令 中断和中断返回指令能使CPU暂停执行后续指令,而转去执行相应的中断服务程序或从中断服务程序返回主程序。 1) 软中断指令 格式: INTn 功能: n为中断类型码,可以取0~0FFH的256个值。每个中断类型码在中断矢量表中占4字节,前2字节用来存放中断服务程序入口地址的偏移地址,后2字节用来存放段基址。CPU执行INT指令时,首先将标志寄存器FR 压栈,接着清除IF、TF,然后将当前程序断点的段基址和偏移地址入栈保护,最后将中断矢量表中与中断类型码对应的4字节内容先后送入IP、CS,这样CPU转去执行中断服务程序。 2) 中断返回指令 格式: IRET 功能: 放在中断服务程序的出口处,由它从堆栈中弹出程序断点分别送IP、CS,并弹出一个字送入标志寄存器FR,以退出中断,返回到断点处执行后续程序。 中断服务程序的最后一条指令必须是IRET。 3) 溢出中断指令 格式: INTO 功能: 该指令为单字节指令,中断类型码为4,放在有符号的算术运算指令之后,仅当运算产生溢出(OF=1)时,才向CPU发出溢出中断请求。 3.3.6处理器控制类指令 1. 标志位操作指令 1) 进位位清0指令 格式: CLC 功能: 置CF=0。 2) 进位位求反指令 格式: CMC 功能: CF←CF。 3) 进位位置1指令 格式: STC 功能: 置CF=1。 4) 关中断指令 格式: CLI 功能: 置IF=0,禁止外部可屏蔽中断。 5) 开中断指令 格式: STI 功能: 置IF=1,允许外部可屏蔽中断。 6) 方向标志清0指令 格式: CLD 功能: 置DF=0。 7) 方向标志置1指令 格式: STD 功能: 置DF=1。 2. 外部同步指令 1) 空操作指令 格式: NOP 功能: 不执行任何操作,其机器码占1字节。 2) 暂停指令 格式: HLT 功能: 该指令执行后,使机器暂停工作,使处理器处于停机状态,以等待一次外部中断到来,中断结束后,程序继续执行,处理器继续工作。 3) 交权指令 格式: ESC 功能: 协处理器在系统加电工作后,就不断检测CPU是否需要协助工作,当发现ESC指令时,被选定的协处理器便开始工作。 4) 等待指令 格式: WAIT 功能: 该指令每隔5个时钟周期就测试一次TEST信号,若该信号为高电平,CPU则继续执行WAIT指令,进入等待状态; 否则结束等待,执行后续指令。 3.480386的寻址方式和指令系统 3.4.180386的寻址方式 80386的寻址方式和8086一样,包括立即寻址、寄存器寻址、直接寻址和寄存器间接寻址。但是由于80386的存储器组织方式和8086有差别,故寄存器间接寻址有别于8086。 按照80386系统的存储器组织方式,逻辑地址由段选择子和偏移量组成。偏移量由以下4个分量计算得到。 ① 基址。任何通用寄存器都可以作为基址寄存器,其内容即为基址。 ② 位移量。在指令操作码后面的32位、16位或8位数。 ③ 变址。除了ESP寄存器外,任何通用寄存器都可以作为变址寄存器,其内容即为变址。 ④ 比例因子。变址寄存器的值可以乘以一个比例因子,根据操作数的长度可以为1字节、2字节、4字节或8字节,比例因子相应可以为1、2、4或8。 由上面4个分量计算偏移量的方法为: 偏移量=基址+变址×比例因子+位移量 按照4个分量组合偏移量的不同方法,可以有9种存储器寻址方式,其中8种属于寄存器间接寻址。 (1) 直接寻址方式。 位移量就是操作数的有效地址,此位移量包含在指令中。 例如: DECWORD PTR [200];有效地址为200 (2) 寄存器间接寻址方式。 基址寄存器的内容为操作数的有效地址。 例如: MOV[EBX],EAX;有效地址在EBX中 (3) 基址寻址方式。 基址寄存器的内容和位移量相加形成有效地址。 例如: MOV[EBX+100],EAX;有效地址为EBX的内容加100 (4) 变址寻址方式。 变址寄存器的内容和位移量相加形成有效地址。 例如: SUBEAX,[ESI],20;有效地址为ESI的内容加20 (5) 带比例因子的变址寻址方式。 变址寄存器的内容乘以比例因子,在加位移量相加形成有效地址。 例如: SUBEAX,[ESI*8],7;有效地址为ESI的内容乘以8再加7 (6) 基址变址寻址方式。 基址寄存器的内容加上变址寄存器的内容组成有效地址。 例如: SUBEAX,[ESI][EBX];有效地址为EBX的内容加ESI的内容 (7) 基址加带比例因子的变址寻址方式。 变址寄存器的内容乘以比例因子再加上基址寄存器的内容组成有效地址。 例如: MOVECX,[EDI*2][EBX];有效地址为EDI的内容乘以2再加EBX的内容 (8) 带位移量的基址加变址寻址方式。 基址寄存器的内容加位移量,再加上变址寄存器的内容组成有效地址。 例如: MOVEDX,[ESI][EBP+200H];有效地址为EBP的内容加200H加EBX的内容 (9) 带位移量的基址加带比例因子的变址寻址方式。 变址寄存器的内容乘以比例因子,再加上基址寄存器内容与位移量之和组成有效地址。 例如: MOVECX,[EDI*2][EBX+20];有效地址为EDI的内容乘以2,再加EBX的内容再加20 3.4.280386的指令系统 80386的指令系统是在8086指令系统基础上设计的,并完全兼容8086指令系统,主要差别是80386指令系统扩展了数据宽度,对存储器寻址方式也进行了扩充,另外还增加了少量指令。本节仅对两者的差别和使用的注意点做简单的介绍,8086已有的指令参见3.3节。 1. 数据传送类指令 数据传送指令包括通用数据传送指令、标志寄存器传送指令、地址传送指令、数据转换指令等。 1) 通用数据传送指令 使用MOV指令时,两个操作数的位数必须相同,如果不同,则可以选用新增的MOVZX和MOVSX指令。例如: MOVZXAX,BL 该指令将BL的内容带符号扩展为一个字送入AX。 另外,PUSH指令的功能有所扩展,其源操作数可以是立即数。例如: PUSH0204H 而这样的指令在8086系统中不被允许。另外80386指令系统还提供了PUSHA指令,可以将全部16位寄存器一次压入堆栈,提供的PUSHAD指令可以全部32位寄存器一次压入堆栈。 2) 标志寄存器传送指令 在LAHF、SAHF、PUSHF和POPF的基础上,增加了两条指令,即 PUSHFD;将标志寄存器的内容作为双字压入堆栈 POPFD;从堆栈弹出双字送入标志寄存器 3) 地址传送指令 80386的地址传送指令实现6字节的地址指针传送。地址指针来自存储单元,目的地址为两个寄存器,其中一个为段寄存器,另一个为双字的通用寄存器。例如: LDSEBX,DATA;将DATA开始的指针送入DS、EBX寄存器 LSSESP,DATA;将DATA开始的指针送入SS、ESP寄存器 这些指令适合32位微机系统的多任务操作,因为在任务切换时,需要同时改变段寄存器和偏移量指针的值。 4) 数据转换指令 在8086的CBW、CWD指令的基础上,增加了两条指令。即 CWDE;将AX的内容扩展为双字送入EAX CDQ;将EAX的内容扩展为四字送入EDX、EAX 输入输出指令和8086完全相同,端口地址可以在指令中给出,也可以由DX寄存器给出。 2. 算术运算类指令 算术运算类指令的用法和8086中基本一致,只是在80386指令系统中,运算支持32位。例如: ADDEAX,0FF200A0H;将EAX 内容加0FF200A0H送回EAX寄存器 SUBEAX,EBX;将EAX 内容减去EBX内容送回EAX寄存器 在80386指令系统中,对IMUL指令给出两种扩充形式。 例如: IMULDX,BX,100;将BX的内容乘以100,结果送入DX寄存器 这类指令是用一个立即数乘以一个放在寄存器或存储器中的数,结果存入指定的寄存器。 例如: IMULEDX,ECX;将EDX的内容乘以ECX内容,结果送入EDX 这类指令是一个寄存器操作数乘以一个同样长度的放在寄存器或存储器的数,结果存入该寄存器。但由于这两类指令的乘积和被乘数、乘数的长度一样,有时会产生溢出,如果溢出,OF标志则被自动置1。 3. 逻辑运算类指令 逻辑运算类指令包括逻辑运算和移位指令。这两组指令的用法和8086中基本一致,只是在80386指令系统中,运算和移位支持32位。 例如: ANDEAX,EBX;将EAX 内容与EBX内容相与,结果送回EAX ROLEBX,CL;按CL指定的次数将EAX内容循环左移 在80386指令系统中,还增加了两条专用的双精度移位指令,即双精度左移指令SHLD和双精度右移指令SHRD。 例如: SHRDEAX,EBX,10 这条指令将EAX的内容右移10位,高10位由EBX的低10位来补充,而EBX的内容不变。 4. 串操作指令 80386的串操作指令和8086中基本一致,包括MOVS、CMPS、SACS、LODS和STOS。此外,80386指令系统还增加了字符串输入指令INS和字符串输出指令OUTS,来处理输入输出端口的数据块的读写。 INS指令可以从一个输入输出端口读入数据送到一串连续的存储单元; OUTS指令可以将一串连续的存储单元的内容顺序输出到一个输入输出端口。 INS指令使用时有INSB、INSW 和INSD 3种形式,分别对应字节串、字串和双字串。OUTS与之类似。 5. 转移、循环和调用指令 80386的转移指令在形式和意义上和8086相同,唯一不同的是条件转移的地址不再受范围的限制,可以到达存储空间的任何地方。 循环指令LOOP、LOOPE、LOOPNE等与8086完全相同,转移范围仍然为-128~+127。 调用指令CALL和返回指令RET在用法和含义上与8086类同,只是在80386中,由于EIP是32位,故在堆栈操作时,对于EIP的操作是4字节。 6. 条件设置指令 条件设置指令是80386中新增加的,用来根据测试标志的结果设置目的操作数的值。 例如: SETZAL;若ZF=1,则AL设置为1,否则设置为0 CMPAX,1000 SETBEBX;若AX低于或等于1000,则BX设置为1,否则设置为0 7. 系统设置和测试指令 这组指令也是80386中新增加的,它们一般出现在操作系统中,用来对系统设置和测试。具体如下。 (1) CLTS: 清TS标志指令。 (2) SGDT/SLDT/SIDT。 这3条指令将全局描述符表寄存器、局部描述符表寄存器或中断描述符表寄存器的内容送到存储器。 例如: SGDTMEM1;其中MEM1为6字节存储器操作数 SLDTMEM2;其中MEM2为2字节存储器操作数 SIDTMEM3;其中MEM3为6字节存储器操作数 (3) LTR: 装入任务寄存器指令。 这条指令一般用在多任务操作系统中,它将内存中2字节装入任务寄存器TR,执行该指令后,相应的任务状态段TSS 标上“忙”标志。 例如: LTRMEM2;其中MEM2为2字节存储器操作数 (4) STR: 存储任务寄存器指令。 这条指令一般用在多任务操作系统中,它将任务寄存器TR的内容送入内存中2字节。 例如: STRMEM2;其中MEM2为2字节存储器操作数 (5) LAR: 装入访问权指令。 本指令将2字节段选择子中的访问权字节送入目的寄存器。 例如: LARAX,SELECT;将段选择子中的访问权字节送入AH,AL清0 (6) LSL: 装入段界限值指令。 本指令将描述符中的段界限值送入目的寄存器。在指令中,由段选择子来指出段描述符。 例如: LSLBX,SELECT2;将SELECT2段选择子所对应的描述符中的段界限值送入BX (7) LGDT/LLDT/LIDT。 这3条指令分别将存储器的内容送全局描述符表寄存器、局部描述符表寄存器或中断描述符表寄存器的内容。 例如: LGDTMEM1;其中MEM1为6字节存储器操作数 LLDTMEM2;其中MEM2为2字节存储器操作数 LIDTMEM3;其中MEM3为6字节存储器操作数 (8) VERR/VERW: 检测段类型指令。 VERR指令检测段选择子所对应的段是否可读,VERW指令则检测一个段选择子所对应的段是否可写。 例如: VERRSELECT1;SELECT1段选择子所对应的段是否可读 VERWSELECT2;SELECT2段选择子所对应的段是否可写 (9) LMSW: 装入机器状态字指令。 本指令将存储器中的2字节送入机器状态字MSW。通过这种方式,可以使CPU切换到保护方式。检测段选择子所对应的段是否可读,VERW指令则检测一个段选择子所对应的段是否可写。 例如: VMSW[SP];将堆栈指针SP所指出的2字节送入MSW (10) SMSW: 存储机器状态字指令。 本指令将2字节机器状态字MSW存入内存中。 例如: SMSWMEM2;其中MEM2为2字节存储器操作数 (11) ARPL: 调整请求权级指令。 本指令可以调整段选择子的RPL字段,由此常用来阻止应用程序访问操作系统中涉及安全的高级别的子程序。ARPL的第一个操作数可由存储器或寄存器给出,第二个操作数必须是寄存器。如前者的RPL(最后2 位)小于后者的RPL,则ZF置1,且将前者的RPL增值,使其等于后者的RPL; 否则,ZF清0,并不改变前者的RPL。 例如: ARPLMEM_WORD,BX 3.5Pentium新增加的指令 Pentium一共增加了3条处理器专用指令和5条系统控制指令,具体如下。 1. 处理器专用指令 1) CMPXCHG8B m: 8字节比较指令 本指令将EDX:EAX中的8字节与m所指的存储器中的8字节比较,若相等,则ZF置1,并将EDX:EAX中的8字节送入目的存储单元; 否则ZF清0,并将目的存储单元中的8字节送入EDX:EAX中。 2) RDSTC: 读时钟周期数指令 本指令读取CPU中用来记录时钟周期数的64位计数器的值,并将读取的值送入EDX:EAX,供一些应用软件通过两次执行该指令来确定某段程序需要多少时钟周期。 3) CPUID: 读CPU的标识等有关信息 本指令用来获得Pentium处理器的类型等有关信息。在执行此指令前,EAX中如果为0,则指令执行后,EAX、EBX、ECX、EDX的内容合起来即为Intel产品的标识字符串,如果此前EAX中为1,则指令执行后,在EAX、EBX、ECX、EDX 中得到CPU级别、工作模式、可设置的断点数等。 2. 系统控制指令 (1) RDMSR: 读取模式专用寄存器指令。 本指令用来读出Pentium处理器的模式专用寄存器中的值。在执行该指令前,在ECX中设置寄存器号,可以为0~14H,指令执行后,读取的内容存放在EDX:EAX中。 (2) WRMSR: 写入模式专用寄存器指令。 本指令将EDX:EAX中的64位数写入模式专用寄存器。同样在执行该指令前,必须在ECX中设置寄存器号,可以为0~14H。 (3) RSM: 复位到系统管理模式。 (4) MOV CR4,R32: 将32位寄存器的内容送入控制寄存器CR。 (5) MOV R32,CR4: 将控制寄存器CR内容送入32位寄存器。