20192409潘则宇汇编语言程序设计前四章学习总结

汇编语言程序设计

概念

计算机程序设计语言可以分为机器语言、高级语言和汇编语言三类。

  机器语言:机器语言就是把控制计算机的命令和各种数据直接用二进制数码表示的一种程序设计语言。(优点:运行速度快,程序长度短;缺点:不便于记忆,难于阅读)
  高级语言:高级语言将计算机内部的操作细节屏蔽起来,用户不需要知道计算机内部数据的传送和处理的细节,使用类似于自然语言的一些语句来编制程序,完成指定的任务。(优点:程序设计简单;缺点:程序效率较机器语言低)
  汇编语言:为了方便记忆和阅读,使用字母和符号来被表示机器语言的命令,用十进制数和十六进制数来表示数据,这样的计算机程序设计语言就称为汇编语言。

汇编语言程序与机器语言程序的关系:一条汇编语言的语句与一条机器语言的指令对应,汇编语言程序与机器语言程序效率相同。

进位计数制及其相互转换

进位计数制: 使用一定个数的数码的组合来表示数字,这种表示方式称为进位计数制。根据所使用的数码的个数,就产生了不同的进位计数制。

  • 将各个位置上所表示的基本数值称为位权,简称权
  • 每个数位上所能使用的不同数码的个数称为基数

常用进位计数制
B(Binary)——二进制数
O(Octal或Q)——八进制数
D(Decimal)——十进制数
H(Hexadecimal)——十六进制数

各种数值之间的相互转换
1.十进制整数转换为二进制数
(1)减权定位法
(2)除基取余法
2.十进制小数转换为二进制数
(1)减权定位法
(2)乘积取整法
3.二进制整数转换为十进制数
(1)按权相加法
(2)逐次乘积相加法
4.二进制小数转换为十进制数
(1)按权相加法
(2)逐次除基相加法
5.二进制与八进制和十六进制之间的转换

带符号数的表示

  • 用“+”或“-”表示正负的数叫真值
  • 用“0”或“1”表示正负的数叫机器数

带符号的机器数可以用原码、补码、反码三种不同码制来表示。

  原码表示:二进制数的最高位表示符号,0表示正,1表示负。数值部分用二进制数绝对值表示。
  补码表示:带符号数X的补码表示定义为:
      [X]补=M+X(Mod M)
  其中模数M根据机器数位数而定,如位数为8则M=28
  用补码表示的机器数,符号位仍然表示数的符号:0为正,1为负。对于正数,补码与原码相同,对于负数需要进行变换(符号位不变,各位取反,末位加1)。
  补码的加减运算:规则为:
      [X+Y]补=[X]补+[Y]补
      [X-Y]补=[X]补-[Y]补=[X]补+[-Y]补

字符的表示

在计算机内部,各种字符(字母、符号、数字码)都是按照一定方式编写成二进制信息。不同的计算机以及不同的场合所采用的编码方式不同。目前最广泛采用的是ASCII码。

  非打印ASCII码(33个):用于控制操作,如BEL(响铃,07H),DEL(删除,7FH),CR(回车,0DH),LF(换行,0AH)

  可打印ASCII码(95个):如数字符0~9,大小写字母等

基本逻辑运算

  “与”运算(AND):“与”运算也叫逻辑乘,常用∧或·表示,即F=A∧B或F=A·B。
  “与”运算是指仅当逻辑变量A和B都是1时,运算结果F才为1;其他情况F为0。
  “或”运算(OR):“或”运算也叫逻辑加,常用∨或+表示,即F=A∨B或F=A+B。
  “或”运算是指当逻辑变量A和B中,至少有一个为1时,结果F为1;其他情况F为0。
  “非”运算:对逻辑变量取相反的一个逻辑值。
  “异或”运算(XOR):通常用⨁表示,即F=A⨁B。
  “异或”运算是指当A和B相同时(同时为1或者同时为0),运算结果F为0,而不同时,F为1。

IBM-PC微机基本结构

微机结构

一般计算机应包含五大部件运算器、控制器、存储器、输入设备和输出设备。
由于微机的主要特点是其体积很小,因此在系统设计上就有一些特殊考虑。

  • 将运算器和控制器两大部件集成在一个集成电路芯片上,称为中央处理器,简称CPU,也叫微处理器。
  • 系统采用总线结构,具有较大的灵活性和扩展性。

1.中央处理器CPU
  微型计算机中的中央处理器也叫微处理器。它包括运算器和控制器。
  功能:分析从主存储器取来的各条指令的功能,控制计算机各部件完成指定功能的各项操作。
2.主存储器
  主存储器是用来存放程序和数据的部件,它由若干个存储单元构成。
  存储单元的多少表示存储器的容量。每个存储单元使用一个唯一的编号来标识,称为存储单元的地址。
  对每个存储单元内容的存和取是按照地址进行访问的。
3.输入输出设备及接口
  输入设备将外部信息(程序、数据和命令)送入计算机。包括键盘、鼠标等。
  输出设备将计算机处理后的结果转换为人或其它系统能识别的信息形式向外输出。如显示器、打印机等。
  有的设备既具有输入功能又具有输出功能。如磁盘、磁带、触摸显示屏等。
4.系统总线
  系统总线将CPU、存储器和I/O设备连接起来,实现各大部件之间的各种信息传送。
  系统总线包括地址总线、数据总线和控制总线三组。它们分别用于传送不同的信息。

Intel8086/8088 CPU的功能结构

汇编语言程序是由一系列的指令(指令序列)构成。
指令是构成汇编语言程序的最基本单位,就像高级语言中的语句。

CPU执行指令序列就是重复执行以下两个步骤

  • 从存储器中取指令
  • 执行指令规定的操作

这两个步骤的执行又分为串行方式和指令流水线方式。
1.串行方式
特点:
(1)当CPU不在指令执行阶段,不需要占用系统总线,但此时总线也不工作,因此系统总线的空闲时间比较多。
(2)在从存储器取指令、取数据或存数据的时候,总线处于忙状态,其所占用的时间也较长。而CPU却只需要花很短的时间去处理,因此大部分时间处于闲置状态。
2.指令流水线方式
  采用指令流水线方式的计算机具有较高的工作效率。CPU内部采用了一种先进的指令流水线结构,这种结构可以有效而充分地利用各主要硬件资源。
