第 3章 指令系统
3.1 80X86/ Pentium指令格式和寻址
3.2 8086/8088指令系统
3.3 汇编语言程序设计返回主目录第 3章 指令系统
3.1.1指令格式每台计算机都有一套反映该计算机全部功能的指令,
它构成了该计算机的指令系统 。 通常指令以二进制编码的形式存放在存储器中,用二进制编码形式表示的指令称为机器指令 。 CPU可以直接识别机器指令 。 对于使用者来说,
机器指令记忆,阅读比较困难,为此将每一条指令都用统一规定的符号和格式来表示 。 用符号表示的指令称为符号指令 。 符号指令具有直观,易理解,可帮助记忆的特点 。
汇编语言程序中的指令就是符号指令 。 在计算机中,符号指令与机器指令具有一一对应的关系 。
图 3 - 1指令格式每条符号指令都由操作码和操作数两部分组成,操作码表示计算机执行某种指令功能,操作数表示操作中所需要的数据或者所需数据与输出数据的存放位置 ( 又称地址码 ) 。
80X86/Pentium系列 CPU采用变字节指令格式,由 1~16个字节组成一条指令,指令的一般格式如图 3 - 1 所示 。
P r e f i x O P c o d e m o d r / m s - i - b d i s p d a t a
字段 1
1 ~ 4
字节
1 ~ 2
字节字段 2 字段 3 字段 4 字段 5
1 字节 1 字节
0,1,2,4字节
0,1,2,4字节字段 6
一条指令的 6个字段中,字段 1是附加字段,字段 2到字段 6是基本字段 。 各字段的含义如下:
(1) 操作码字段 OP code。
操作码字段规定指令的操作类型,说明指令所要完成的操作 。 同时还指出操作数类型,操作数传送方向,寄存器编码或符号扩展等 。
(2) 寻址方式字段 mod r/m 和 s-I-b。 寻址方式字段规定寄存器 /存储器操作数的寻址方式 。 mod r/m为主寻址字节,
它规定操作数存放的位置 ( r/m) 以存储器操作数有效地址
EA的计算方法 。 s-I-b为比例 -变址 -基址寻址字节 。 一般所有访问存储器指令中都有主寻址字节,是否需要比例 -变址
-基址字节由主寻址字节的编码决定 。
(3) 位移量字段 disp。
位移量是存储器操作数段内偏移地址的一部分 。 disp字段指出位移量的大小,其长度为 0,1,2或 4个字节 。
(4) 立即数字段 data。
立即数字段指明立即操作数的大小,其长度也是 0,1、
2或 4个字节 。 8位立即数与 16或 32位操作数一起使用时,
CPU自动将它扩展为符号相同的 16或 32位数,也可以将 16
位扩展为 32位 。
(5) 前缀字段 Prefix。
前缀字段用于修改指令操作的某些性质。 常用前缀有五种:
① 段超越前缀,将前缀中指明的段寄存器取代指令中默认的段寄存器 。
② 操作数宽度前缀,改变当前操作数宽度的默认值 。
③ 地址宽度前缀,改变当前地址宽度的默认值 。
④ 重复前缀,重复串的基本操作,以提高 CPU处理串数据的速度 。
⑤ 总线锁存前缀:产生锁存信号,以防止其他总线主控设备中断 CPU在总线上的传输操作 。
每个前缀的编码为一个字节 。 在一条指令前可同时使用多个指令前缀,不同前缀的前后顺序无关紧要 。
上述指令格式的 6个字段中,操作码字段是必要的,
其他字段均可有可无,这取决于特定的操作功能 。
3.1.2寻址方式寻址方式是寻找操作数或操作数地址的方式 。 根据寻址方式,可以方便地访问各类操作数 。
80X86/Pentium指令中的操作数有三种可能的存放位置:
① 操作数在指令中,即指令的操作数部分就是操作数本身,这种操作数叫立即操作数 。
② 操作数包含在 CPU的某个内部寄存器中,这时指令的操作数部分是 CPU内部寄存器的一个编码 。
③ 操作数在内存的数据区中,这时指令的操作数部分包含此操作数所在的内存地址 。
80X86/Pentium系列 CPU中,任何内存单元的实际地址都由两部分组成:段基地址和段内偏移地址 。 例如,内存中某一单元的逻辑地址用 ES,TABLE来表示 。
其中 ES是段基地址,TABLE为段内偏移地址 。 段内偏移地址有 16位或 32位地址,段基地址和段内偏移地址相加形成线性地址 。 选用页功能时,线性地址由管理部件换算为 32位物理地址;不用页功能时,线性地址就是物理地址 。
在存储器寻址时,指令的操作数部分给出的地址是段内偏移地址 。 为了适应处理各种数据结构的需要,段内偏移量由几个基本部分组合而成,所以也称为有效地址 EA。
组成有效地址 EA的基本部分包括,基址寄存器内容,
变址寄存器内容,位移量,比例因子等 。 其中,基址,变址寄存器中通常为某局部存储区的起点,位移量是指令中的 disp字段,比例因子是 32位寻址方式中特有的一种地址分量 。 有效地址 EA的计算公式如下:
EA[ 基址寄存器 ] +([ 变址寄存器 ] × 比例因子 ) +
对于基址,变址寄存器和比例因子,位移量的取值规定有所不同 。 表 3 - 1 给出了这两种寻址方式的四个分量的规定,由此可组合出多种存储器寻址方式 。
表 3 – 1 16位寻址和 32位寻址方式的四个分量
8086/8088提供了八种寻址方式,它们是立即寻址方式,
寄存器寻址方式,直接寻址方式,寄存器间接寻址方式,
变址寻址方式,基址寻址方式,基址加变址寻址方式和带有位移量的基址加变址寻址方式 。 80X86/Pentium有 11种寻址方式 。 与 8086/8088相比增加的三种寻址方式是比例变址寻址方式,基址加比例变址寻址方式和带位移量的比例变址寻址方式 。
1,立即寻址方式在立即寻址方式下,操作数作为立即数包含在指令的操作码之后,与操作码一起存放在代码段区域 。 立即数总是和操作码一起被取入 CPU的指令队列,在指令执行时,不再需要访问存储器 。
立即数可以是 8位,16位或 32位操作数 。 若是 16位,
低位字节存放在相邻两个字节存储单元的低地址单元中;
若是 32位,则低位字存放在相邻两个字存储单元的低地址单元中 。
立即数可以用二进制数,八进制数,十进制数以及十六进制数来表示 。 在非十进制的立即数末尾需要使用字母加以标识 。 必要情况下,十进制数用字母 D加以标识,通常情况下不需要标识 。 如:
MOV AL,10 ; 十进制数 ( D )
MOV AL,00100101B ; 二进制数 ( B )
MOV AL,0AH ; 十六进制(H)
2,寄存器寻址方式在寄存器寻址方式下,操作数存在于指令规定的 8位,
16位或 32位寄存器中 。 寄存器可用来存放源操作数,也可用来存放目的操作数 。 寄存器寻址方式是 CPU内部的操作,
不需要使用访问总线周期,因此指令的执行速度比较快 。
以上两种寻址方式中,操作数是从指令或寄存器中获得的 。 而在实际的程序运行中,大多数操作数需从内存中获得 。 对于内存的寻址方式有多种,不管哪一种寻址方式,
最终都将得到存放操作数的物理地址 。 指令的操作数部分是此操作数的有效地址 EA。
3.
直接寻址方式是存储器直接寻址方式的简称,是一种针对内存的寻址方式 。 在这种寻址方式下,指令代码中给出操作数的偏移地址,即有效地址 (EA)。 它是一个 16位或
32位的位移量数据,与操作码一起放在代码段中 。 在默认方式下,操作数存放在数据段 ( DS) 。 如果要对除 DS段之外的其他段 ( CS,ES,SS,FS,GS) 中的数据寻址,
应在指令中增加前缀,指出段寄存器名,这就是段跨越 。
在实地址方式下,对内存进行寻址时,需计算物理地址 。
物理地址的计算公式为:
物理地址 16d× 段地址 (DS)+偏移地址 (EA)
不同的段地址存放在不同段的段寄存器中 。 如数据段的段地址存放在数据段寄存器 DS中 。 有些机器允许将数据存放在非数据段中,这时需要在指令中使用段跨越前缀标识出相应的段寄存器 。 在直接寻址方式的指令中,直接给出了有效地址 EA,那么操作数的物理地址就是
16d× (DS)+EA。
直接寻址的指令如,MOV AX,[ 1000H]
当 (DS)2000H时,根据物理地址计算公式,得物理地址 16d× 2000H+1000H21000H
图 3 - 2直接寻址示意图
AH AL
2 1 0 0 0
2 1 0 0 1
存储器指令的执行结果是,(AX)(21000H),即内存 21000H
单元的内容已传送到寄存器 AX中 。 指令的执行情况如图 3
- 2 所示 。
下面的指令表示在附加段获得操作数 。
MOV AX,ES:
16d× (ES)+1000H
在汇编语言中,可以用符号地址代替数值地址来表示有效地址 。
MOV AX,[ VALUE]
其中 VALUE为存放操作数单元的有效地址,符号地址的方括号[ ]可以省略。
4.
寄存器间接寻址方式也是对内存的寻址方式之一,操作数的有效地址 EA在指定的寄存器中,即 EA[ 寄存器 ] 。
在 16位寻址和 32位寻址方式中,
不同 。
16位寻址时,EA放在基址寄存器 BX,BP或变址寄存器 SI,DI中,所以该方式下的操作数的物理地址计算公式有以下几个:
物理地址 16d× (DS)+(BX)
物理地址 16d× (DS)+(DI)
物理地址 16d× (DS)+(SI)
物理地址 16d× (SS)+(BP)
前三个式子表示操作数在数据段,最后一个式子表示操作数在堆栈段 。
例如,MOV AX,[ BX]
当 (DS)1000H,(BX)2000H时,
16d× 1000H+2000H12000H
指令的执行结果将内存 12000H单元的内容传送到寄存器 AX中,指令的执行情况如图 3 - 3 所示 。 类似于直接寻址方式,在该方式下,当指令中指定的寄存器为 BX,SI,DI时,操作数存放在数据段中,因此段地址是寄存器 DS的内容 。 若指令中指定的寄存器为 BP时,操作数存放在堆栈段中,段地址是寄存器 SS的内容 。
若指令中指定了跨越前缀,则可以从指定的段中获得操作数 。
图 3 - 3寄存器间接寻址示意图
AH
AL
1 0 0 0 2 0 0 0
DS BX
1 2 0 0 0
1 2 0 0 0
1 2 0 0 1
存储器
× 1 6
例如对于 ADD AX,ES:(SI),
16d× (ES)+(SI)
利用寄存器间接寻址方式可以非常方便地通过改变寄存器的内容来改变内存地址,比起直接寻址方式,其在使用时更为灵活,如图 3 -3 所示 。
32位寻址时,八个 32位通用寄存器均可用来进行寄存器间接寻址 。 这时,EBP,ESP的默认段寄存器为 SS,其余六个寄存器均默认段寄存器为 DS。 同样可以采用加段超越前缀的方法对其他段进行寻址 。
当直接寻址时,有效地址 EA在指令中,它是一个常量 。 当间接寻址时,有效地址 EA在寄存器中,寄存器的内容由它之前的指令确定,因而是一个变量 。
5.
在变址寻址方式中,操作数的有效地址是变址寄存器
(SI或 DI)的内容与指令中指定的位移量的和 。 即有效地址
EA[ 变址寄存器 ] +位移量 。
当进行 16位寻址时,SI和 DI作为变址寄存器 。 这时,
物理地址计算公式为物理地址 16d× (DS)+(SI)+8位 (16位 )
位移量或物理地址 16d× (DS)+(DI)+8位 (16位 )
例如,MOV AX,100H(SI)
当 (DS)2000H,(SI)1000H 时,
16d× (DS)+(SI)+位移量 20000H+1000H+100H21100H
执行指令的结果将内存 21100H单元和 21101H单元的内容传送到寄存器 AX中 。 在用变址寻址方式进行有效地址的计算中,位移量可为正数,也可为负数,同样可以使用段跨越前缀标识段寄存器的使用情况 。
当进行 32位寻址时,除 ESP外的任何 32位通用寄存器均可作变址寄存器 。 其中,EBP以 SS为默认段寄存器,其余寄存器以 DS为默认寄存器 。
6.
在基址寻址方式中,操作数的有效地址是基址寄存器的内容与指令中指定的位移量的和 。
当进行 16位寻址时,BP和 BX作为基址寄存器 。 在缺省段超越前缀时,BX以 DS作为默认段寄存器,BP以 SS
作为默认段寄存器,位移量可以是 8位或 16位 。 该方式下物理地址计算公式为物理地址 16d× (DS)+(BX)+8位 (或 16位 )
或物理地址 16d× (SS)+(BP)+8位 (或 16位 )
当进行 32位寻址时,八个 32位通用寄存器均可作为基址寄存器 。 其中 EBP,ESP以 SS为默认段寄存器,其余六个寄存器以 DS作为默认段寄存器 。
图 3 - 4基址变址寻址示意图
AX
1 2 0 0 1 0 0
DS BX
1 2 1 5 0
1 2 1 5 1
存储器
50
SI
1 2 1 5 0
× 1 6
7,基址加变址寻址方式在基址加变址寻址方式中,有效地址 EA基址寄存器 +变址寄存器,即两个寄存器的内容之和为操作数的有效地址 。
它有 16位和 32位两种寻址方式 。 在每种情况下,基址寄存器,变址寄存器的使用规定以及段寄存器的默认规定与基址寻址方式相同 。 在寻址方式中,当基址寄存器和变址寄存器的默认段寄存器不同时,一般由基址寄存器来决定默认用哪一个段寄存器作为段基址指针 。 若在指令中规定了段跨越,则可以用其他寄存器作为段基地址 。 基址加变址物理地址 16d× (DS)+(BX)+(SI)
或 物理地址 16d× (SS)+(BP)+(DI)
MOV AX,[ BX] [ SI] 或 MOV AX,[ BX+SI]
若 (DS)1200H,(BX)100H,(SI)50H,
16d× (DS)+(BX)+(SI)16d× 1200H+100H+50H12150H
指令的执行结果将内存 12150H单元的内容传送到寄存器 AX中 。 指令的执行情况如图 3 - 4 所示 。
基址变址寻址方式中,可以使用段跨越前缀标识操作数所在的段 。
如,OV AX,ES:[ BX+DI]
则 物理地址 16d× (ES)+(BX)+(DI)
8,带有位移量的基址加变址寻址方式在带位移量的基址加变址寻址方式中,操作数的有效地址是基址寄存器和变址寄存器以及 8位 ( 或 16位 ) 的位移量之和,即
EA[ 基址寄存器 ] +[ 变址寄存器 ] +
它有 16位和 32位寻址方式 。
每种寻址方式下,基址寄存器,变址寄存器的使用规定和段寄存器的默认规定与基址加变址寻址方式相同 。
若基址寄存器是 BX,则使用 DS为段寄存器;若基址寄存器是 BP,则使用 SS为段寄存器 。
相应地,
物理地址 16d× (DS)+(BX)+(DI)+8位 ( 或 16位 ) 位移量或物理地址 16d× (SS)+(BP)+(SI)+8位 (或 16位 )
例如,MOV AX,100 [ BX+DI ] 或 MOV AX,
[ BX+DI+100H]
若 (DS)2000H,(BX)1000H,(DI)100H,
物理地址 16d× 2000H+1000H+100H+100H21200H
指令的执行结果将内存单元 21200H和 21201H的内容传送到寄存器 AX中 。 除了上面介绍的八种方式外,以下三种寻址方式适合于 32位寻址的情况,它们是 32位特有的寻址方式 。
9,比例变址寻址方式
EA[ 变址寄存器 ] × 比例因子 +
这里,乘比例因子的操作在 CPU内部由硬件完成 。
10,基址加比例变址寻址方式
EA[ 基址寄存器 ] +[ 变址寄存器 ] ×
11,带位移量的基址加比例变址寻址方式
EA[ 基址寄存器 ] +[ 变址寄存器 ] × 比例因子 +位移量在寻址过程中,变址寄存器内容乘以比例因子的操作在
CPU内部由硬件完成 。
3.1.3存储器寻址时的段约定在进行存储器操作数访问时,除了要计算偏移地址
EA外,还必须确定段寄存器,即操作数所在的段 。 一般情况下,指 令 中 不 特 别 指 出 段 寄 存 器 。 因 为 在
80X86/Pentium中,对于各种不同操作类型的存储器寻址的段寄存器有一个基本默认约定 。 只要在指令中不特别说明要超越这个约定,则一般情况下就按这个基本约定来寻找操作数 。 这些基本约定如表 3 - 2 所示 。
表 3 - 2 中,除了程序只能在代码段,堆栈操作数只能在堆栈段,目的串操作数只能在附加数据段外,其他操作虽然有默认段,但都是允许超越的 。
表 3 - 2存储器操作时段和偏移地址寄存器的约定
3.2 8086/8088指令系统
8086/8088指令系统是 80X86/Pentium的基本指令集 。 指令的操作数是 8位或 16位操作数,偏移地址是 16位地址 。 按功能可将指令分成六类,即数据传送类,算术运算类,逻辑运算与移位类,串操作类,控制转移类和处理器控制类 。
为便于理解指令的形式和功能,对指令中操作数符号的约定如下:
OPRD:
OPRD1,OPRD2,多操作数指令中,OPRD1为目标操作数,OPRD2为源操作数 ;
reg,8位或 16位的通用寄存器 ;
sreg,段寄存器 ;
reg8,8位通用寄存器 ;
reg16,16位通用寄存器 ;
mem,8位或 16位存储器 ;
mem8,8位存储器 ;
mem16,16位存储器 ;
imm,8位或 16位立即数 ;
imm8,8位立即数 ;
imm16,16位立即数 。
3.2.1数据传送类指令数据传送类指令是计算机中最基本,最常用,最重要的一类操作 。 它用来在寄存器与存储单元,寄存器与寄存器,累加器与 I/O端口之间传送数据,地址等信息,也可以将立即数传送到寄存器或存储单元中 。 为此,指令中必须指明数据起始存放的源地址和数据传送的目标地址 。
数据传送类指令共有 14条,分成 4组 。 如表 3 - 3 所示 。
其中,除了 SAHF,POPF指令外,其他指令执行后对标志位没有影响 。
表 3-3
1.
(1) 传送指令 MOV。
指令格式,MOV OPRD1,OPRD2
指令功能:将源操作数传送给目标操作数,即
OPRD2→OPRD 1。 OPRD1和 OPRD2可以是字节或字,
但是必须等长 。
具体指令形式:
MOV reg/sreg,reg ; reg/sreg←reg
MOV reg,sreg ; reg←sreg
MOV reg/sreg,mem ; reg/sreg←mem
MOV mem,reg/sreg ; mem←reg/sreg
MOV reg,imm ; reg←imm
MOV mem,imm ; mem←imm [HT5]
源操作数可以是通用寄存器,段寄存器,存储器以及立即操作数,目标操作数可以是通用寄存器,段寄存器
( CS除外 ) 或存储器 。 各种数据传送关系如图 3 - 5 所示 。
使用 MOV指令进行数据传送时应注意:段寄存器 CS及立即数不能作为目标操作数;两个存储单元之间不允许直接传送数据;立即数不能直接传送到段寄存器;两个段寄存器之间不能直接传送数据 。
图 3 -5数据传送关系示意图通用寄存器
( A X,BX,CX,DX,BP,
SP,SI,D I )
存储器立即数段寄存器
( C S,SS,DS,E S )
(2) 堆栈操作指令 PUSH/POP。
堆栈是按照后进先出原则组织的一段内存数据区域 。
80X86/Pentium规定堆栈设置在堆栈段 SS内 。 堆栈的栈底是固定不变的,这块存储器只有一个出入口,称之为栈顶栈指针 SP始终指向堆栈的栈顶 。 随着 PUSH和 POP指令的执行,
栈顶的位置将发生变化,进栈栈顶向低地址方向扩展,退栈栈顶向高地址 ( 栈底 ) 方向扩展,即 SP的内容被修改,并始终指向的是栈顶 。 在子程序调用或中断时,堆栈用于保护当前的断点地址和现场数据,以便子程序执行完毕后正确返回到主程序 。 断点地址的保存由子程序调用指令或中断响应来完成,现场数据保存可通过堆栈操作指令来实现 。
指令格式,PUSH OPRD
POP OPRD
指令功能:进栈指令 PUSH使 SP-2→SP,然后将 16位的源操作数压入堆栈,先高位后低位 。 源操作数可以是通用寄存器,段寄存器和存储器 。
POP退栈指令的执行过程与 PUSH相反 。 它从当前栈顶弹出 16位操作数到目标操作数,同时 SP+2→SP,使 SP
指向新的栈顶 。 目标操作数可以是通用寄存器,段寄存器 ( CS除外 ) 或存储器 。
进栈和退栈的操作数要求以字为单位。 PUSH和 POP
指令不影响标志位。
具体指令形式:
PUSH reg16 ; SPSP-2,[ SP] ← reg16
POP reg16 ; reg16 ← [ SP],SPSP+2
PUSH Sreg ; SPSP-2,[ SP] ← Sreg16
POP Sreg16 ; Sreg16 ← [ SP],SPSP+2
PUSH mem16 ; SPSP-2,[ SP] ← mem16
POP mem16 ; mem16 ← [ SP],SPSP+2
(3) 交换指令 XCHG。
指令格式,XCHG OPRD1,OPRD2
指令功能,将一个字节或一个字的源操作数与目标操作数进行交换 。
具体指令形式,[HT5”]
XCHG reg,reg[WB]; reg←→reg
XCHG mem,reg [DW]; mem←→reg
XCHG reg,mem [DW]; reg←→mem [HT5]
XCHG可实现寄存器之间或寄存器与存储器之间的信息交换 。 但是,不能在两个存储单元之间直接交换数据,段寄存器和立即数不能作为操作数 。
(4) 查表转换指令 XLAT。
指令格式,XLAT
XLAT OPRD; AL← [ BX+AL]
指令功能,完成一个字节的查表转换 。 它将数据段中偏移地址为 BX与 AL寄存器之和的存储单元的内容送入 AL
寄存器 。
在使用该指令时,应首先在数据段中建立一个长度小于 256 B的表格,表的首地址置于 BX中,AL中存放查找对象在表中的下标 。 指令执行后,所查找的对象存于 AL中,
BX内容保持不变 。
2,地址传送指令
(1) 有效地址传送指令 LEA。
指令格式,LEA OPRD1,OPRD2
指令功能,将源操作数的有效地址送到目的操作数 。
具体指令形式:
LEA reg16,mem; reg16←Addr(mem)
(2) 地址指针传送指令 LDS/LES。
指令格式,LDS OPRD1,OPRD2
LES OPRD1,OPRD2
指令功能:这两条指令的功能类似,都是将源操作数偏移地址决定的双字单元中的第一个字的内容传送到指令指定的 16位通用寄存器,第二个字的内容传送给段寄存器
DS或 ES。
3.
标志字传送指令用于对标志寄存器 ( FR) 的保护和更新操作 。 指令的操作数由隐含方式给出 。
(1) 标志字读写指令 LAHF/ SAHF。
指令格式,LAHF
SAHF
LAHF指令可将标志寄存器的低字节 ( 含符号标志 SF、
零标志 ZF,辅助进位标志 AF,奇偶标志 PF和进位标志 CF)
传送到 AH寄存器中 。 这条指令不影响标志位 。
SAHF指令的功能与 LAHF相反,它将寄存器 AH的内容传送到标志寄存器的低字节中 。
(2) 标志进栈 /出栈指令 PUSHF/ POPF。
指令格式,PUSHF
POPF
PUSHF指令把标志寄存器的内容压入堆栈,同时堆栈指针 SP←SP -2。
POPF指令将堆栈指针 SP所指的一个字传送到标志寄存器中,同时堆栈指针 SP←SP+ 2。
4,输入 /输出数据传送指令 IN/OUT
在计算机中,输入/输出操作是由 CPU 利用输入,输出指令并通过累加器 AL,AX 进行的 。 输入指令完成由输入端口到 CPU的信息传送,输出指令完成从 CPU到输出端口的信息传送 。
指令格式,IN OPRD1,OPRD2
OUT OPRD1,OPRD2
指令功能:在 AL或 AX寄存器与 I/O端口之间传送数据 。
具体指令形式:
IN AL,imm8 ; AL←(imm 8)
OUT imm8,AL ; (imm8) ←AL
IN AX,imm8 ; AX←(imm 8+1)(imm8)
OUT imm8,AX ; (imm8+1)(imm8) ←AX
IN AL,DX ; AL←(DX)
OUT DX,AL ; (DX) ←AL
IN AX,DX ; AX←(DX+ 1)(DX)
OUT DX,AX ; (DX+1)(DX) ←AX
3.2.2算术运算类指令算术运算指令可完成加,减,乘,除运算以及在算术运算过程中进行进制及编码调整操作 。 在进行这些操作时,可针对字节或字运算,也可对带符号数和无符号数进行运算 。
算术运算类指令如表 3 - 4 所示 。
1.
(1) 加法指令 ADD。
指令格式,ADD OPRD1,OPRD2
指令功能:将源操作数与目的操作数相加,结果存放于目的操作数 。 即 OPRD1+OPRD2→OPRD 1。
3 - 4 所示算术运算类指令如表 。
具体指令形式,ADD reg,reg[WB]; reg←reg+reg
ADD reg,mem ; reg←reg+mem
ADD reg,imm ; reg←reg+imm
ADD mem,reg ; mem←mem+reg
ADD mem,imm ; mem←mem+imm [HT5]
要求源操作数和目的操作数同时为带符号的数或无符号数,且长度相等。
(2) 带进位加法指令 ADC。
指令格式,ADC OPRD1,OPRD2
指令功能:将源操作数与目的操作数以及进位标志位
CF 的值相加,并将结果存放于目的操作数,即
OPRD1+OPRD2+CF→OPRD 1。
具体指令形式:
ADC reg,reg ; reg←reg+reg+CF
ADC reg,mem ; reg←reg+mem+CF
ADC reg,imm ; reg←reg+imm+CF
ADC mem,reg ; mem←mem+reg+CF
ADC mem,imm ; mem←mem+imm+CF
(3) 加 1指令 INC。
指令格式,INC OPRD
指令功能:将指定操作数内容加 1。 INC指令不影响进位标志 CF。
具体指令形式:
INC mem ; mem←mem+ 1
INC reg ; reg←reg+ 1 [HT]
2.
减法指令有 SUB减法,SBB带借位的减法,DEC减 1、
NEG求补和 CMP比较等指令 。
(1) 减法指令 SUB。
指令格式,SUB OPRD1,OPRD2
指令功能:将目的操作数减去源操作数,结果存放于目的操作数,即 OPRD1-OPRD2→OPRD 1。
具体指令形式:
SUB reg,reg ; reg←reg -reg
SUB reg,mem ; reg←reg -mem
SUB reg,imm ; reg←reg -imm
SUB mem,reg ; mem←mem -reg
SUB mem,imm ; mem←mem -imm
(2) 带借位减法指令 SBB。
指令格式,SBB OPRD1,OPRD2
指令功能:将目的操作数减去源操作数,再减去借位 CF的值,结果存放于目的操作数 。 即 OPRD1-OPRD2-
CF→OPRD 1。
具体指令形式:
SBB reg,reg ; reg←reg -reg-CF
SBB reg,mem ; reg←reg -mem-CF
SBB reg,imm ; reg←reg -imm-CF
SBB mem,reg ; mem←mem -reg-CF
SBB mem,imm ; mem←mem -imm-CF
(3) 减 1指令 DEC。
指令格式,DEC OPRD
指令功能,对指定操作数减 1。 DEC指令不影响进位标志 。
具体指令形式,〖 HT5”〗
DEC mem [DW]; mem←mem -1
DEC reg [DW]; reg←reg -1 [HT]
(4) 求补指令 NEG。
指令格式,NEG OPRD
指令功能:对指定操作数求补运算 。 在机器内部,
对操作数的求补操作是对操作数进行求反后末位加 1。 通过求补可使正数变为负数或使负数变为正数 。 这样使得一个正数减去一个正数的减法运算,
转化为一个正数加上一个负数的加法运算 。
具体指令形式:
NEG mem ; mem← 0-mem
NEG reg ; reg← 0-reg [HT]
(5) 比较指令 CMP。
指令格式,CMP OPRD1,OPRD2
指令功能:将目的操作数减去源操作数,结果不予保存 。 只是根据结果的状态设置条件标志位,设置状态标志位与 SUB指令含义相同 。
CMP reg,reg ; reg-reg
CMP reg,mem ; reg-mem
CMP reg,imm ; reg-imm
CMP mem,reg ; mem-reg
CMP mem,imm ; mem-imm
比较指令通常用于比较两个操作数的大小 。 由受影响的标志位状态来判断两个操作数比较的结果 。 不论是无符号数比较还是有符号数比较,若在比较指令后,ZF1,则两者相等,否则不相等 。 若两者不相等,则可在比较两个数之后,利用其他标志位的状态来确定两者中哪个大 。
如果是两个无符号数比较,则可根据进位标志 CF的状态来判断:
若 CF1,则 OPRD1<OPRD2 ;若 CF0,
OPRD1>OPRD2。
如果是两个有符号数比较,则要根据 SF和 OF两个标志的关系来判断:
若 SFOF0,则 OPRD1>OPRD2 ;若 SFOF1,则
OPRD1<OPRD2。
在程序中,比较指令常用于条件转移之前,条件转移指令根据 CMP操作之后的状态标志决定程序转移或不转移 。
3,乘法指令乘法指令包括无符号数乘法,带符号数乘法两种 。
(1) 无符号数乘法指令 MUL。
指令格式,MUL OPRD
指令功能,完成两个无符号数的乘法运算 。 要求被乘数放在 AL或 AX累加器中,用于字节运算和字运算,另一乘数可通过指令中的 OPRD( 除立即数方式以外的寻址方式 ) 获得 。
具体指令形式:
MUL reg ; AX←AL × reg8或 DX,
AX←AX × reg16
具体指令形式:
IMUL reg ; AX←AL × reg8或 DX,
AX←AX × reg16
IMUL mem ; AX←AL × mem8或 DX,
AX←AX × mem16
乘法指令的执行结果会使标志位发生变化 。 只有进位标志 CF,溢出标志 OF有意义,其它标志位无定义 。 CF、
OF定义如下:当进行字节运算时,其结果超过字节长度成为字 (AH≠0),
CF和 OF 置,1”; 当进行字运算时,其结果超过字长度成为双字 (DX≠0),CF 和 OF置,1”。 这样就可以用 OF及
CF来检查和判断字节或字操作的结果 。 对 MUL指令,当进行字节操作时,乘积结果的高一半为 0(AH0),或当进行字操作时,乘积结果高一半为 0(DX0),CF和 OF均为 0。 对于 IMUL指令,如果乘积结果的高一半为低一半的符号位的扩展,那么 CF和 OF均置,0”,否则置,1”。
乘法指令为乘积保留了两倍于原来操作数的存储空间,
因而不会出现溢出现象 。
4.
除法指令包括无符号数除法指令 DIV,带符号数除法指令 IDIV,以及在除法运算中辅助 DIV,IDIV指令的字节转换为字指令 CBW和字转换为双字指令 CWB。
(1) 无符号数除法指令 DIV。
指令格式,DIV OPRD
指令功能,完成两个无符号数的除法运算,除法操作可作字节或字操作 。 在进行字节操作时,要求被除数为 16
位,并存放在 AX累加器,除数 8位由指令中的源操作数指定,结果的 8位商存放于 AL中,8位余数存放于 AH中 。 在进行字操作时,要求被除数为 32位,存放在 DX,AX寄存器中,16位除数由指令中源操作数指定,结果的 16位商存放于 AX中,16位余数存放于 DX中,
(2) 带符号数除法指令 IDIV。
指令格式,IDIV
指令功能:完成两个带符号数的除法操作 。 在执行该指令时,要求操作数为带符号数,商及余数也为带符号数,
余数与被除数的符号相同 。
除法指令的使用需要说明:
① 源操作数不允许使用立即寻址方式 。
② 除法指令执行后,标志位无定义 。
③ 除数为零时,则产生一个 0类型中断 。
在除法运算中常常使用 CBW和 CWD对除法所需操作数进行长度扩展。
(3) 字节转换为字指令 CBW。
指令格式,CBW
指令功能,将 AL中的符号扩展到 AH中 。
如,当 (AL)04H,执行 CBW指令后,(AH)00;
当 (AL)F0H,执行 CBW指令后,(AH)0FFH
(4) 字转换为双字节指令 CWD。
指令格式,CWD
指令功能,将 AX中的符号扩展到 DX中 。 它只是增加了操作数长度,其操作数的大小没有改变 。 CBW和 CWD
指令的执行对标志位无影响 。
5.
在算术运算中操作数可以采用 BCD码,但是运算后的结果必须经过调整,否则结果是错误的 。 BCD码是一种用二进制编码表示的十进制数,每个 BCD码都是由 4位二进制代码来表示的,故称为压缩 BCD码 。 例如,10000101可看作十进制的 85。 使用 BCD码进行算术运算,一方面符合计算机只能处理二进制数的要求,另一方面 BCD码也给编写和阅读程序带来了直观效果 。 为此指令系统提供了必须用在 ADD,ADC指令后面的加法十进制调整指令 DAA
和必须用在 SUB,SBB指令后面的减法十进制调整指令
DAS。 经过调整后的结果才是正确的 BCD码 。
(1) 压缩 BCD数加法调整指令 DAA。
指令格式,DAA
指令功能,将 AL寄存器中的和调整为压缩的 BCD码 。
由于一个字节可以表示两位 BCD码,因此该指令的调整将根据标志位 CF,AF以及 AL寄存器的值自动地进行 。
DAA
① 当辅助进位标志 AF1或者 AL寄存器的低 4位为 A~
FH时,AL寄存器的内容加上 06H,并将标志 AF置,1” (调整低 4位 )。
② 当 CF1或者 AL寄存器的高 4位为 A~ FH时,AL寄存器的内容加上 60H,并将标志 CF置,1”(调整高 4位 )。
例如,当 (AL)26,(CL)26时,
ADD AL,CL ; (AL)4C,CF0 AF0
DAA ; (AL)52,CF0 AF1
可以看到 DAA指令是将 (AL)←(AL)+ 06,得到 (AL)52,
使结果调整为正确的 BCD码,并将标志 AF置,1”。
(2) 压缩 BCD数减法调整指令 DAS。
指令格式,DAS
指令功能:将 AL寄存器中的差调整为压缩的 BCD码 。
DAS指令的使用要求与 DAA指令一样 。 DAS指令也是根据标志位 CF,AF以及 AL寄存器的值自动进行调整 。
DAS
① 当辅助进位标志 AF1或者 AL寄存器的低 4位为 A~
FH时,AL寄存器的内容减 06H,并将 AF置,1”。
② 当 CF1或者 AL寄存器的高 4位为 A~ FH时,AL寄存器的内容减 60H,并将标志 CF置,1”。
DAA,DAS指令对压缩 BCD码在运算之后进行自动调整 。 在算术运算中也可以使用非压缩的 BCD码 。 同样,非压缩的 BCD码在运算之后,其结果也需要进行调整 。 非压缩的 BCD码用 8位二进制代码表示一个十进制数,即占用一个字节,其中低 4位的含义与压缩 BCD码相同,而高 4位为
,0”。 如,十进制数 8表示为非压缩的 BCD码即为 00001000。
(3) 非压缩 BCD数加法调整指令 AAA。
指令格式,AAA
指令功能,将寄存器 AL中的和调整为非压缩的 BCD码 。
AAA 指令用在 ADD,ADC指令之后 。
AAA指令调整过程如下:
① 当 (AL)的低 4位为 0~ 9H之间,且 AF为,0”,则执行 ③ ;
② 当 (AL)的低 4位为 A~ FH之间,或 AF为,1”,则
(AL)←(AL)+ 06,(AH)←(AH)+ 1,AF置,1”;
③ AL寄存器的高 4位被清除;
④ 将 AF的值送 CF标志位。
例如,当 (AX)0008H,(BL)09H
ADD AL,BL ; (AX)0011H,(BL)09H
AAA ; (AL)07H,(AH)01H,或 (AX)0107H,CF1
(4) 非压缩 BCD数减法调整指令 AAS。
指令格式,AAS
指令功能,将 AL中的差调整为非压缩的 BCD码,AAS
指令用在 SUB,SBB指令之后 。
AAS指令调整过程如下:
① 当 (AL)的低 4位为 0~ 9H时,且 AF0,则执行 ③ ;
② 当 (AL)的低 4位为 A~ FH时,或 AF1,则 (AL)←(AL) -
06H,(AH)← (AH)-1,AF置,1”;
③ AL寄存器高 4位被清除;
④ 将 AF的值送 CF标志位 。
AAA指令和 AAS指令对 AF,CF标志位产生影响,其它标志位均无定义 。
(5) 非压缩 BCD数乘法调整指令 AAM。
指令格式,AAM
指令功能:将存放在寄存器 AL中的积调整为非压缩的
BCD码 。 AAM指令用在 MUL指令对两个非压缩 BCD码的数进行乘法之后 。
其调整方法是将 AL寄存器中的内容除以 0AH,商放在
AH寄存器中,余数放在 AL寄存器中 。
例如,当 (AL)08H,(CL)08H时执行下列指令:
MUL AL,CL ; (AL)80H
AMM ; (AH)06H (AL)04H
由此可见,调整后的结果是非压缩 BCD码乘积结果 。
由于非压缩的 BCD码占一个字节,因此结果被分别存放在
AH,AL中 。
(6) 非压缩 BCD数除法调整指令 AAD。
指令格式,AAD
指令功能:将 AX寄存器中非压缩的 BCD码形式的被除数调整为二进制数,并存放在 AL寄存器中 。 AAD指令的使用要求与加法调整 AAA,减法调整 AAS,乘法调整 AAM不同,它是放在除法 DIV指令的前面来使用的,其调整方法是将 (AH)的内容乘 10H,并与 AL寄存器内容相加送到 AL寄存器中,AH寄存器清零 。
AAM和 AAD指令将根据 AL寄存器结果设置 SF,ZF和
PF标志位,CF,OF及 AF无定义 。
3.2.3逻辑运算类指令逻辑运算类指令包括逻辑与,逻辑或,逻辑非,逻辑异或及按位测试 。 逻辑运算指令所执行的操作可对字节或字进行操作,并且安位进行 。 逻辑运算指令见表 3 -5。
(1) 逻辑与 /或 /异或指令 AND/OR/XOR
指令格式,AND/OR/XOR OPRD1,OPRD2
指令功能,AND/OR/XOR指令执行按位的逻辑与,逻辑或,逻辑异或操作 。 它们均为双操作数指令,两个操作数宽度必须相等,即同为字节或字,执行结果存入 OPRD1中并且是按位进行 。
表 3 - 5逻辑运算类指令表具体指令形式:
AND/OR/XOR reg,reg
AND/OR/XOR reg,mem
AND/OR/XOR reg,imm
AND/OR/XOR mem,reg
AND/OR/XOR mem,imm
AND指令可用来屏蔽操作数所指定的字节或字中的某些位,也可用来清除某些位 。 OR指令可用来对操作数所指定的某些位进行置,1”。 XOR指令将根据异或运算规则,
对源操作数所指定的内容按位取反,取反的位只要用 XOR
指令置,1”即可完成 。 XOR还可用来进行特殊数值的判断 。
(2) 逻辑非指令 NOT。
指令格式,NOT OPRD
指令功能,对操作数所指定的内容按位求反 。
(3) 测试指令 TEST。
指令格式,TEST OPRD1,OPRD2
指令功能,对两个操作数指定的内容进行与操作,但不保留结果,只是根据结果状态,对标志位进行置位 。
由此可用 TEST指令对指定的字节或字的对应位进行测试,
并根据测试结果进行不同的操作 。 指令中用操作数 2来指定测试的位 。
3.2.4移位操作类指令移位操作类指令可以对字节或字中的各位进行算术移位,逻辑移位或循环移位 。 移位操作指令如表 3 -6 所示 。
(1) 移位指令 SHL/SAL/SHR/SAR。
指令格式,SHL/SAL/SHR/SAR OPRD,
SHL/SAL/SHR/SAR OPRD,CL
指令功能:它们分别对操作数进行逻辑左移 SHL,算术左移 SAL,逻辑右移 SHR,算术右移 SAR操作 。 可以进行字节操作,也可以进行字操作 。
指令中操作数可由任何寻址方式获得,n是位移次数 。
也可以在执行指令前,将位移的次数送到 CL寄存器中 。 图
3 - 6 为各种位移操作的功能示意 。
3-6 移位指令功能示意
C M
S A R
C M
S H R
0
C M
S A L
0
C M
S H L
0
C
RCR
C
RCL
C
R O R
C
R O L
C -进位标志; M -最高位 ( 符号位 )
表 3-6 移位操作类指令具体指令格式:
SHL/SAL/SHR/SAR reg,1
SHL/SAL/SHR/SAR mem,1
SHL/SAL/SHR/SAR reg,CL
SHL/SAL/SHR/SAR mem,CL 〖 HT5〗
移位指令对各标志位的影响如下:
① CF标志位要根据各种移位指令而定 。 OF标志位可表示移位后的符号位与移位前是否相同,即当位移为 1,移位后的最高有效位的值发生变化时,OF置,1”,否则清,0”。
② 循环指令不影响 CF和 OF以外的其它标志位 。
② 循环指令不影响 CF和 OF以外的其它标志位 。
③ 移位指令根据移位后的结果设置 SF,ZF,PF标志位,
AF标志位无定义 。
在程序设计中,常常用左移位和右移位指令实现乘以 2
或除以 2的操作 。 要进行带符号数的乘以 2或除以 2的运算,
可以通过算术左移和算术右移指令来实现 。
例如,将 (AL)的内容左移 4位的指令如下:
MOV AL,02H[WB]; (AL)00000010
AHL AL,4 [DW]; (AL)00100000,CF0
通过 AL 的结果,看出 (AL)由于左移 4位,使 (AL)× 16,
即 2× 1632 。
(2) 循环移位指令 ROL/ROR/RCL/RCR。
指令格式,ROL/ROR/RCL/RCR OPRD,n
ROL/ROR/RCL/RCR OPRD,CL
指令功能,循环移位指令包括不通过进位位的循环移位指令和通过进位位的循环移位指令 。 通过进位位的循环指令把 CF标志作为目标操作数的扩展,参与循环操作 。 与移位指令不同的是,从操作数一端移出来的位
,循环地,进入该操作数的另一端 。 循环移位指令只影响 CF和 OF两个标志,CF中只是存有最后一次循环移出的那一位值,OF的变化规则同移位操作 。
具体指令形式:
ROL/ROR/RCL/RCR reg,1
ROL/ROR/RCL/RCR mem,1
ROL/ROR/RCL/RCR reg,CL
ROL/ROR/RCL/RCR mem,CL
3.2.5
数据串是存储器中的一串字节或字的序列 。 串操作就是对串中的每一项都执行的操作 。 串操作指令如表 3- 7 所示 。
基本串操作指令有串传送 (MOVS),串比较 (CMPS)、
串扫描 (SCAS),串的存取 (LOPS,STOS)等 。 任何一个基本串操作指令的前面都可以加一个操作重复前缀使指令操作重复,这样,在处理长数据串时就比用循环软件处理快得多 。
串操作指令有以下特点:
约定以 DS,SI寻址源串,以 ES,DI寻址目标串 。 指令中不必显式指明操作数 。 其中源串的段寄存器 DS可通过加段超越前缀而改变,但目标串的段寄存器 ES不能超越 。
用方向标志规定串处理方向 。 若标志 DF0,则从低地址向高地址方向处理;若 DF1,则处理方向相反 。
表 3 - 7串操作指令在每次操作后,源串,目标串的两个地址指针 SI和 DI
都将根据方向标志 DF 的值自动增量 ( DF0) 或减量
( DF1),以指向串中下一项 。 增量 /减量的大小由串元素的长度来决定:当其为字节串时,SI和 DI加 /减 1;当其为字串时 SI和 DI加 /减 2。
通常,在串操作指令前加重复前缀用来对一个以上的串数据进行操作 。 但这时必须用 CX作为重复次数计数器,
其中存放着被处理数据串的元素个数 ( 字节个数或字个数 ) 。 串操作指令每执行一次,CX值自动减 1,直至减为 0
则停止串操作 。
重复的数据串处理过程可以被中断 。 CPU在处理数据串中的下一元素之前识别中断并转入中断服务程序 。 在中断返回以后,重复过程从中断点继续执行下去 。
除了串比较指令和串搜索指令外,其余串操作指令均不影响标志位 。
(1) 重复前缀 REP/REPE/REPNE/REPZ/REPNZ。
重复前缀不能单独使用,只能加在串操作指令前,用来控制基本串操作指令是否重复 。
① 在 MOVS,LODS,STOS指令前加上前缀 REP后,
按下列步骤不断重复执行:若 CX0,则退出 REP操作;否则 CX←CX -1,执行 REP后面的数据串指令 。 重复上述步骤 。
② 将 REPE/REPZ加在 CMPS或 SCAS指令之前时,上述重复执行步骤 ① 变为:若 CX0或 ZF0,则停止重复过程 。
③ 将 REPNE/REPNZ加在 CMPS或 SCAS指令之前时,
上述重复执行步骤 ① 变为:若 CX0或 ZF1,停止重复过程 。
(2) 基本串操作指令 。
① 串传送指令 MOVS/ MOVSB/ MOVSW。
指令格式,MOVS OPRD1,OPRD2
MOVSB
MOVSW
指令功能,MOVS指令把由 (SI)作为指针所指示的源串中的一个字节或字,传送到由 (DI)作为指针所指示的字节单元或字单元中 。 且根据方向标志 DF自动修改源串及目的串的地址指针,以指向串中的下一个元素 。 OPRD1,OPRD2
分别为目标串和源串的符号地址 。
具体指令格式:
MOVS mem,mem
MOVSB 和 MOVSW分别为字节串或字串传送指令,不带操作数,其余同 MOVS指令 。
MOVS指令要求源串必须放在数据段中,目的串必须放在附加段中,必要时允许使用段跨越前缀修改源字串所在的段 。 当所做的串操作需要重复进行时,可使用 REP前缀,并将重复次数存放在 CX寄存器中,以完成字串的传送 。
② 串比较指令 CMPS/CMPSB/CMPSW。
指令格式,CMPS OPRD1,OPRD2
CMPSB
CMPSW
指令功能,从 (SI)作为指针所指示的源串中减去 (DI)
作为指针所指示的目的串 (字节操作或字操作 ),结果不保存,用标志位的变化表示比较结果 。 同时根据方向标志
DF自动修改源串和目标串指针 SI,DI,该指令可用来检查两个串是否相同 。 字节或字操作的说明与 MOVS指令相同 。
具体指令格式:
CMPS mem,mem
若 CMPS指令用 REPE/REPZ作前缀,则表示:当串未结束 ( CX≠0) 且串相等 ( ZF1) 时继续比较 。
若 CMPS用 REPNE/REPZ作前缀,则表示,当串未结束 ( CX≠0) 且串不相等 ( ZF1) 时继续比较 。
CMPSB/CMPSW分别指明是字节串或字串比较指令,
不带操作数,其余约定与 CMPS相同 。
③ 串搜索指令 SCAS/ SCASB/ SCASW。
指令格式,SCAS
SCASB
SCASW
指令功能:从 AL( 字节操作 ) 或 AX( 字操作 ) 的内容中减去 ( DI) 作为指针所指示的目的串元素,不保存结果,只是根据结果置标志位 。
SCAS指令可用来检查两个串的值是否相同,也可用来从一个字符串中搜索某个字符 。
④ 串 元 素 存 取 指 令 STOS/STOSB/STOSW 和
LODS/LODSB/LODSW。
指令格式,STOS/LODS OPRD
STOSB/LODSB
STOSW/LODSW
指令功能,STOS指令将累加器 ( AL或 AX) 的内容存入 ES,DI指定的目标串中,同时自动修改 DI。 OPRD是目标串的符号地址 。 STOS指令前可加重复前缀 REP,从而给一个内存块赋同一个值 。 LODS指令将 DS,SI指定的源串中的元素,传送到 AL( 字节操作 ) 或 AX( 字操作 ) 寄存器中,同时自动修改 SI。 OPRD是源串的符号地址 。 该指令前一般不加重复前缀,因为每重复一次,累加器的内容就要改写一次 。
具体指令形式:
STOS/ LODS mem
STOSB /STOSW与 LODSB/ LODSW的功能分别与
STOS和 LODS相同,只是不带操作数。
3.2.6
控制转移类指令用来控制程序执行的顺序,常用的有无条件转移指令和条件转移指令 。 通过控制转移指令可实现各种结构化程序设计,如分支结构程序,循环结构程序等 。 控制转移指令如表 3 - 8 所示 。
1,无条件转移指令 JMP
指令格式,JMP OPRD
无条件转移指令可无条件地转移到由指令中的操作数所指定的目的地址,并开始执行程序 。 其中操作数所代表的目的地址可以利用各种寻址方式得到 。
表 3-8 控制转移类指令类别 指令名称 指令格式无条件转移 无条件转移 JMP标标号调用 /返回 过程调用 CALL 程名条件转移过程返回 RET 弹出值高于 /不低于也不等于转移 JA/JNBE 目标标号高于或等于 /不低于转移 JAE/JNB 目标标号低于 /不高于也不等于转移 JB/JNAE 目标标号低于或等于 /不高于转移 JBE/JNA 目标标号类别 指令名称 指令格式条件转移进位位为 1转移 JC 目标标号进位位为 0转移 JNC 目标标号等于 /结果为 0转移 JE/JZ 目标标号不等于 /结果不为 0转移 JNE/JNZ 目标标号大于 /不小于也不等于转移 JG/JNLE 目标标号大于或等于 /不小于转移 JGE/JNL 目标标号小于 /不大于也不等于转移 JL/JNGE 目标标号续表( 2)
类别 指令名称 指令格式条件转移小于或等于 /不大于转移 JLE/JNG 目标标号溢出转移 JO 目标标号不溢出转移 JNO 目标标号奇偶位为 0/奇偶性为奇转移 JNP/JPO 目标标号奇偶位为 1/奇偶性为偶转移 JP/JPE 目标标号符号标志位为 0转移 JNS 目标标号符号标志位为 1转移 JS 目标标号续表( 3)
续表( 4)
类别 指令名称 指令格式循环控制循环 LOOP 目标标号等于 /结果为 0循环 LOOPE/LOOPZ目标标号不等于 /结果不为 0循环 LOOPNE/LOOPNZ目标标号
CX内容为 0转移 JCXZ目标标号中断中断 INT 中断类型溢出时中断 INTO
中断反回 IRET
由于转移指令可采用不同的寻址方式,因此确定转移地址便成为转移指令中的一个重要问题 。 指令系统提供了以下几种寻址方式的无条件转移指令 。 (1) 段内直接短转移指令 JMP SHORT lable。
功能,无条件地转移到 lable指定的目标地址 。 指令中的操作数表示转移的目的地址与转移指令之间的距离为 8位位移量 。 即在 -128~ +127范围内转移 。
(2) 段内直接近转移指令 JMP NEAR PTR lable。
功能:无条件地转移到 lable指定的目标地址 。 指令中
NEAR PTR类型说明符,其对应的操作数为 16位的位移量 。
可在 -32 768~+32 767范围内转移,即转移到段内的任何一个位置 。
(3) 段内间接转移指令 JMP WORD PTR OPRD。
功能,无条件转移到由寄存器的内容指定的目标地址,
或者由存储器寻址方式提供的存储单元内容所指定的目标地址 。
(4) 段间直接转移指令 JMP FAR PTR lable。
功能:实现段与段之间的转移,转移到指定段内的目标地址 lable。 由于是段间转移,代码段寄存器内容需要指定,将由操作数决定的段的段地址送到代码段寄存器中,
将段内偏移地址送到指令寄存器 IP中 。 该指令采用的是直接寻址方式,故称为段间直接转移 。
(5) 段间间接转移指令 JMP DWORD PTR OPRD。
功能,完成段间的转移 。 其目的地址是除立即数和寄存器以外的存储器寻址方式所得到的 。 该指令将所寻址到的存储单元字内容 ( 16位 ) 送到指令寄存器 IP中,将其后的单元字 ( 16位 ) 送到段寄存器 CS中,由此实现段间间接转移 。
无条件直接转移指令格式中的作为转移目的地址的操作数,在汇编语言格式中可直接使用符号地址 。 在汇编之后可得到相应的段地址及偏移量 。
2,条件转移指令
8086/8088指令系统具有一系列的条件转移指令 。 这些条件转移指令以某些标志位的状态或有关标志位的逻辑运算结果作为依据,以此决定是否转移 。 这些标志位通常由条件转移指令的上一条指令所设置 。 条件转移指令将根据这些标志位的状态,判断是否满足对应的测试条件 。 若满足条件,则转移到指令指定的地方,否则继续执行条件转移指令之后的指令 。
条件转移指令都为短转移,即转移的相对地址位移范围在 -128~ +127。 当满足转移条件时,将位移量与当前的指令寄存器 IP的内容相加,由此形成所需的程序地址,并开始执行程序 。 执行条件转移指令不影响标志位 。
下面将按照单个标志位和多个标志位进行测试的分类形式介绍条件转移指令 。
(1) 测试单个标志的条件转移指令 。
① 结果为零 ( 或相等 ) 转移指令 JZ (或 JE)。
指令格式,[WB]JZ OPRD
或 [DW]JE OPRD
转移条件,ZF= 1
② 结果非零 ( 或不相等 ) 转移指令 JNZ( 或 JNE)。
指令格式,[WB]JNZ OPRD
或 [DW]JNE OPRD
转移条件,ZF= 0
③ 结果为负转移指令 JS。
指令格式,JS OPRD
转移条件,SF= 1
④ 结果为正转移指令 JNS。
指令格式,JNS OPRD
转移条件,SF0
⑤ 溢出转移指令 JO。
指令格式,JO OPRD
转移条件,OF1
⑥ 不溢出转移指令 JNO。
指令格式,JNO OPRD
转移条件,OF0
⑦ 偶状态转移指令 JP (或 JPE)。
指令格式,JP OPRD
或 JPE OPRD
转移条件,PE1
⑧ 奇状态转移指令 JNP (或 JPO)。
指令格式,JNP OPRD
或 JPO OPRD
转移条件,PF0
⑨ 低于或不高于转移或有进位转移指令 JB (或 JNAE,
JC)。
指令格式,JB(或 JNAE,JC) OPRD
转移条件,CF1
10不低于或高于转移或无进位转移指令 JNB (或 JAE,
JNC)。
指令格式,JNB (或 JAE,JNC) OPRD
转移条件,CF0
(2) 测试多个标志的条件转移指令 。
① 高于 ( 或不低于等于 ) 转移指令 JA(或 JNBE)。
指令格式,JA OPRD
或 [DW]JNBE OPRD
② 低于 ( 或等于 ) 转移指令 JNA (或 JBE)。
指令格式,JNA OPRD
或 JBE OPRD
转移条件,CF和 ZF1
③ 小于或等于 ( 或不高于 ) 转移指令 JL(或 JNGE)。
指令格式,JL OPRD
或 JNGE OPRD
转移条件,SF OF1
④ 不小于 ( 大于或等于 ) 转移指令 JNL (或 JGE)。
指令格式,JNL OPRD
或 JGE OPRD
转移条件,SF OF0
⑤ 大于 ( 或不小于或等于 ) 转移指令 JG (或 JNLE)。
指令格式,JG OPRD
或 JNLE OPRD
转移条件,(SF OF) ZF1
⑥ 小于或等于 ( 或不大于 ) 转移指令 JNG (或 JLE)。
指令格式,JNG OPRD
JLE OPRD
转移条件 ( SF OF) ZF0
在条件转移指令中,JCXZ为一特殊条件转移指令,依据 CX寄存器的值进行转移 。 若 (CX)0,则转移,否则顺序执行程序 。 其指令格式为 JCXZ OPRD。 CX寄存器通常作为计数器,根据 CX的值是否为零,决定程序是否转移 。
3,循环指令循环控制指令用于实现指令或指令组的重复操作,不仅可以通过测试条件控制循环,也可以根据测试条件提前结束循环 。
(1) 循环指令 LOOP。
指令格式,LOOP OPRD
图 3 - 7LOOP指令控制流程循环次数送 CX
循环体
CX ←( CX ) - 1
判断
( CX ) = 0?
N
Y
LOOP指令是以寄存器 CX的内容作为计数控制,作
(CX)←(CX) -1的操作,并判断 CX;当 CX≠0时,转移到由操作数指示的目的地址,即 (IP)←(IP)+ 位移量,进行循环;
当 CX0时,结束循环 。 LOOP指令控制循环的过程如图 3 - 7
所示 。 其中寄存器 CX中的值是在进入循环前送入的 。
LOOP指令控制转移的目的地址为相对地址,在机器指令格式中,相对地址在 -128~ +127B的范围内 。 在汇编指令格式中的目的地址为符号地址 。
(2) 为零或相等时循环指令 LOOPZ/LOOPE。
指令格式,LOOPZ OPRD
或 LOOPE OPRD
LOOPZ/LOOPE指令可完成当 ZF1且 CX≠0条件下的循环操作 。 在 LOOPZ或 LOOPE所做的控制循环操作过程中,
除了进行 (CX)←(CX) -1的操作,还要判断 (CX)是否为零 。
此外,还将判断标志位 ZF的值 。
(3) 非零或不相等时循环 LOOPNZ/LOOPNE。
指令格式,LOOPNZ OPRD
或 LOOPNE OPRD
LOOPNZ或 LOOPNE指令可完成当 ZF0且 (CX)≠0的条件下控制循环操作 。 其操作过程类似于 LOOPZ或 LOOPE
指令 。
循环控制指令只是根据标志位状态进行控制操作,
指令本身不影响标志位。
4,子程序调用和返回指令子程序调用及返回指令是程序设计中常用的指令 。 在执行程序的过程中,它们可实现对某一个具有独立功能子程序的多次调用操作,由此可实现模块化的程序设计 。 指令系统提供了 CALL子程序调用和 RET返回指令 。
(1) 子程序调用指令 。
指令格式,CALL
子程序调用指令可实现段间的子程序调用 。 为了保证调用之后正确地返回,CALL指令需要把 CALL指令的下一条指令的地址 (称为断点 )压入堆栈进行保护 。 下面分别讨论段内,段间的子程序调用指令所作的操作 。
对于段内的直接调用指令,其指令中的目的地址为一个 16位目的地址的相对位移量 。 CALL指令的操作可完成
(SP)←(SP) -2,并将指令寄存器 (指针 )IP压入堆栈,然后修改指令寄存器 IP的内容,即 (IP)←(IP)+ 相对位移量 。
对于段内的间接调用指令,指令中所指定的 16位通用寄存器或存储单元的内容为目的地址的位移量 。 CALL指令的操作可完成 (SP)←(SP) -2,将指令寄存器 IP压入堆栈,然后取出目的地址位移量送入指令寄存器 IP。
对于段间的直接调用指令,其目的地址不仅包括位移量,还包括段地址,它们由指令直接给出 。 因此 CALL指令的操作可完成 (SP)←(SP) -2,将现行指令的段地址 (段寄存器 CS的内容 )压入堆栈,然后作 (SP)←(SP) -2,将现行的位移量 (指令寄存器 IP的内容 )压入堆栈 。 最后将指令中所指示的段地址及位移量分别送入 CS及 IP中 。
对于段间的间接调用指令,其目的地址由指令的寻址方式所决定 。 将现行地址压入堆栈的操作同段间直接调用指令 。 将段地址及段内位移量送入段寄存器 CS及指令寄存器 IP由寻址方式来决定 。
(2) 返回指令 RET。
指令格式,RET
或 RET
子程序完成其功能操作之后,RET指令使其返回调用程序,因此,RET指令为子程序的最后一条指令 。 RET指令所完成的操作是从堆栈中弹出返回地址,送入指令寄存器
IP和段寄存器 CS。 由于子程序调用分为段内调用和段间调用,因此返回指令也可分为段内返回和段间返回 。
段内返回是指将 SP所指示的堆栈顶部弹出一个字的返回地址,送入指令寄存器 IP中 。
段间返回是指将从堆栈顶部弹出的返回地址为 2个字的内容,其中一个字送入指令寄存器 IP,另一个字送入段寄存器 CS中,以表示不同的段 。
对于段内和段间返回都可带立即数,如 RET 0004H 或
RET 4。 由于主程序在调用子程序之前,利用堆栈进行参数传递,因此利用带立即数的返回指令可以对堆栈指针 SP进行调整,即 (SP)←(SP)+ 立即数,使堆栈寄存器 SP所指示的位置为调用之前的位置 。
子程序调用和返回指令对标志位无影响 。
5.
子程序调用和返回指令用在人们事先安排好的程序中,
控制程序的执行顺序 。 而在实际的系统运行过程中或在执行程序过程中常有各种随机的,不可预知的情况出现,要求计算机也能够对其实施控制处理,这种控制称为中断控制 。
中断控制就是指当遇到突发事件时,计算机能自动执行一段处理程序,处理所发生的事件,并在处理之后,返回原程序继续执行中断了的程序 。 计算机自动执行的处理程序称为中断服务程序 。
引发中断的情况有:除法运算中的除以零所产生的溢出,输入 /输出设备与 CPU之间的通信中止等 。 CPU在响应了中断之后,断点的处理同子程序调用基本相同 。 中断控制处理不仅要保存返回地址,还要保存有关的状态信息 。
保存方法是将指令寄存器 IP,段寄存器 CS,状态寄存器
PSW的内容压入堆栈,进行保护 。 中断结束之后,将 IP、
CS,PSW弹出堆栈,继续执行被中断的程序 。
80286指令系统提供了以下三条中断指令,供程序中使用 。
(1) 中断指令 INT。
指令格式,INT TYPE
或 INT
INT指令可完成由指令中的中断类型号 (TYPE)所指定的中断服务程序的调用 。
通过中断指令中的中断类型可以计算出中断服务程序入口的向量地址 。 存储器 00000H~003FFH共 1KB单元被定义为中断向量表,存放着 256个中断服务程序入口地址 (中断向量 ),每个中断向量为 4个字节,分别存放中断服务程序的段地址和段内偏移量 。 两个高字节用于存放中断服务程序的段地址,两个低字节用于存放中断服务程序的偏移量 。 在执行 INT指令时,CPU对断点,状态进行保护之后,
将中断指令中的中断类型号 (TYPE)乘上 4,便为中断向量表的入口地址 。 取出相继的 4个字节单元的内容,即为中断服务程序入口地址,并送入 IP 和 CS,以完成中断调用 。
中断向量表如图 3 - 8 所示 。 对于 INT中断指令格式,其默认的中断类型为 3。
图 3-8 中断向量表结构中断类型 0 ( IP )
中断类型 0 ( C S)
中断类型 1 ( I P)
中断类型 1 ( C S)
中断类型 N ( I P)
中断类型 N ( C S)
中断类型 2 5 6 ( I P)
中断类型 2 5 6 ( C S)
中断向量内容地址
0 0 0 0 0
0 0 0 0 4
0 0 0 0 8
4× N
0 0 3 F C
(2) 溢出中断指令 INTO。
指令格式,INTO
INTO指令将根据溢出标志位 OF的状态,决定是否调用溢出中断处理程序 。 当 OF1时,则调用溢出中断处理程序,否则不予调用 。 INTO指令在进行断点保护之后,直接将中断类型 4的向量地址送入指令寄存器 IP和段寄存器
CS中 。 中断类型 4的入口地址为 00010H,即将 (IP)←( 10H),
(CS)←( 12H)。
(3) 中断返回指令 IRET。
指令格式,IRET
IRET指令用于实现中断返回,该指令置于中断处理程序的最后 。 返回操作将保存的断点地址,状态标志位从椎栈中弹出,送入指令寄存器 IP,段寄存器 CS以及状态寄存器 PSW中 。
以上介绍了不同形式的控制转移指令,它们从不同角度实现程序执行过程的转移,利用这些指令可实现各种结构的程序设计 。 既可对程序内部情况进行预定处理,
也可对程序外部情况提供处理 。
3.2.7处理器控制类指令处理器控制类指令主要用来对 CPU的工作状态进行控制 。
指令系统为了控制 CPU的工作状态,提供了以下几类指令,
如表 3 - 9 所示 。
1.
在前面介绍的有关指令中,已经涉及到了对标志位的影响问题,由此可以利用标志位的状态对所执行的程序进行控制 。 通过标志位处理指令,可直接对指定的标志位进行设置或消除操作 。
(1) 清进位位指令 CLC。
CLC指令用于对状态标志寄存器 FLGA的 CF标志位清
,0”,即 CF← 0。
表 3 - 9
类别 名称 操作码标志位操作进位标志置 1 STC
进位标志复位 CLC
进位标志取反 CMC
方向标志置 1 STD
方向标志复位 CLD
中断标志置 1 STI
续表( 2)
类别 名称 操作码标志位操作 中断标志复位 CLI
外同步停机 HLT
等待 WAIT
交权 ESC
封锁总线 LOCK
空操作 空操作 NOP
(2) 进位位求反指令 CMC。
CMC指令用于对标志寄存器的 FLGA的 CF标志位求反的操作,即 CF← 。
(3) 进位标志位置,1”指令 STC。
STC指令用于对标志寄存器的 FLGA的 CF标志位置
,1”,即 CF← 1。
(4) 方向标志位清,0”指令 CLD。
CLD指令用于对标志寄存器 FLGA的 DF标志位置,0”,
即 DF← 0。
CF
(5) 方向标志位置,1” 指令 STD。
STD指令用于对标志寄存器 FLGA的 DF标志位置,1”,
即 DF← 1。
(6) 中断标志位清,0”指令 CLI。
CLI指令用于对标志寄存器 FLGA的 IF标志位清,0”,
即 IF← 0。
(7) 中断标志位置,1”指令 STI。
STI指令用于对标志寄存器 IF标志位置,1”,
IF←1 。
2,工作状态控制指令
(1) 空操作指令 NOP。
NOP指令不执行任何操作,它作为单字节指令占用一个字节的单元 。 一般用它来占用字节单元,便于插入指令进行程序调试,还可利用它对定时程序中的时间进行调整 。
(2) 停机指令 HLT。
HLT指令使 CPU进入暂停状态 。 暂停状态期间,CPU
可响应外部中断 。 如 RESET复位信号,INTR,NMI的中断请求 。 中断返回后,CPU将退出暂停状态 。 通常在程序中使用 HLT指令等待中断请求 。
(3) 等待指令 WAIT。
WAIT指令可以使 CPU进入等待状态,等待状态期间
( 变为无效 ) CPU可被中断 。 当 为有效时,
CPU会停止执行 WAIT。
(4) 换码或协处理器指令 ESC。
ESC指令可向协处理器提供一条可执行的指令及相应的操作数 。 当执行 ESC指令时,协处理器监视系统总线,
并可取得操作码 。 由于 80287协处理器无寻址能力,当取得操作需要存储器访问时,80286将指定存储单元的内容送到数据总线上,否则不需要 80286做任何事情 。
BUSE BUSE
(5) 封锁指令 LOCK。
LOCK是一个可用在有关指令前面的前缀,使用了这个指令前缀的指令,可在指令执行期间封锁局部总线,以保证在多处理器及多任务下的数据安全 。
LOCK指令前缀可使 CPU的 LOCK 引脚产生一个有效电平,以实现总线封锁 。
上面已经对 8086/8088的指令系统作了介绍,由于
80X86/Pentium系列 CPU对 8086/8088的指令是向上兼容的,
关于标准的 16位 CPU80286 和 32位 CPU80386,80486和
Pentium的指令系统在本书中不再详细介绍,读者在需要的时候可以参见有关资料 。
3.3汇编语言程序设计
3.3.1汇编语言与汇编程序前面介绍了指令,指令系统及程序的基本概念,由此了解到计算机所以能够自动地工作,是因为运行程序的结果 。 计算机能够按照程序中的安排去执行相应的指令,才使得计算机看起来工作得非常有序 。 通过第一节的内容还了解到计算机可直接识别的是机器指令,而用机器指令编写的程序称为机器语言程序 。 由于机器指令是用二进制编码来表示的,既不直观又难以记忆,所以使得机器指令编写的程序在使用上受到了限制 。
为了解决机器语言使用上的不便,人们开始使用容易记忆和识别的符号指令编写程序 。 汇编语言就是用与操作功能含义相应的缩写英文字符组成的符号指令作为编程用的语言 。 因此说汇编语言实际上是一种符号语言,并且是一种面向机器的低级语言 。 在使用汇编语言编写程序时需要对计算机硬件有一定的了解 。
下面分别使用机器语言和汇编语言编写的一段小程序,
以此观察它们的不同 。
机器语言程序
0000 B0 09 MOV AL,9
0002 04 08 ADD AL,8
0004 F4 HLT
使用汇编语言编写的程序计算机是不能够直接地识别和执行的,必须经过,翻译,,将汇编语言程序,翻译,
成机器语言程序 。 这个,翻译,是由汇编程序来完成的,
汇编程序是由系统预先提供的系统软件之一,汇编程序不是简单的翻译,而是一个把源文件转换成二进制编码表示的目标文件 (,OBJ) 的过程 ( 将这个过程称为汇编 ) 。 在这个过程中,对源程序进行语法检查 ( 又称扫描 ),得到无语法错误的结果后,还要经过连接程序,使目标程序成为计算机可执行文件 (,EXE) 。 汇编语言程序转换成为计算机可运行的程序的过程如图 3 - 9 所示 。
图 3 - 9汇编语言程序的汇编过程汇编语言源程序 经汇编程序转换为目标文件 经连接程序转换成可执行文件
3.3.2
在指令系统一节中所看到的指令都是在程序运行期间由计算机来执行的指令,在汇编语言源程序中除了这些指令以外,还有伪指令和宏指令 。 伪指令又称伪操作,在汇编程序对源程序汇编期间由汇编程序处理的操作 。 伪指令可用来进行数据定义,分配存储区及指定程序结束等操作 。
下面对一些常用的伪操作作简单介绍 。
1,数据定义及存储器分配伪指令格式:
[ Varable] Mnemonic Operand;,.,Operand[ ; Comments]
其中 Varable用来表示伪指令的标号,标号通常使用符号地址表示 ;
Comments 为注释,用来说明伪指令的功能 ;
Varable及 Comments都为可选项 。
格式中的 Mnemonic 为伪指令助记符,在数据定义及存储器分配伪操作中,可用以下几种助记符完成相应伪操作,
① DB,用来定义字节 。
② DW,用来定义字 。
③ DD,用来定义双字 。
④ DQ,用来定义四个字 。
⑤ DT,用来定义十个字节 。
举例说明各伪操作的实际意义:
例如:
DATA -BYTE DB 10,4,10H
[DW]DATA -WORD DW 200,10H,-100
[DW]DATA -DW DD 5× 60,0FFFDH
[DW]MESSAGE DB ′HELLO′
以上伪指令分别把字节数据,字数据,双字数据及字符串数据存放在符号地址指定的存储单元,例题中还说明这类伪指令中操作数可以是二进制,十进制,十六进制的常数,也可为表达式及字符串常数 。 对于数值可以是正数,
也可以是负数,经过汇编后的伪指令其结果见图 3 - 10。
图 3- 10伪指令执行结果
0A
04
10
C8
00
10
9C
D A T A

B Y T E
D A T A

W O R D
D A T A

D W 2C
01
00
00
FD
FF
00
00
48
45
4C
4C
4F
M E S S A G E
由图 3 - 10 中的数据排列顺序可以看出存储单元中的数据均由补码表示,并且对于多字节的数据定义,其高字节存在于高地址单元,低字节存在于低地址单元 。 对于字符串数据存储单元中存入的是对应的 ASCII码 。
伪指令中可使用符号,?”作为操作数,它可以实现对存储单元的保留,而不存入任何数据的操作 。
例如:
OUTDATA1 DB?
ARRAY DB 5 DUP? [HT]
上面伪指令中的 DUP是重复定义子句,使用 DUP可实现大批重复数据的定义及若干个存储单元的保留 。
使用重复子句的伪指令中操作数格式为:
重复数 DUP ( 操作数项,,..,操作数项 )
例如:
BUFFER DB 100 DUP (0)
BUFFER1 DB 5 DUP (1,?)
另外,在伪指令中还可以对重复子句进行嵌套,见下面的伪指令,
BUFFER2 DB 2,2 DUP (1,2 DUP(2,3))
通过以上介绍,可从图 3 - 10 观察上例中的伪指令汇编后的结果 。
利用伪指令 DW或 DD可把变量或标号的地址偏移量或把由地址偏移量及段地址形成的全地址存入存储单元 。
DW START
DD MESS
其伪指令汇编后的情况如图 3 - 11 所示
2,表达式赋值伪操作伪指令格式,Name EQU Expression
图 3 - 11伪指令执行结果
--
--
--
--
--
--
00
O U T D A T A
A R R A Y
B U F F E R
B U F F E R 1 01
--
01
--
01
--
01
--
01
--