(1)执行单元EU
  EU的主要任务是分析与执行指令,包括:

  • 从指令队列中取出指令代码,由控制器译码后产生相应的控制信号,控制各部件完成指令规定的操作。
  • 对操作数执行各种指定的算数或逻辑运算。
  • 向总线接口单元BIU发送访问主存或I/O的命令,并提供相应的地址和传送的数据。  

(2)总线接口单元BIU
  BIU负责CPU与存储器、I/O的信息传送。具体包括:

  • 取指令——根据CS寄存器和指令指针IP形成20位的物理地址,从相应的存储器单元中取出指令,暂存到指令队列中,等待EU取走并执行。
  • 存取数据——在EU执行指令的过程中,需要与存储器或I/O端口传送数据时,由EU提供的数据和地址,结合段寄存器,通过外部总线与存储器或I/O进行数据的存取。

Intel086/8088 CPU寄存器结构及其用途

通用寄存器:累加器、基址寄存器、计数寄存器、数据寄存器、堆栈寄存器、基址指针、源变址寄存器、目的变址寄存器;
控制寄存器:指令指针、标志寄存器;
段寄存器:代码段寄存器、数据段寄存器、附加段寄存器、堆栈段寄存器。

1.通用寄存器
(1)数据寄存器
  它包括AX、BX、CX、DX四个寄存器。它们中的每一个既可以是16位寄存器,也可以分成两个8位寄存器使用。即可以当作8个独立的8位寄存器使用。
  数据寄存器既可以用来存放参加运算的操作数,也可以存放运算的结果。
(2)指针寄存器
  指针寄存器有堆栈指针SP和基址指针BP。
  它们一般用来存放16位地址,在形成20位的物理地址时常被作为偏移量使用。

  • SP指针——在进行堆栈操作时,被隐含使用,被用来指向堆栈顶部单元。
  • BP指针——被用来指向堆栈段内某一存储单元。

(3)变址寄存器
  有两个16位的变址寄存器SI和DI,一般被用来作地址指针。

  • SI——源变址寄存器
  • DI——目的变址寄存器

2.段寄存器

8086/8088 CPU在使用寄存器的时候,将它划分成若干段。
每个段用来存放不同的内容,如程序代码、数据等等。
每个存储段用一个段存储器来指明该段的起始位置(也叫段基址)。

CPU在访问存储器时必须指明两个内容:
(1)所访问的存储单元属于哪个段,即指明使用的段寄存器。
(2)该存储单元与段起始地址(段基址)的相距多少,即偏移量。
3.指令指针IP

CPU在从存储器取指令时,以段寄存器CS作为代码段的基址指针,以IP的内容作为偏移量,共同形成一条指令的存放地址。
当CPU从内存中取出一条指令后,IP内容自动修改为指向下一条指令。

注意:IP的内容不能被直接访问,既不能用指令去读IP的值,也不能用指令给它赋值。但是可以通过某些指令的执行自动修改IP的内容。

  • 转移指令将指令中的目的地址的偏移量送入IP
  • 子程序调用指令CALL,将IP原有内容自动压入堆栈,而将子程序的入口地址偏移量自动送入IP,而返回指令RET,又自动从堆栈中弹回原有IP的内容。

4.标志寄存器

标志寄存器是用来反映CPU在程序运行时的某些状态,如是否有进位、奇偶性、结果的符号、结果是否为零等等。
8086/8088 CPU中的标志寄存器的长度为16位,但只定义了其中的9位。

标志位分为:

  • 状态标志:CF、PF、AF、ZF、SF、OF
  • 控制标志:TF、DF、IF

(1)进位标志位CF
  在进行算数运算时,若最高位(对字操作是第15位,字节操作是第7位)产生进位或借位时CF被自动置“1”,否则置“0”。
  在移位类指令中,CF也被用来存放从最高位(左移时)或最低位(右移时)移出的数值(0或1)。
(2)奇偶标志位PF
  当指令操作结果的低8位中含有1的个数为偶数时,则PF被置“1”,否则PF被置“0”。
注意:PF只反映操作结果的低8位的奇偶性,与指令操作数的长度无关。
(3)辅助进位标志位AF
  在进行算术运算时,若低字节的低四位向高四位产生进位或错位,即第3位产生进位或借位时,AF位被置“1”,否则置“0”。AF标志位用于十进制运算的调整。
注意:AF只反映运算结果低八位,与操作数长度无关。
(4)零值标志位ZF
  若运算结果各位全为0,则ZF被置“1”,否则置“0”。
(5)符号标志位SF
  将运算结果视为带符号数,当运算结果为负数的时候SF被置“1”,为正数时,则置“0”。
(6)溢出标志位OF
  当运算结果超过机器补码所能表示数的范围时,则OF置“1”,否则置“0”。
注意:溢出和进位是两个完全不同的概念,不能相互混淆。
(7)单步标志位TF
  单步标志也叫跟踪位,该标志为控制标志位。单步标志位供调试程序使用。
  当TF位被置“1”时,没执行一条指令后,CPU暂停运行,即产生单步中断。
(8)中断允许标志位IF
  该标志位为控制标志位。当IF被置“1”时,CPU可以响应可屏蔽中断,否则不允许响应可屏蔽中断。
(9)方向标志位DF
  DF也是控制标志位。它被用来规定串操作指令的增减方向。
  当DF=0时,串操作指令自动使变址寄存器(SI和DI)的内容递增。当DF=1时,串操作指令自动使变址寄存器内容递减。

存储器组织结构

1.寄存器的组成
(1)寄存器是由若干个存储单元构成
  存储单元的多少就表示了存储器的容量。
(2)每个存储单元存放相同长度的二进制数
  一个存储单元的长度一般为8位二进制数,即一个字节。
(3)每个存储单元有一个唯一的地址编号——地址
  8086/8088 CPu有20根地址线,即它可以产生20位的地址码,它的存储器寻址能力为22,即1兆字节空间