00
B U F F E R 2 02
01
02
03
02
03
01
02
03
03
02
S TA R T
M E S S 偏移地址
M E S S 段地址该伪指令用来给表达式赋一个名字 。 由于在有些程序中多次出现同一表达式,而使用表达式赋值伪操作 EQU将这一表达式赋值之后,凡是出现表达式的地方都可用赋予的表达式名来代替 。 特别是当表达式较复杂时,引用表达式名可体现其优势 。
伪指令格式中的 Expression不仅可以是表达式,还可以是常量和各种有效的助记符 。
COUNT EQU 10
DATA EQU 100
DATA1 EQU DATA+100
INC COUNT
ADD AX,DATA
MOV BX,DATA1
上面的例子中的伪指令说明在使用 EQU给表达式赋名时,其表达式中仍然可以使用表达式名,但是需要说明的是表达式名的使用应遵守先定义后使用的规定,否则汇编程序按错误处理。 EQU伪指令在给表达式赋予表达式名时,表达式名是不允许重复定义的,在伪操作指令中使用“=”可以实现重复定义表达式名。
例如:
DATA100

DATA200
3.
在存储器的寻址过程中需要得到存储单元所在段及段内偏移地址 。 由于源程序或数据在存储器中分别存放在代码段或数据段中,因此对于任何一段程序,在其汇编过程中要求汇编程序将源程序转换为目标程序之前必须明确地定义并赋予一个段名,汇编时根据段名确定段的性质,汇编之后,连接程序可以通过目标模块的有关信息将其连接成一个可执行程序 。
段定义伪指令格式:
Segment -Name SEGMENT