(4)任何两个相邻字节单元就构成一个字单元
  一个字存储单元(WORD)的长度为16位二进制数,即两个字节。字单元的地址为两个字节单元中较小地址字节单元的地址。
  16位长数据的存放规则是低8位放在较低地址字节单元中,高8位放在较高地址字节单元中。
(5)在定义一个地址时必须指出是字节或字类型属性
2.存储器的段结构

由于8086/8088可寻址的存储空间为1MB,需要提供20位长的地址码,而CPU内部的寄存器长度只有16位,能够直接访问的最大地址空间是64KB。

特点
(1)8086/8088 CPU将1MB的存储空间划分成若干段,每个段最大长度为64K(65536)个字节单元组成。
(2)每个段的基址(段基址)必须是一个小节的首址。
(3)逻辑段在物理存储器中可以是邻接的、间隔的、部分重叠的和完全重叠的等4种情况。
(4)在任一时刻,一个程序只能访问4个当前段中的内容。

4个段分别是代码段、数据段、堆栈段和附加段,称为当前段。4个段寄存器CS、DS、SS、ES分别保存了它们段基址的高16位地址,称为段基值。段基址的最低4位为0。(小节首址的低4位为全0)

3.逻辑地址与物理地址及对应关系
(1)物理地址
  在1MB的存储空间中,每个存储单元的物理地址是唯一的,它就是该存储单元的20位地址。
(2)逻辑地址
  一个逻辑地址包括两个部分:段基值偏移量

  • 段基值:存放在某一个段寄存器中,是一个逻辑段的起始单元地址(段基址)的高16位。
  • 偏移量:表示某个存储单元与它所在段的段基址之间的字节距离。

(3)逻辑地址转换为物理地址
  当CPU要范围跟存储器时,需要由总线接口单元BIU将逻辑地址转换为物理地址。
转换方法:将逻辑地址的段基值左移4位,形成20位的段基址(低位为0)然后与16位的偏移量相加,,结果即为20位的物理地址。
(4)逻辑地址的来源
  在程序的执行过程中,CPU根据不同操作类型访问存储器,其逻辑地址中段基值和偏移量的来源是不一样的。

  • 取指令——段基值隐含来源CS——偏移量IP
  • 堆栈操作——段基值隐含来源SS——偏移量SP
  • 取源串——段基值隐含来源DS允许替代来源CS、SS、ES——偏移量SI
  • 存目的串——段基值隐含来源ES——偏移量DI
  • 以BP作基址——段基值隐含来源SS允许替代来源CS、DS、ES——偏移量有效地址EA
  • 存取一般变量——段基值隐含来源DS允许替代来源CS、SS、ES——偏移量有效地址EA

说明:允许替代来源也叫做段超越,它表示了段基值除使用隐含的段寄存器外是否可以指定其它段寄存器来提供;有效地址EA,它表示根据指令所采用的寻址方式计算出来的段内偏移量。

堆栈及其操作方法

堆栈是一个特定的存储区,访问该存储区一般需要按照专门的规则进行操作。

堆栈的用途:主要用于暂存数据以及在过程调用或处理中断时保存断点信息。
1.堆栈的构造

堆栈一般分为专用堆栈存储器和软件堆栈

  • 专用堆栈存储器:按堆栈的工作方式专门设计的存储器
  • 软件堆栈:由程序设计人员用软件在内存中划出的一块存储区域作为堆栈来使用

堆栈的一端是固定的,称为栈底。栈底是堆栈存储区最大的地址单元。
另一端是浮动的,称为栈顶。栈顶是最后存入信息的存储单元,随着堆栈中存放信息的多少而改变。
为了指示现在堆栈中存放数据位置,通常设置一个寄存器来指示栈顶位置。其内容就像一个指针一样,因此被称为堆栈指针SP。

  在堆栈中存取数据的规则是“后进先出FILO”。
2.8086/8088堆栈的组织

在8086/8088微机中堆栈是由堆栈段寄存器SS指示的一段存储区。

(1)顶由堆栈指针SP指示。当SP内容为最大(初始)值时,表示堆栈为空,而当SP=0时,表示堆栈全满;
(2)当SP被初始化时,指向栈底+2单元,其值就是堆栈的长度。由于SP是16位寄存器,因此堆栈长度小于等于64K字节;
(3)数据在堆栈中的存放格式是:以字为单位存放,数据的低8位放在较低地址单元,高8位放在较高地址单元。
3.堆栈操作
(1)设置堆栈
  设置堆栈主要是对堆栈寄存器SS和堆栈指针SP赋值。
(2)进栈PUSH
  进栈就是把数据存入堆栈。由指令PUSH或者由机器自动实现,可以将通用寄存器、段寄存器或字存储单元的内容压入堆栈顶部。
(3)出栈POP
  出栈操作由POP指令或机器自动实现,它从堆栈顶部弹出一个字到通用寄存器、段寄存器或字存储单元。

寻址方式与指令系统

寻址方式

一条指令通常由操作码和操作数构成。

  • 操作码:表示该指令完成的具体操作,如加法、减法、乘法、移位等等。在汇编语言中使用一定的符号来表示,称为助记符。如ADD、PUSH、POP、MOV等。
  • 操作数:表示该指令的操作对象。如移位操作的被移位数,加法操作的加数等等。

寻址方式:寻找指令中所需操作数的各种方法,也就是提供指令中操作数的存放信息的方式。

各指令中提供操作数的方法有以下四种:

  • 立即数操作数——操作数在指令代码中提供
  • 寄存器操作数——操作数在CPU的通用寄存器或段寄存器中
  • 存储器操作数——操作数在内存的存储单元中
  • I/O端口操作数——操作数在输入/输出接口的寄存器中

(1)立即数寻址
  立即数寻址方式的指令中,所需操作数直接包含在指令代码中,这种操作数称为立即数。
注意:立即数只能作为源操作数,而不能作为目的操作数。
(2)寄存器寻址
  寄存器寻址方式是指指令中所需的操作数在CPU的某个寄存器中。寄存器可以是8位或16位通用寄存器,或者是段寄存器。如:AH、AL、AX、CX、DS、ES等。