Segment -Name ENDS
段定义伪指令可对代码段,数据段,堆栈段及附加段进行定义和赋名 。 代码段的内容主要是指令及伪指令 。 数据段,堆栈段及附加段主要是定义数据,分配存储单元等说明哪些段为代码段或数据段时,需要用伪指令 ASSUME。
ASSUME在代码段中指明了段和段寄存器的对应关系 。
ASSUME伪指令格式为:
ASSUME segment -reg:segment -name
[,...′segment -reg:segment -name
格式中的 segment -reg为段寄存器,用来指定 CS、
DS,ES,SS。 segment -name是段名,与 SEGMENT段定义伪指令相对应地来确定 。 可利用下面例子中的一段程序说明以上伪指令的使用 。
NAME progrom; **********************************
DATA-SEG segment
dw 500,1000
.
.
.
DATA-SEG ends; *************************************
STACK[CD*2]SEG segment
dw 256 dup?
STACK[CD*2]SEG ends; *************************************
CODE-SEG segment
assume DS,DATA-SEG
SS,STACK-SEG
START:
mov ax,DATA[CD*2]SEG
mov ds,ax ;数据段地址送 DS
mov ax,STACK-SEG
mov ss,ax ;堆栈段地址送 SS
CODE[CD*2]SEG ends;*************************************
end START
上面源程序的代码段中,用伪指令 ASSUME只是用来明确段寄存器与段的对应关系,不具有把段地址装入对应段寄存器的功能,因此需要使用传送指令将段地址送入对应段寄存器,而代码段的段地址不需要使用该方式送入代码段寄存器中 。
4.
汇编语言源程序要求可以在开始处用伪指令给程序指定一个名字 。
伪指令的格式为,NAME module-name
或 TITLE text
格式中的 module[CD*2]name即为命名的程序模块名 。
对于格式 TITLE text,汇编程序将取 text的前 6个字符作为程序模块名,并且规定 text最多可有 60个字符 。 使用
TITLE伪指令可指定每一页打印的标题,以此可从列表文件中看到程序的说明 。 如果没有使用 NAME及 TITLE伪指令对程序命名,则源程序文件名被用来作程序模块名,我们在源程序清单上可以看到标题 。
程序结束伪指令格式为,END [ lable
格式中的标号为可选项,通常用来指示程序开始执行的起始地址 。 汇编程序在汇编过程中,END指令可使其结束 。 上例中的 START即为程序开始执行的起始地址标号,
程序模块名为 program。
5,基数控制伪指令在汇编语言源程序中,通常使用十进制数对数据进行描述,这主要是因为汇编程序默认的基数为十进制,而在必要的情况下可通过加标识字母来表示二进制 (B),八进制
(O),十进制 (D)及十六进制 (H)数 。
例如:
MOV AX,10D
MOV BX,10110010B
MOV EX,0AH
RADIX伪指令格式为,RADIX expression
其中表达式 expression的值可以是 2,8,10,16 中的任一数值 。 当使用伪指令 RADIX指定某一基数之后,对于不加标识字母的数值均可看作被指定的基数 。
例如:
MOV AX,10
RADIX 2
MOV AX,1010
RADIX 16
MOV AX,0A
MOV BX,12O
上例中所传送的数据在伪指令的指定下都为相同的数据,
当给定数据不符合默认基数时,需要加标识字母确认 。
6,指定地址伪操作在汇编语言程序中可通过伪指令使源程序在汇编过程中将产生的目标代码存放在指定的地址开始单元中,而这个起始地址最初被保存在地址计数器中 。 地址计数器在汇编过程中保存的是当前正在汇编的指令地址 。
指定地址伪指令格式为,ORG expression 和 EVEN
ORG伪指令中的 expression用来指定存放目标代码的地址,即给地址计数器赋值 。 EVEN伪指令可使下一目标代码字节的地址调整为偶数,这为字数据的操作提供了便利 。
例如:
DATA-SEG -SEGMENT
ORG 100H
DB ′program′
EVEN
DW 10,20,30,40,50
DATA-SEG ENDS
汇编之后,′program′字符串的 ASCII码被存放在偏移地址 100H开始的存储单元中,EVEN伪指令将偏移地址调整为继存放 program的 ASCII码之后的偶数地址 (即 108H),
开始存放 DW伪指令中的字数据 。
汇编程序在对源程序的汇编过程中,汇编地址计数器的值除了使用预先指定的 ORG伪指令外,其值还将随着数据定义等伪操作而变化 。 在伪指令中可以直接用 $ 来表示当前地址计数器的值,也可以在指令中使用 。
3.3.3汇编语言程序格式汇编语言程序是由指令,伪指令及宏指令组成的 。 将每一条指令又称作为一条语句,汇编语言程序中一条完整
[ name] operation operand [ ; comment]
其中,name 为名字项,通常为一符号序列; operation为操作码助记符,它可以是指令,伪指令及宏指令名;
operand为操作数,它为操作码提供数据及操作信息,可由一个或多个表达式组成; comment为语句注释,说明所在语句行的功能,其注释也可占用单独一行,常用来说明一段程序的功能,注释项分号,;,是不可缺少的 。 正确书写语句是非常重要的,要求上面四项内容之间必须留有空格,
否则会被认为是错误的命令 。
此外,[ ] 表示可选项 。 汇编语言对于每项内容都有规定,只有按规定正确来表示,语句才能被正确地汇编及执行 。
1.
名字项是指由字母 A~ Z(a~ z),数字 (0~ 9)及专用字符
(?,.,@,-,$)组成的字符序列,最长不超过 31个字符 。 名字的第一个字符不能为数字,当使用含有专用字符,,,作为名字时,,,,必须是第一个字符 。
名字项可用作标号和变量 。 作为标号表示的是符号地址,
其后跟冒号 (,);作为变量表示的是一个数据,其后不跟
,:,。 标号和变量也可以用 LABLE和 EQU伪操作来定义 。
相同的标号或变量的定义在同一程序中只能允许出现一次 。
2.
操作码指的是指令,伪指令的操作符部分,是指令系统所明确的助记符,对于宏指令则是在编写程序时来决定的 。
3.
操作数项根据操作码项的功能而确定,操作数项可以是数据 (常数,变量,表达式 ),也可以是操作数的地址,地址表达式 。 对于表达式和地址表达式,汇编过程都将计算出具体的数值 。 在表达式中可能出现各种运算的运算符,汇编过程将按照它们的优先级别进行运算 。
4.
一段完整的程序注释是很重要的,它可使程序思路显得更清楚,特别是在模块化程序设计中可通过注释将各模块的功能描述出来,大大增强了程序的可读性 。
3.3.4宏操作指令和条件汇编宏指令和条件汇编指令实际上也是一种伪指令,比起前面介绍的伪指令功能更强些 。 当在源程序中使用宏指令时,
可简化程序 。
宏是指源程序中一段具有独立功能的代码,宏指令代表一段源程序,由于多次被调用而使用宏定义伪指令将其定义成一条宏指令,并赋给这条宏指令一个名字,这个名字就可以像指令一样在程序中使用 。 当宏汇编时,宏指令就被自动地展开成为相应的机器代码而插入源程序中的宏调用处 。
1.
宏定义格式:
宏指令名,MACRO [ 形参表 ]
[ 语句 ] 宏 定 义
ENDM 宏 结其中 MACRO和 ENDM是一对伪指令,MACRO是宏定义的定义符,ENDM是宏定义的结束标志 。
宏指令名是以 MACRO标号形式出现的 。 当进行宏调用时,只要在语句的操作符部分使用该宏指令名,便可实现宏定义体中的语句所代表的功能 。 格式中的形参表是可选项 。
宏调用格式,宏指令名 [ 实参数 ]
宏调用是一种伪操作,由于伪操作是处理汇编程序的操作,因此宏调用指令在汇编过程中对宏定义体作宏展开操作 。 宏展开就是用宏定义体取代源程序中的宏指令名,
并用实参取代宏定义中的形参,并且要求实参要与形参一一对应 。
例如,宏定义
P1 MACRO X1,X2,X3
MOV AX,X1
ADD AX,X2
MOV X3,AX
ENDM
宏调用:
P1 B1,B2,B3
宏展开:
MOV AX,B1
ADD AX,B2
MOV B3,AX
2.
(1) 宏指令的嵌套 。
宏指令的嵌套,指的是在宏定义体内可以包含宏定义或可以包含宏调用 。
P1 MACRO X1,X2,X3
MOV AX,X1
ADD AX,X2
MOV X3,AX
ENDM
P2 MACRO C1,C2,C3,C4
PUSH AX
P1 C1,C2,C3
MOV C4,AX
POP AX
ENDM
宏调用:
P2 D1,D2,D3,D4
宏展开,PUSH AX
P1 D1,D2,D3
MOV D4,AX
POP AX
(2) 宏定义嵌套宏定义 。
宏定义:
ST1 MACRO R1,R2;
R1 MACRO X,Y,Z ;
PUSH AX
MOV AX,X
R2 AX,Y
ST1 SUBTRACT,SUB
宏展开:
SUBTRACT MACRO X,Y,Z
PUSH AX
MOV AX,X
SUB AX,Y
MOV Z,AX
POP AX
ENDM
在使用宏定义嵌套时,若有形式参数表,在展开后可以形成不同操作的宏定义,即外层宏调用使用不同的实参就定义了不同的内层定义,从而可以看出宏定义的嵌套,
进一步增加了宏指令的灵活性 。
从上面的两个例子中可以看到宏指令嵌套在使用上应遵守先定义后调用的原则 。 对于宏定义嵌套宏定义,在汇编时若没有外层宏调用,内层宏调用是不能进行的 。
3.
从功能上看,宏指令与子程序有类似的地方,都可以简化源程序。
子程序不仅可以简化源程序的书写,还实实在在地节省了存储空间 。 因为子程序的目标代码只有一组,它不需要重复,当主程序中有调用子程序的指令时,程序只是转到子程序处执行一次子程序的目标代码,然后再返回主程序继续执行 。
宏指令在书写源程序上虽也简化了,但是在汇编过程中,汇编程序对宏指令的处理是把宏定义体的目标代码插入到宏调用处 。 宏展开有多少次调用,在目标程序中就需要有同样次数的宏定义体的目标代码插入,所以说宏指令没有简化目标程序,也就没有节省目标程序所占用的存储空间 。
由于子程序在每一次的调用中需要保护断点,现场,
返回主程序时要恢复现场,返回断点,因此执行时间长,
速度慢 。 而宏指令在调用时不存在保护断点,现场的问题,
因而执行速度快 。 由此可以说宏指令是以存储空间作为代价提高执行速度的,而子程序是以降低执行速度来节省存储空间的 。 建议在多次调用较短的程序时使用宏指令,在多次调用较长的程序时使用子程序 。
4.
条件汇编也是汇编语言提供的一组伪操作 。 伪操作指令中指出汇编程序所进行测试的条件,汇编程序将根据测试的结果有选择地对源程序中的语句进行汇编处理,即条件汇编是指汇编程序根据条件把一段源程序包括在汇编语言程序内或者排除在外的操作 。
条件伪操作的一般格式:
IF 〈 表达式 〉
[ 条件程序块 1]
[ ELSE]
[ 条件程序块 2]
ENDIF
格式中的表达式即是条件 。 如果满足条件,则汇编条件程序块; 若不满足条件,则不汇编条件程序块 。 ELSE命令可对另一条件程序块进行汇编,格式中的表达式是由汇编程序计算的 。 对于 IF条件汇编伪指令,若表达式的值为零,
则表明不满足条件;若表达式非零,则表明满足条件 。
表 3 - 10
条件伪指令 功能
IF表达式 汇编程序计算表达式得值。若表达式值非零,则满足条件
IFE表达式 汇编程序计算表达式的值。若表达式值为零,则满足条件
IFDEF符号 若符号已在程序中的定义,或已用 EXTRN
伪指令进行了说明,则满足条件
FNDEF符号 若符号未定义货未用 EXTRN说明,则满足条件续表( 3)
条件伪指令 功能
IFB子变量 若子变量为空,则满足条件
IFNB子变量 若子变量若不为空,则满足条件
IFIDN<字符串 1 >< 字符串 2> 若字符串 1和字符串 2相同,则满足条件
IFDIF<字符串 1>< 字符串 > 若字符串 1和字符串 2相同,则满足条件
3.3.5汇编语言程序设计程序设计是指为计算机编写的,能够接受并执行的,
且具有实际意义的语句序列 。 对于汇编语言程序设计,了解指令系统,伪指令及宏指令是最基本的要求,这些内容在前面都已进行了介绍 。 合理地使用不同的指令进行汇编语言程序的编制仅仅是一个基础,是编出高质量程序的一个方面 。 然而程序设计的方法可体现出一个程序设计者的思路及运用指令的水平 。
程序设计是把解决实际问题的方法转化为程序 。 由于实际问题有简单与复杂之分,因此程序设计就需要根据解决问题的思路,运用一些基本的程序设计方法设计出解决不同问题的程序来 。 在汇编程序设计过程中,首先对要解决的问题的过程进行具体的描述,这也是编程的准备阶段,
对于较小的程序可以使用程序流程图 。 对于较大的程序可以采用模块化程序设计方法 。 无论采用流程图还是模块化的方法设计都要使用程序设计的基本程序结构来表现出来 。
基本的程序结构包括顺序结构,分支结构,循环结构及子程序结构 。 由于不同的问题可采用不同结构设计,因此需要对各种结构形式有所了解,才能找到解决某一问题的最佳程序结构形式 。
1,顺序结构程序设计顺序结构是一种最简单的程序设计结构形式 。 采用这种结构只能完成简单的任务程序设计 。 顺序结构在任何结构的程序中都会出现,因此说它是基础 。 下面举一个顺序结构的程序设计例子,要求完成表达式所规定的操作:
YX1+X2+X3。 首先分析程序设计方法:
① 表达式 YX1+X2+X3的计算过程可采用顺序执行的方法来完成,首先读入数据 X1,X2,X3;其次计算 X1、
X2,X3的和;最后保存结果到指定变量 Y中 。
② 根据计算步骤编写汇编语言程序:利用伪指令确定存储器的分配,将 X1,X2,X3定义为字变量 ;按照汇编语言源程序结构要求编写源程序 。
程序如下,
PROGRAM;***************************
DATA SEGMENT
DATA1 DW X1,X2,X3,?
DATA ENDS;***************************
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV AX,[ DATA1]
ADD AX,[ DATA1+2]
ADD AX,[ DATA1+4]
MOV [ DATA1+6],AX
HLT
CODE ENDS;***********************
END START
可以看出,上面的源程序是由数据段和代码段两部分组成的 。 在数据段定义了 X1,X2,X3为自变量,在运行时应填入具体数值 。 代码段确定了各段与段寄存器的关系,
并且以计算机的基本操作指令按顺序执行的结构形式将计算机操作过程进行描述,从而完成程序设计的最初阶段任务 。 一个源程序的编写过程还说明不了程序的正确性,必须经过上机调试,才能验证设计的程序是否符合要求 。
2,循环结构程序设计循环结构程序设计针对的是处理一些重复进行的过程的操作 。 采用循环结构设计的程序,其长度缩短了,不仅节省了内存,也使得程序的可读性大大提高 。 使用循环结构形式设计程序时,
① 循环的初始化部分:主要为循环所需的变量赋初值 。
② 循环体:程序所要完成的主要工作部分,这一部分的内容是由所要处理的问题来确定的,这一部分的执行结果可能影响到循环是否继续进行 。
③ 循环控制部分:这一部分主要是以条件表达式的结果作为是否结束循环的条件 。 在事先知道了循环次数的情况下,
可采用循环计数控制循环的结束;在事先不知道循环次数的情况下,多采用结果及给定特征作为条件来控制循环的结束 。
图 3 - 12 可以帮助我们很好地理解循环结构程序 。
图 3 - 12
(a) 单循环结构; (b) 双循环结构预置循环次数其他准备工作循环体循环减 1 计数结果为 0?
退出循环
N
Y
预置内循环次数其他准备工作循环体内循环减 1 计数结果为 0?
N
Y
预置外循环次数其他准备工作外循环减 1 计数结果为 0?
退出循环
Y
N
( a )
( b )
在编写程序之前要对解决的问题进行分析:
① 首先确定程序采用循环结构完成数据搬家操作 。
② 定义数据单元 。
③ 按顺序将原数据逐一搬家 (该步骤要求修改原数据地址,目的数据地址及搬家次数 )。
④ 搬家程序的控制是以变化的数据个数作为条件。
程序如下,MOV AX,1000H
MOV DS,AX
MOV BX,1000H
MOV DI,1500H
MOV CX,100
LOOP,MOV AL,[ BX]
MOV [ DI],AL
INC BX
INC BX
DEC CX
JNZ LOOP
HLT
下面再举一个例子说明循环结构程序设计的方法 。
假设从 BUF单元开始为一个 ASCII码字符串,找出其中的最大数送屏幕显示 。
程序流程图如图 3 - 13 所示 。
图 3 - 13找最大数数据区首址 →D S,B X
无符号最小数 0 →A L
数据个数 →C X
[ B X ] >= A L?
[ B X ] →A L
BX + 1 →B X
CX - 1 →C X
CX = 0?
显示结果返回 D O S
N
N
Y
Y
程序如下:
DATA SEGMENT
BUF DB ′ABCREF873′
COUNT EQU $-BUF ;
MAX DB ′MAX′,? /ODH,OAH,′$′
DATA-ENDS
CODE SEGMENT
ASSUME CS,CODE,DS,DATA
BEG,MOV AX,DATA
MOV DS,AX
MOV AL,0 ; 无符号最小数 0→AL
LEA BX,BUF ; 串首址偏移量 → BX
MOV CX,COUNT ; 串长度 → CX
LAST,CMP [ BX],AL ;
JC NEXT
MOV AL,[ BX] ; 大数 → AL
NEXT,INC BX
LOOP LAST ;
NEXT,INC BX
LOOP LAST ;
MOV MAX+4,AL ; 最大数 → MAX+4
MOV AH,9
MOV DX,OFFSET MAX
INT 21H ;
MOV AH,4CH
INT 21H ; 返回 DOS
CODEENDS
END BEG
在上述程序中,ASCII应看成无符号数,无符号数的最小值为 0,因此,在进行第一次比较时,把 0送 AL寄存器,
各个数都和 AL比较,每次比较后的较大的数放入 AL寄存器中,N个数需要比较 N次,若把第一个数送 AL作为初始比较对象,那么 N个数需要比较 N-1次 。
根据循环程序的嵌套层数不同,可以将循环程序的结构分成单循环,双循环和多重循环 。 上面介绍的例子是单循环的结构,下面举例说明如何进行双重循环的程序设计假设需要对无序表中的元素排序,冒泡排序是最常用的一种方法 。
设从地址 ARRAY开始的内存缓冲区中有一个字数组,
要使该数据表中的 N个元素按照从大到小的次序排列,用冒泡算法显示的过程叙述如下:
从第一个数开始依次进行相邻两个数的比较,即第一个数与第二个数比较,第二个数与第三个数比较 ……,比较时若两个数的次序符合排序要求,则不做任何操作;若次序不对,就交换这两个数的位置 。 经过这样一遍全表扫描比较后,最大的数放到了表中第 N个元素的位置上 。 在第一遍扫描中进行 N-1次比较 。 用同样的方法再进行第二次扫描,
这时只需考虑 N-1个数之间的 N-2次比较,扫描完毕,最大的数放到了表中第 N-1个元素的位置上 …… 依此类推,在进行了 N-1遍的扫描比较后将完成排序 。
下面是对有 7个元素的次序表进行冒泡排序的过程 。
表的初始状态,[ 43 36 65 95 81 12 25]
第一遍扫描比较之后,[ 36 43 65 81 12 25] 95
第二遍扫描比较之后,[ 36 43 65 12 25] 81 95
第三遍扫描比较之后,[ 36 43 12 25] 65 81 95
第四遍扫描比较之后,[ 36 12 25] 43 65 81 95
第五遍扫描比较之后,[ 12 25] 36 43 65 81 95
第六遍扫描比较之后,12 25 36 43 65 81 95
冒泡法最大可能的扫描遍数为 N-1。 但是,往往有的数据表在第 1遍 ( 1< N-1) 扫描后可能已经成序 。 为了避免后面不必要的扫描比较,可在程序中引入一个交换标志若在某一遍扫描比较中,一次交换也未发生,则表示数据已按序排列,在这遍扫描结束时,就停止程序循环,结束排序过程 。
程序如下:
DATA SEGMENT
ARRAY DW d1,d2,d3,...,dn
COUNT EQU( $ -ARRAY) / 2 ;
FLAG DB-1 ; 交换标志,
初值为 -1
DATA ENDS
STACK SEGMENT PARA STACK ′STACK′
DB 1024 DUP(? )
STACK ENDS
CODE SEGMENT
SORT,MOV AX,DATA
MOV DS,AX
MOV BX,COUNT
LP1,CMP FLAG,0 ; 数组已有序?
JE EXIT ; 是,
DEC BX ; 否,置本遍扫描比较次数
MOV CX,BX
MOV SI,0 ;
MOV FLAG,0 ; 预置交换标志为 0
LP2,MOV AX,ARRAY[ SI] ; 取一个数据 → AX
CMP AX,ARRAY[ SI+ 2] ;与下一个数比较
JLE NEXT ; 后一个数大,
转 NEXT
XCHG AX,ARRAY[ SI+2] ; 逆序,交换两
MOV ARRAY[ SI],AX
MOV FLAG,-1 ; 置交换标志为 -
1
NEXT:ADD SI,2 ; 修改地址指针
LOOP LP2 ;
JMP LP1 ; 内循环结束,继续下一轮排序
EXIT,MOV AH,4CH ; 排序完成,返回 DOS
INT 21H
CODE ENDS
END SORT
3,分支结构程序设计在解决某些实际问题时,解决问题的方法随着某些条件的不同而不同,将这种在不同条件下处理过程的操作编写出的程序称为分支程序 。 程序中所产生的分支是由条件转移指令来完成的 。 汇编语言提供了多种条件转移指令,可以根据使用不同的转移指令所产生的结果状态选择要转移的程序段,对问题进行处理 。 采用分支结构设计的程序,结构清晰,
易于阅读及调试 。
下面是一个采用分支结构设计的程序例子,要求从键盘上输入字符,A~ Z,则将其转换为对应的 ASCII码并显示;若为 0,则结束输入 。
首先使用程序流程图将解决问题的思路描述出来,如图
3 - 14 所示 。
程序如下:
abc1,MOV AH,01H;
INT 21H ;
CMP AL,0 ; 输入字符与 0
JE abc2 ; 为零结束
CMP AL,′A′ ; 判断是否小于大写字母 A
JL abc1 ; 小于大写字母 A返回重新输入
CMP AL,′Z′ ; 判断是否大于大写字母 Z
JG abc1 ; 大于大写字母 Z
MOV DL,AL ; 将 AL内容送 DL,
MOV AH,02 ;
INT 21H ; 将 A~Z
abc2,MOV AH,4CH ; 带返回码结束 INT 21H
INT 21H
图 3 -14分支程序结构开始键盘输入并显示输入为零?
输入字符
< A 否?
输入字符
< Z 否?
字符送显示器输出结束
N
Y
Y
N
N
Y
在汇编语言程序设计中,常常要使用多分支结构 。 多分支结构相当于一个多路开关,在程序设计中通常是根据某寄存器或某单元的内容进行程序转移 。
在设计多分支转移程序时,如果分支太多,则平均转移速度太慢 。 如果用转移地址表实现多分支转移,则可以提高平均转移速度 。 多分支结构如图 3 - 15 所示 。
例如,设计一个 256分支的段内程序转移程序 。
设 JUMP单元有一个数 X,若 X0,则转移到标号为
P000的程序段;若 X1,则转移到标号为 P001的程序段,……;
若 X255,则转移到标号为 P255的程序段 。
图 3 - 15多分支结构
K =?
… … …
= 0 = 1 = n
DATA SEGMENT
JUMP DB? ; 某数 X
TAB DW P000;
DW P001
……
DW P255
DATA ENDS
CODE SEGMENT
ASSUME CS,CODE,DS,DATA
BEG,MOV AX,DATA
MOV DS,AX
MOV BL,JUMP
MOV BH,0
ADD BX,BX ; 2× X→BX
MOV SI,OFFSET TAB
JMP [ BX+SI] ; DS,[ BX+SI]
→ IP
P000,...,..
P001,...,..
...,..
...,..
P255,...,..
CODE ENDS
END BEG
以上通过例子介绍了汇编语言程序设计中常用的基本结构程序形式 。 利用这些结构形式的特点以及使用要求并结合汇编语言提供的指令,可以设计出适合解决各类问题的汇编语言程序 。 这些基本结构形式不仅可以单独使用来解决一些简单的问题,还可以联合起来使用解决一些复杂的问题 。 另外在基本结构形式中还有子程序结构,这种结构在很多语言程序中都被采用,在此不作介绍 。 总之,采用基本结构形式设计方法编写出来的程序称为结构化程序,
这样的程序结构清晰,不仅容易阅读,也给修改程序,调试程序带来了便利 。