(3)直接寻址
  在直接寻址方式的指令中,操作数的有效地址EA只有位移量地址分量。
  在汇编语言源程序中,直接寻址方式用符号或常数来表示。
注意:用常数表示时,必须用方括号括起来。段寄存器不能省略。
(4)寄存器间接寻址
  操作数有效地址EA直接从基址寄存器(BX或BP)或变址寄存器(SI或DI)中获得。

寄存器间接寻址就是事先将偏移量存放在某个寄存器(BX、BP、SI或DI)中,这些寄存器就如同一个地址指针。
在程序运行期间,只要对寄存器内容进行修改,就可以实现用同一条指令实现对不同存储单元进行操作。
指示存储器所在段的段寄存器可以省略,当指令中使用的是BP寄存器,则隐含表示使用SS段寄存器,其余情况则隐含使用DS段寄存器。

(5)基址寻址和变址寻址
  操作数的有效地址EA等于基地址分量或变址分量加上指令中给出的位移量。

指令中使用BX或BP时为基址寻址。指令中使用SI或DI时为变址寻址。

注意:当位移量为常数时,不能加方括号。
(6)基址变址寻址
  操作数的有效地址是三个地址分量之和,即:EA=基址+变址+位移量。

当基址选用BX时隐含使用段寄存器DS,而选用BP时则隐含使用段寄存器SS。

(7)串操作寻址方式

  • 在寻找源操作数时,隐含使用SI作为地址指针。
  • 在寻找目的串时,隐含使用DI作为地址指针。
  • 在串操作完成之后,自动对SI和DI进行修改,使它们指向下一个操作数。

(8)I/O端口寻址
在计算机系统,对I/O端口的寻址方式有以下两种方法。

  • 直接端口寻址:在指令中直接给出端口地址,端口地址一般采用2位十六进制数,也可以用符号表示。
  • 寄存器间接端口寻址:寄存器间接端口寻址:把I/O端口的地址先送到DX中,用DX作间接寻址寄存器。

指令系统

一种计算机所能执行的各种类型的指令的集合称为该计算机的指令系统。

Intel8086/8088CPU指令系统的指令可以分为六大类:

  • 传送类指令
  • 算术运算类指令
  • 位操作类指令
  • 串操作类指令
  • 程序转移类指令
  • 处理器控制类指令

从指令的格式划分,一般可以分为三种:

  • 双操作数指令:OPR DEST SRC
  • 单操作数指令:OPR DEST
  • 无操作数指令:OPR

对于无操作数指令,包含两种情况:

  • 指令不需要操作数,如暂停指令HLT。
  • 在指令格式中,没有显式地指明操作数,但是它隐含指明了操作数的存放地方,如指令PUSHF。

1.传送类指令
  传送类指令的作用是将数据信息或地址信息传送到一个寄存器或存储单元中,可以分为以下四种情况。
通用数据传送指令
  指令格式:MOV DEST,SRC
  作用:将源操作数指定的内容传送到目的操作数,即DEST<=(SRC)。
MOV指令可以分为以下几种情况:

  • 立即数传送到通用寄存器或存储单元
  • 寄存器之间的传送
  • 寄存器与存储单元之间传送

综合起来,MOV指令在使用时需注意以下几个问题:

  • 立即数只能作源操作数,且它不能传送给段寄存器。
  • 段寄存器CS只能作源操作数,段寄存器之间不能直接传送。
  • 存储单元之间不能直接传送数据。
  • MOV指令不影响标志位。

交换指令
  指令格式:XCHG DEST,SRC
  作用:源操作数和目的操作数两者内容相互交换,即:(DEST)<=>(SRC)。
标志传送指令
  对标志寄存器进行存取的指令有4条,它们都是无操作数指令,即指令隐含指定标志寄存器、AH寄存器或堆栈为操作数。

  • 取标志寄存器指令

  指令格式:LAHF
  作用:将标志寄存器的低8位送入AH寄存器,即将标志SF、ZF、AF、PF和CF分别送入AH的第7、6、4、2、0位,而AH的第5、3、1位不确定。

  • 存储标志寄存器指令

  指令格式:SAHF
  作用:将寄存器AH中的第7、6、4、2、0位分别送入标志寄存器的SF、ZF、AF、PF和CF各标志位。而标志寄存器高8位中的各标志位不受影响。

  • 标志进栈指令

  指令格式:PUSHF
  作用:先将堆栈指针SP减2,使其指向堆栈顶部的空字单元,然后将16位标志寄存器的内容送SP指向的字单元。

  • 标志出栈指令

  指令格式:POPF
  作用:将由SP指向的堆栈顶部的一个字单元的内容送入标志寄存器,然后SP的内容加2。
地址传送指令

  • 装入有效地址

  格式:LEA DEST,SRC
  作用:将SRC存储单元地址中的偏移量,即有效地址EA传送到一个16位通用寄存器中。

  • 装入地址指针指令

  格式:LDS DEST,SRC
     LES DEST,SRC
  作用:把SRC存储单元开始的4个字节单元的内容(32位地址指针)送入DEST通用寄存器和段寄存器DS(LDS指令)或ES(LES指令),其中低字单元内容为偏移量送通用寄存器,高字单元内容为段基值送DS或ES。
2.算术运算类指令

8086/8088指令系统中有加、减、乘、除指令,这些指令可以对字节数据或字数据进行运算。
参加运算的数可以是无符号数,也可以是带符号数。带符号数用补码表示。
参加运算的数可以是二进制数,也可以是十进制数(以BCD码表示)。

加法指令
  指令格式:ADD DEST,SRC
  功能:目的操作数和源操作数相加,其和存放到目的操作数中,而源操作数内容保持不变,即DEST<=(DEST)+(SRC)。
带进位加法指令
  指令格式:ADC DEST,SRC
  功能:该指令的功能与ADD基本相同,所不同的是其结果还要加上进位标志CF的值,即:DEST<=(DEST)+(SRC)+CF。
加1指令
  指令格式:INC DEST
  功能:该指令为单操作数指令,其功能是将目的操作数加1,并送回到目的操作数,即:DEST<=(DEST)+1。
减法指令
  指令格式:SUB DEST,SRC
  功能:目的操作数的内容减去源操作数的内容,结果送入目的操作数,源操作数中内容保持不变。即:DEST<=(DEST)-(SRC)。
带借位减法
  指令格式:SBB DEST,SRC
  功能:该指令的功能与SUB指令基本相同,不同的是在两个操作数相减后再减去进位标志CF的值。即:DEST<=(DEST)-(SRC)-CF。
减1指令
  指令格式:DEC DEST
  功能:该指令为单操作数指令,将目的操作数的内容减1后,送回到目的操作数。即:DEST<=(DEST)-1。
求负数指令
  指令格式:NEG DEST
  功能:用零减去目的操作数的内容,并送回目的操作数,即:DEST<=0-(DEST)。
3.位操作指令
逻辑运算指令
逻辑运算指令共有4条,它们的指令格式分别是:
  逻辑“与”指令 AND DEST,SRC
  逻辑“或”指令 OR DEST,SRC
  逻辑“异或”指令 XOR DEST,SRC
  逻辑“非”指令 NOT DEST
测试指令
  指令格式:TEST DEST,SRC
  功能:该指令的功能与AND指令相似,实现源操作数与目的操作数进行按位“逻辑与”运算,对标志位的影响与AND指令相同,但运算的结果不送入目的操作数,即目的操作数内容也将保持不变。TEST指令主要用于测试某一操作数的一位或几位的状态。
移位/循环移位指令

  • 算术移位:

   算术左移 SAL DEST,COUNT
   算术右移 SAR DEST,COUNT

  • 逻辑移位:

   逻辑左移 SHL DEST,COUNT
   逻辑右移 SHR DEST,COUNT

  • 循环移位:

  循环左移 ROL DEST,COUNT
  循环右移 ROR DEST,COUNT
  带进位循环左移 RCL DEST,COUNT
  带进位循环右移 RCR DEST,COUNT
这8条指令具有以下几个共同点:

  • DEST为操作对象,它可以是字节或字操作数,可以是通用寄存器或存储器操作数。
  • COUNT用来决定移位/循环的位数,即确定移位的次数。
  • 在执行移位时,根据指令不同,每移位一次,最高位(左移)或最低位(右移)都要送到进位标志CF。
  • 前4条移位指令根据移位结束后修改标志位CF、PF、ZF、SF和OF,而AF不确定。而后4条循环移位指令根据移位结束后的结果仅修改CF和OF。

4.处理器控制类指令
标志位操作指令
  它们都是无操作数指令,操作数隐含为标志寄存器的某个标志位。能直接操作的标志位有CF、IF和DF。

  • 清除进位标志:CLC;置CF为0
  • 置1进位标志:STC;置CF为1
  • 进位标志取反:CMC;CF的值取反
  • 清除方向标志:CLD;置DF为0
  • 置1方向标志:STD;置DF为1
  • 清除中断标志:CLI;置IF为0
  • 置1中断标志:STI;置IF为1

与外部事件同步的指令

  • HLT;暂停指令
  • WAIT;等待指令
  • ESC;外部协处理器指令前缀
  • LOCK;总线锁定指令

空操作指令 NOP
  执行一次NOP占用CPU三个时钟周期,它不改变任何寄存器或存储单元内容,主要用于延时。

指令编码

Intel8086/8088汇编指令的编码格式有四种基本格式:

  • 双操作数指令编码格式
  • 单操作数指令编码格式
  • 与AX或AL有关的指令编码格式
  • 其它指令编码格式

(1)双操作数指令编码格式
  对于像MOV、ADD、AND等双操作数指令,操作数可以是以下两种情形:

  • 一个操作数在寄存器中,另一操作数在寄存器或存储器中。
  • 目的操作数在寄存器或存储器中,源操作数是立即数。

操作特征部分
这部分为指令编码的首字节,它又分为以下三个段:

  • OPCODE:操作码字段——该字段长度为6bit。它表示了该指令所执行的功能和两个操作数的来源。
  • 方向字段d——该字段与第2部分寻址特征一起来决定源操作数和目的操作数的来源。
  • 字/字节字段W——当W=1时,表示两操作数长度为字;当W=0时,表示两操作数长度为字节。

寻址特征部分

它与操作特征部分的方向字段d结合,指定两个操作数分别使用什么寻址方式,及使用哪个寄存器。
它包括MOD、REG和R/M三个字段,REG字段确定一个操作数,而MOD和R/M字段确定另一个操作数。

  • 当d=1时,则目的操作数由REG字段确定,而源操作数由MOD和R/M字段确定。
  • 当d=0时,则目的操作数由MOD和R/M 字段确定,而源操作数由REG字段确定。

REG字段
  由REG字段确定的一个操作数是某一通用寄存器的内容,即使用的是寄存器寻址方式。
寻址方式字段MOD和寄存器/存储器字段R/M:
  这两个字段共同确定一个操作数。该操作数可以在寄存器中,也可以在存储器中。
位移量部分
  根据寻址特征中MOD和R/M字段确定的有效地址计算方法,位移量可以是以下三种情况之一:

  • 没有位移量
  • 1字节位移量disp8
  • 2字节位移量disp16

立即数部分
  如果指令的源操作数为立即数,则指令编码中包含有该部分。它总是位于指令编码的最后1~2字节。
(2)单操作数指令编码格式

这种编码格式适用于只有一个操作数的指令,如INC、DEC、移位/循环等指令。指令编码为2~3字节。

操作特征部分:
  包括OPCODE 、V和W三个字段,其中V字段只有移位/循环指令中才有该字段,其它指令中没有该字段。
(3)与AX或AL有关的指令编码格式

这种编码格式用于隐含指定AX/AL作为一个操作数的双操作数指令,其编码格式为:

  采用这种编码格式的指令,除一个操作数隐含指定为AX/AL外,另一个操作数可以是立即数或存储单元。
  立即数:则编码中应有1~2字节的立即数
  存储单元:只能使用直接寻址方式,位移量由disp字段给出
(4)其它指令编码格式
  除上述三种编码格式外,还有一些指令的编码格式更简单。如标志位操作指令、堆栈操作指令等。这些指令的编码格式一般只有一个字节。

汇编语言语句种类及其格式

汇编语言的语句可以分为指令语句和伪指令语句。

1.指令语句
  每一条指令语句在汇编时都要产生一个可供CPU执 行的机器目标代码,它又叫可执行语句。
指令语句的一般格式为:

(1)标号字段
  标号是可选字段,它后面必须有“:”。标号是一 条指令的符号地址,代表了该指令的第一个字节存放地址。
  标号一般放在一个程序段或子程序的入口处,控制程序的执行转到该程序位置。
  在转移指令或子程序调用指令中,可直接引用这个标号。
(2)指令助记符字段
  该字段是一条指令的必选项,它表示这条语句要求CPU完成什么具体操作,如MOV、ADD、SHL等。
  有些指令还可以在指令助记符的前面加上前缀,实 现一定的附加操作。如串操作指令前所加的重复前 缀REP等。
(3)操作数字段
  一条指令可以有一个操作数、两个操作数或者无操作数。
  如ADD、MOV指令需要两个操作数,INC、NOT 指令只需一个操作数,而CLC指令不需要操作数。
(4)注释字段
  注释字段为可选项,该字段以分号“;”开始。它的作用是为阅读程序的人加上一些说明性内容。
  注释字段不会产生机器目标代码,它不会影响程 序和指令的功能。
  注释字段可以是一条指令的后面部分,也可以是整个语句行。
2.伪指令语句
  伪指令语句又叫命令语句。伪指令本身并不产生对应的机器目标代码。它仅仅是告诉汇编程序对其后面的指令语句和伪指令语句的操作数应该如何处理。
  一条伪指令语句可以包含四个字段。如下所示:

(1)符号名字段
  该字段为可选项。根据伪指令的不同,符号名可以是常量名、变量名、过程名、结构名和记录名 等等。
  一条伪指令语句的符号名可以作其它伪指令语句或指令语句的操作数,这时它表示一个常 量或 存储器地址。
(2)伪指令符字段
  该字段是伪指令语句的必选项,它规定了汇编程序所要完成的具体操作。本章后面的章节将对各种伪指令作详细介绍。
(3)操作数字段
  该字段是否需要,以及需要几个是由伪指令符字段来决定。
  操作数可以是一个常数(二进制、十进制、十六进制等)、字符串、常量名、变量名、标号和一些专用符号(如BYTE、FAR、PARA等)。
(4)注释字段
  注释字段为可选项,该字段必须以分号开始。其作用与指令语句的注释字段相同。
3.标识符
  指令语句中的标号和伪指令语句中符号名统称为标识符。标识符是由若干个字符构成的。
标识符构成规则

  • 字符的个数为1~31个;
  • 第一个字符必须是字母、问号、@或下划线“_”这4种字符之一;
  • 从第二个字符开始,可以是字母、数字、@、“_”或问号“?”;
  • 不能使用属于系统专用的保留字。

保留字: CPU中各寄存器名(如AX、CS等),指令助记符(如MOV、ADD),伪指令符(如SEGMENT、DB)、表达式中的运算符(如GE、 EQ)以及属性操作符(如PTR、OFFSET等)

汇编语言数据

数据是指令和伪指令语句中操作数的基本组成部分。一个数据由数值和属性两部分构成。
在说明数据时不仅要指定其数值,还需说明它的属性,比如是字节数据还是字数据。
在汇编语言中常用的数据形式有:常数、变量和标号。

1.常数
  常数在汇编期间其值已完全确定,并且在程序运行过程中,其值不会发生变化。
常数有以下几种形式

  • 二进制数:以字母B结尾,如01001001B
  • 八进制数:以字母O或Q结尾,如631Q 254O
  • 十进制数:以字母D结尾,或者没有结尾字母。如2007D、2007
  • 十六进制数:以字母H结尾,如3FEH,如果常数的第一个数字为字母,为了与标识符加以区别,必须在其前面冠以数字“0”
  • 实数。一般格式为:±整数部分.小数部分E±指数部分
  • 字符串常数:用引号(单引号或双引号)括起来的一个或多个字符,这些字符以它的ASCII码值存储在内存

常数在程序中可以用在以下几种情况:

  • 作指令语句的源操作数
  • 在指令语句的直接寻址方式、变址(基址)寻址方式或基址变址寻址方式中作位移量
  • 在数据定义伪指令中使用

2.变量

变量用来表示存放数据的存储单元,这些数据在程序运行期间可以被改变 。
程序中以变量名的形式来访问变量,因此,可以认为变量名就是存放数据的存储单元地址。

(1)变量的定义与预置
  定义变量就是给变量在内存中分配一定的存储单元。也就是给这个存储单元赋与一个符号名,即变量名,同时还要将这些存储单元预置初值。
当变量被定义后,就具有了以下三个属性

  • 段属性——它表示变量存放在哪一个逻辑段中。
  • 偏移量属性(OFFSET)——它表示变量所在位置与段起始点之间的字节数。
  • 类型属性——它表示变量占用存储单元的字节数。其中DB伪指令 定义的变量为字节,DW定义的变量为字,DD定义的为双字(4字节),DQ定义的为4字,DT定义的为5字。

在变量的定义语句中,给变量赋初值的表达式可以使用下面4种形式:

  • 数值表达式
  • ?表达式——不带引号的问号“?”表示可以预置任意内容。
  • 字符串表达式——对于DB伪指令,字符串为用引号括起来的不超过255 个字符。给每一个字符分配一个字节单元。字符串按从左 到右,将字符的ASCII编码值以地址递增的排列顺序依次 存放。
  • DUP表达式——DUP称为重复数据操作符。

(2) 变量的使用

  • 在指令语句中引用——在指令语句中直接引用变量名就是对其存储单元的内容进行存取
  • 在伪指令语句中引用——后面三条伪指令的操作数中都包含了前面定义的两个变量

(3)标号

标号写在一条指令的前面,它就是该指令在内存的存放地址的符号表示,也就是指令地址的别名。
标号主要用在程序中需要改变程序的执行顺序时,用来标记转移的目的地,即作转移指令的操作数。

每个标号具有三属性

  • 段属性(SEG)——它表示该标号所代表的地址在哪个逻辑段中,即段基值。
  • 偏移量属性(OFFSET)——它表示该标号所代表的地址在段内与段起点间的字节 数,即地址的偏移量。
  • 距离属性(也叫类型属性)——它表示该标号可以被段内还是段间的指令调用。

NEAR(近):该标号只能作段内转移,也就是说只能是与该标号所指指令同在一个逻辑段的转移指令和调用指令才能使用它。
FAR(远):该标号可以被非本段的转移和调用指令使用。
标号的距离属性可以有两种方法来指定:

  • 隐含方式
  • 用LABEL伪指令给标号指定距离属性

符号定义语句

在源程序设计中,使用符号定义语句可以将常数或表 达式等内容用某个指定的符号来表示。在8086/8088汇编语 言中有两种符号定义语句。

(1)等值语句
  语句格式:符号名 EQU 表达式
  功能:用符号名来表示EQU右边的表达式。后面的程序中一旦出现该符号名,汇编程序将把它替换成该表达式。
表达式可以是任何形式,常见的有以下几种情况:

  • 常数或数值表达式
  • 地址表达式
  • 变量、寄存器名或指令助记符

(2)等号语句
  格式:符号名=表达式
  等号语句与等值语句具有相同的作用。但等号语句可以对一个符号进行多次定义。

表达式与运算符

表达式是指令或伪指令语句操作数的常见形式。它由常数、变量、标号等通过操作运算符连接而成。

注意:任何表达式的值在程序被汇编的过程中进行计算确 定,而不是到程序运行时才计算。
8086/8088宏汇编语言中的操作运算符非常丰富,可以 分为以下五类:

  • 算术运算符

  包括:+、—、*、 / 、MOD、SHL、SHR、[ ]
  运算符“+”和“-”也可作单目运算符,表示数的正负。
  使用“+”、“-”、“*”、和“/”运算符时,参加运算的数和运算结果都是整数。
  “/”运算为取商的整数部分,而“MOD”运算取除法运算的余数。
  “SHR ”和“SHL ”为逻辑移位运算符。
  下标运算符“[ ]”具有相加的作用。

  • 逻辑运算符

  包括:NOT、AND、OR和XOR

  • 关系运算符

  包括:EQ(等于)、NE(不等于)、LT(小
于)、 LE(小于等于)、GT(大于)、 GE(大于等于)

关系运算符用来比较两个表达式的大小。关系运算符如果是常量的比较,则按无符号数进行比较;如果是变量的比较,则比较它们的偏移量的大小。比较的两个表达式必须同为常数或同一逻辑段中的变量。
关系运算的结果只能是“真”(全1)或“假”(全0)。

  • 数值返回运算符

该类运算符有5个,它们将变量或标号的某些特征值或存储单元地址的一部分提取出来。
SEG运算符
  作用:取变量或标号所在段的段基值。
OFFSET运算符
  作用:取变量或标号在段内的偏移量。
TYPE运算符
  作用:取变量或标号的类型属性,并用数字形式表示。对变量来说就是取它的字节长度。
LENGTH运算符
  作用:取变量的长度。
SIZE运算符
  作用:作用于变量,SIZE取值等于LENGTH和TYPE两个运算符返回值的乘积。

  • 属性修改运算符

这一类运算符用来对变量、标号或存储器操作数的类型属性进行修改或指定。
PTR运算符
  使用格式:类型 PTR 地址表达式
  作用:将地址表达式所指定的标号、变量或用其它形式表 示的存储器地址的类型属性修改为“类型”所指的值。
HIGH/LOW运算符
  使用格式:HIGH 表达式/LOW 表达式
  作用:将表达式的值分离出高字节和低字节。
THIS运算符
  THIS运算符一般与等值运算符EQU连用,用来定义一个变量或标号的类型属性。所定义的变量或标号的段基值和偏移量与紧跟其后的变量或标号相同。
运算符的优先级
  在一个表达式中如果存在多个运算符时,在计算时就有先后顺序问题。不同的运算符具有不同的运算优先级别。

优先级别 运算符
(最高)1 LENGTH,SIZE ,圆括号
  2 PTR,OFFSET,SEG,TYPE,THIS
  3 HIGH,LOW
  4 *,/,MOD,SHR,SHL
  5 +,-
  6 EQ,NE,LT,LE,GT,GE
  7 NOT
  8 AND
(最低)9 OR,XOR

汇编程序在计算表达式时,按以下规则进行运算:

  • 先执行优先级别高的运算,再算较低级别运算;
  • 相同优先级别的操作,按照在表达式中的顺序,从左到右进行;
  • 可以用圆括号改变运算的顺序。

程序的段结构

8086/8088在管理内存时,按照逻辑段进行划分, 不同的逻辑段可以用来存放不同目的的数据。在程序中使用四个段寄存器CS,DS,ES和SS来访问它们。

  在源程序设计时,使用伪指令来定义和使用这些逻辑段。
1.段定义伪指令
  伪指令SEGMENT和ENDS用于定义一个逻辑段。使
用时必须配对,分别表示定义的开始与结束。
段定义伪指令语句各部分的作用如下:
(1)段名

段名是由用户自己任意选定的,符合标识符定义规则的一个名称。
最好选用与该逻辑段用途相关的名称。如第一个数据段为DATA1,第二个数据为DATA2等。
一个段的开始与结尾用的段名必须一致。

(2)定位类型

定位类型用于决定段的起始边界,即第一个可存放数据 的位置(不是段基址)。它可以有4种取值。

  • PAGE: 表示该段从一个页面的边界开始
  • PARA:表示该段从一个小节的边界开始
  • WORD:表示该段从一个偶数字节地址开始,即段起始单元地址的最后一位二进制数一定是0。
  • BYTE:表示该段起始单元地址可以是任一地址值。

注意:定位类型为PAGE和PARA时,段起始地址与段基址相同。定位类型为WORD和BYTE时,段起始地址与段基址 可能不同。
(3)组合类型

组合类型说明符用来指定段与段之间的连接关系和定位。 它有六种取值选择。

  • 若未指定组合类型,表示本段与其它段无连接关系。在装入内存时,本段有自己的物理段,因此有自己的段基址。
  • PUBLIC:在满足定位类型的前提下,将与该段同名的段邻接在一起,形成一个新的逻辑段,共用一个段基址。段内的所有偏移量调整为相对于新逻辑段的段基址。
  • COMMON: 产生一个覆盖段。在多个模块连接时,把该段与其它也用COMMON说明的同名段置成相同的段基址,这样可达到共享同一存储区。共享存储区的长度由同名段中最大的段确定。
  • STACK:把所有同名段连接成一个连续段,且系统自动对SS段寄存器初始化为该连续段的段基址。并初始化堆栈指针SP。
  • AT表达式:表示本段可定位在表达式所指示的小节边界上。表达式的值也就是段基值。
  • MEMORY:表示本段在存储器中应定位在所有其它段之后的最高地址上。如果有多个用MEMORY说明的段,则只处理第一个用MEMORY说明的段。其余的被视为COMMON。

(4)类别名

类别名为某一个段或几个相同类型段设定的类型名称。系 统在进行连接处理时,把类别名相同的段存放在相邻的存储 区,但段的划分与使用仍按原来的设定。

  类别名必须用单引号引起来。所用字符串可任意选定,但它不能使用程序中的标号、变量名或其它定义的符号。
  在定义一个段时,段名是必须有的项,而定位类型、组合类型和类别名三个参数是可选项。各个参数之间用空格分隔。各参数之间的顺序不能改变。
2.段寻址伪指令
  段寻址伪指令ASSUME的作用是告诉汇编程序,在处理源程序时,定义的段与哪个寄存器关联。
  ASSUME并不设置各个段寄存器的具体内容,段寄存器的值是在程序运行时设定的。
  一般格式 :ASSUME 段寄存器名:段名,段寄存器名:段名,......
  其中段寄存器名为CS,DS,ES和SS四个之一,段名是用SEGMENT/ENDS伪指令定义的段名。

  • 在一个代码段中可以有几条ASSUME伪指令,对于前面的设置,可以用ASSUME改变原来的设置。
  • 一条ASSUME语句不一定设置全部段寄存器,可以选择其中一个或几个段寄存器。
  • 可以使用关键字NOTHING将前面的设置删除。

3.段寄存器的装入
  段寄存器的初值(段基值)装入需要用程序的方法来实现。四个段寄存器的装入方法略有不同。
(1)DS和ES的装入
  在程序中,使用数据传送语句来实现对DS和ES的装入。
(2)SS的装入
SS的装入有两种方法:

  • 在段定义伪指令的组合类型项中,使用STACK参数,并在段寻址伪指令ASSUME语句中把该段与SS段寄存器关联。
  • 如果在段定义伪指令的组合类型中,未使用STACK参数,或者是在程序中要调换到另一个堆栈,这时,可以使用类似于DS和ES的装入方法。

(3)CS的装入
  CPU在执行指令之前根据CS和IP的内容来从内存中提取指令,即必须在程序执行之前装入CS和IP的值。因此,CS和IP的初始值就不能用可执行语句来装入。
装入CS和IP一般有下面两种情况:

  • 由系统软件按照结束伪指令指定的地址装入初始的CS和IP。
  • 在程序运行期间,当执行某些指令时,CPU自动修改CS和IP,使它们指向新的代码段。

过程定义伪指令(PROC/ENDP)

在程序设计过程中,常常将具有一定功能的程序段设计成一个子程序。在MASM宏汇编程序中,用过程(PROCEDURE)来构造子程序。
过程名是子程序的名称,它被用作过程调用指令CALL的目的操作数。它类同一个标号的作用。具有段、偏移量和距离三个属性。而距离属性使用NEAR和FAR来指定,若没有指定,则隐含为NEAR。

  NEAR过程只能被本段指令调用,而FAR过程可以供其它段的指令调用。
  每一个过程中必须包含有返回指令RET,其作用是控制CPU从子程序中返回到调用该过程的主程序。

当前位置计数器$与定位伪指令ORG(Origin)

汇编程序在汇编源程序时,每遇到一个逻辑段,就要为其设置一个位置计数器,它用来记录该逻辑段中定义的每一个数据或每一条指令在逻辑段中的相对位置。
在源程序中,使用符号\(来表示位置计数器的当前值。因此,\)被称为当前计数器。它位于不同的位置具有不同的值。

定位伪指令ORG:用来改变位置计数器的值。
格式: ORG 数值表达式
作用:将数值表达式的值赋给当前位置计数器$。ORG语句为其后的数据或指令设置起始偏移量。

标题伪指令TITLE

语句格式:TITLE 标题名
作用:给所在程序指定一个标题。以便在列表文件的每一页的第一行都显示这个标题。其中标题是用户任意选用的字符串,字符个数不能超过60。

从程序返回操作系统的方法

为了使程序运行结束后,能够正确地返回到操作系统,需要在程序中加上一些必要的语句。一般有以下两种方法。

(1)使用程序段前缀PSP(Program Segment Prefix)实现返回
  DOS系统将一个.EXE文件(可执行文件)装入内存时,在该文件的前面生成一个程序段前缀PSP,其长度为100H字节。同时让DS和ES都指向PSP的开始,而CS指向该程序的代码段,即第一条可执行指令。
为了使程序执行完后,正确返回DOS,需要做以下三个操作:

  • 将用户程序编制成一个过程,类型为FAR;
  • 将PSP的起始逻辑地址压栈,即将INT 20H指令的地址压栈;
  • 在用户程序结尾处,使用一条RET指令。执行该指令将使保存在堆栈中的PSP的起始地址弹出到CS和IP中。

(2)使用DOS系统功能调用实现返回
  执行DOS功能调用4CH,也可以控制用户程序结束,并返回DOS操作系统。
在程序结束时,使用两条指令:MOV AH,4CH
              INT 21H

posted @ 2022-03-13 18:25  20192409潘则宇  阅读(82)  评论(0编辑  收藏  举报