目录
目录
第一章 计算机基本知识
计算机系统的概述
硬件
软件
计算机中的数制
十进制、二进制、十六进制转化
BCD码
原码、反码、补码
机器语言、汇编语言、高级语言
第二章 80X86微处理器及系统结构
8086微处理器结构
寄存器
控制寄存器:IP、PSW(OF、CF、ZF、SF、PF、AF)
8086存储器的组织,存储单元的地址和内容
存储地址的分段
第三章 操作数的寻址方式
处理器寻址方式的默认组合
操作数的类型
七种寻址方式
第四章 汇编指令详解
数据传送指令:MOV、XCHG、XLAT、PUSH、POP、标志传送指令、地址传送指令
交换指令:XCHG
查表指令:XLAT(用到BX和AL)
堆栈指令:PUSH 和 POP
标志传送指令:LAHF、SAHF、PUSHF、POPF
地址传送指令:LEA ,LDS ,LES
运算指令:ADD、ADC、INC 、SUB 、SBB、DEC、CMP
乘法指令:MUL、IMUL
除法指令:DIV、IDIV
符号扩展指令:CBW、CWD
十进制数调整指令:DAA、DAS、AAA、 AAS、AAM、AAD
逻辑运算指令: AND、OR、XOR、TEXT
移位指令:SAL、SAR、SHL、SHR、ROR、ROL、RCR、RCL
控制转移指令: JMP、JCC、LOOP、CALL、RET
字符串操作指令:MOVS(B/W)、STOS(B/W)、LODS(B/W)、CMPS(B/W)、SCAS(B/W)、REP、REPZ、RZPNZ
处理器控制指令:NOP、LOCK、HLT、ESC、WAIT
输入/输出指令: IN、OUT
中断指令和中断返回指令:INT、IRET
第五章 系统功能的调用(五个初学者必须掌握的)
1.单个字符的输入(1号功能的调用)
2.单个字符输出、显示(2号功能调用)
3.字符串输出、显示(9号功能调用)
4.字符串输入(10号功能的调用)
5.返回DOS调用(4CH号功能的调用)
第六章 零碎小知识
第七章 汇编语言的程序格式
汇编语言格式
汇编语言的程序格式
汇编语句参数
数值型参数
地址型参数
特殊运算符
第八章 调试DEBUG相关
DUBUR命令
期末考试记录
第一章 计算机基本知识
计算机系统的概述
- 汇编语言:是一种直接在硬件上面工作的编程语言。
- 汇编语言:是面向机器的语言。
- 汇编语言:重点是如何利用硬件系统的编程结构和指令集有效灵活的控制系统进行工作。
- 完整的计算机系统由硬件系统(就是指我们所能莫到的实物)和软件系统(就是虚拟的,在计算机里面的东西)。
- 硬件是软件建立和依托的基础,软件是计算机系统的灵魂。两者不可分割。
- 用机器指令语句、伪指令语句、宏指令语句表示的一种面向机器的语言称为 汇编语言 。
- 用该语言编写的程序需要经过 汇编 翻译,成为计算机能直接识别并执行的程序称机器语言。
硬件
1.硬件由五大功能部件组成:
下图所示
- 虚线表示:控制信号,起控制的作用
- 实线表示:数据或者指令,在计算机内部,数据指令都是以二进制的形式存储的
2.五大部件之间的联系是由总线(公共的信号线),是计算机中 传送信息的公共通道。
总线(用来传送以下三种信息)有:
- 地址总线(20位):传送地址信息
- 数据总线(16位):传送数据信息
- 控制总线(16位):传送控制信号
3.五大部件的功能
输入设备:如键盘、鼠标、扫描仪等,当计算机要进行数据处理时,必须将程序和数据送到内存转化为计算机所能识别的电信号(0和1)。
输出设备:将产生的各种电信号在显示器上面显示、打印机上打印、外存储器上存放等,将计算机的内部信息传递出去。
运算器:进行算术运算(加减乘除等)和逻辑运算(与或非等,指非算术运算),运算器在控制器的作用下,从内存取出数据在运算器里面进行一系列的操作,处理的结果送回存储器。
控制器:是协调各部件的中枢,就像人的大脑,也就是 计算机中的计算机,指挥并协调计算机的各个部件工作,主要机理是采用内部存储信号来实现。
存储器:用来存放程序和数据,分为主存储器和辅助存储器
- <主存储器>:就是内存,内存储器,在控制器的控制下,与运算器、输入输出设备交换信息,目前都是由超大规模的半导体集成器件组成。由RAM和ROM组成
- RAM:叫随机读/写存储器:在这里面的程序和数据,一旦电脑关机就全部丢失
- ROM:只读存储器:就好像我们电脑里面的数据存储的位置,里面的东西我们在开关机前已经有自己的存储位置,就是说放到了RAM里面。
- 其中运算器的速度很快,主存的速度比运算器要慢,因此在中央处理器内部增加了高速缓冲
- <辅助存储器>:外存储器,外存。比如:U盘,光碟,以前的录音带等。
小总结:CPU(中央处理器)是指:将运算的逻辑部件、寄存器部件和控制部件等集成在一起叫中央处理器。I/O设备叫外部设备,外设,由输入输出设备组成。
软件
1.不同的软件系统工作效率不同
2.系统软件:电脑里面自带的一些系统
应用软件:就好像后期我们根据自己的需求下载的软件
3.系统软件的核心是操作系统。操作系统是最靠近硬件的一层系统
计算机中的数制
数制基本概念
- 位(bit):比特,是计算机中最小的信息单位,存储信息的基本单位是二进制位,用小写的b表示,就是用0或1来表示一个二进制数,一位可以存储一个二进制位。
- 字节:微机存储器的容量是以字节为最小的单位来计算,是最基本的数据单位,一个八位二进制数表示一个字节,用大写的B表示,一个字节可以表示一个ASCII码,两个人字节可以表示一个汉字国际码。
- 字:是计算机中信息交换、加工、存储的基本单元,用W表示,由一个或者多个字节构成。这里注意,与我们平时理解的汇编存储单元的字节不同,这里的字可以由多个字节构成。
- 有双字(两个连续的字),四字......
- 一个微型存储器的存储单元可以存储一个Byte(也就是8个2进制位)
十进制、二进制、十六进制转化
十六进制转化为二进制十进制
- 十六进制-----二进制:利用8421码,有4位,看我们的十六进制数由8421码的哪些个位置的数相加,就在相应的位置写1,比如:
5H----4+1---->0101 |
17H----1、4+2+1----0001 0111 |
987H----8+1、8、4+2+1----1001 1000 0111 |
|
342H----2*16^0+4*16^1+3*16^2=2+64+768=834 |
2DEA---A*16^0+D*16^1+E*16^2+a*16^3=11754 |
二进制转化为十六进制和十进制
- 二进制----十六进制:也是用8421码,反推即可,0101---4+1=5
- 二进制转化为十进制:将二进制转化为16进制,再转化为十进制即可
十进制转化为十六进制和二进制
- 十进制----十六进制:
35=16*2+3=23H
7566=472*16+14=16*(16*29+8)+15=16*(16*(16*1+13)+8)+15=1D8FH
- 十进制-----二进制:将其转化为十六进制再转化为二进制。
两个16进制怎么加快:
比如:FE+FE
首先是E+E ,看成:14+14=28 ,然后28-16=12(C有进位)
F+F ,看成:15+15 =30 ,30-16=14 ,加进位:15(F)有进位
所以FE+FE= 1FC H
BCD码
- 二进制数是计算机处理容易实现的,但是二进制数不适合人进行处理、书写、纠正等,而且我们人类更喜欢使用的是十进制数,所以计算机中有时候也可以使用十进制的形式来表示,叫十进制的BCD编码方式。
- BCD码也叫:二-十进制数,也就是用4位二进制数表示一位十进制数,表示方法有很多,用得比较多的是8421BCD码,分为压缩BCD码和非压缩BCD码
- 压缩BCD码:其中每位压缩BCD码占4个二进制位表示(也就是一个十进制数占4个二进制位),一个字节可以表示两位十进制数,可以存放两个BCD码(注意:这里和前面的用8421码将十六进制数转化为2进制数不一样,但是都是利用BCD码),比如:十进制数56=(0101 0110B)—这是压缩BCD码
- 非压缩BCD码:好像是只能表示0~9,个位数,其他位不能表示,用1个字节表示一位十进制数,高四位总是0000,低4位的0000~1001表示0~9.例如0000 0100B表示十进制数4.
原码、反码、补码
1.预备知识
- 计算机只能做加法运算,因为计算机的运算器只有加法运算器,没有减法运算器,所以如果想要在计算机中进行减法运算,只能通过加法运算来实现,减去一个数可以看成加上这个数的相反数(也就是负数),但是在计算机的计算过程中也没有负数的概念,因此计算机就引入了一个叫符号位的东西。
2.为什么会产生原码、反码、补码?
3.慢慢理解吧,我感觉会有点绕(以下内容是根据另外一位博主写的,我自己看着做了一个总结,我会把连接放后面)
原码:
就是最简单的机器数表示法。最高位为符号位,“1”表示负号,“0”表示正号,这里可以这样理解,既然第一位是符号位,那如果表示为1肯定就代表这个数是有符号数,且为负数,就好像汇编里面的ZF(零标志位),运算结果如果为0,则ZF=1,因为叫零标志位嘛,如果为0,就是我们所说的真,当然ZF就为1啦。
以带符号位的四位二进制数为例:最高位是符号位
这里我们做几个运算:
- 1.(1+2=3)—0001 + 0010 = 0011(3)-----正确
- 2.(+0 +(-0)= -0,0加任何数等于任何数)——0000 +1000 =1000 -----正确
- 3.(1+(-1)= 0)----但 0001+1001 =1010(-2)-----矛盾,这。。。。
我们可以看出来,正数之间的加法是符合我们正常的逻辑思维,但是正数+负数和 负数+ 负数 会产生错误的结果。对于原码有符号位,所以说0有+0和-0
这里我们可以知道,原码直观易懂,很容易就可以实现正数负数转换,但是不适于实现减法的运算-----因此就产生了反码。
反码:从原码我们可以看出,一个数加上它的相反数不为0,按道理应该是要为0的。
(1+(-1)= 0)----但 0001+1001 =1010(-2)
- 1.对于一个自然数,负数是正数的相反数,所以就产生了将正数按位取反的方式来表示负数。
- 2.正数的反码等于原码
- 负数的反码就是除符号位外,其他位取反
- 3.比如:3的反码等于原码,为0011,-3的原码是1011,反码就为1100
再 利用反码进行运算:得到的是反码(二进制相加过程符号位不变)
- 1+(-1)=0 ----0001 +1110 = 1111(-0)-----是-0,但是也算是解决了
- (-1)+(-2)= --3------1110+1101 = 1011(-4)----好像又出问题了
但是我们观察可以看出:(-4)的反码为1011,但1011用原码表示就是(-3),这里可以留一个疑问????
- (-1)+(-3)=(-4)---- 1110 +1100 =1010(-5)----但1010的原码-2,所以上面的例子只是一个巧合,我们发现,正数加负数解决了(第一个例子),但是负数和负数相加还没有解决------?????
思考一下:
- 我们解决的是减法问题,在做减法运算时,把减法当做加法来进行运算。
- 这里两个正数相加和两个负数相加,都是加法问题,只是有无符号位的问题,然而正数加负数才是我们考虑的减法问题。所以反码我们解决的是正数加负数的问题
- 用原码表示两个负数相加,在不发生溢出的情况下,只有符号位会出错。
- (-1)+(-2) = (-3)------原码:1001 + 1010 =0011(符号位没了)
- 所以对于反码中负数相加会出现错误,我们可以在实现两个负数相加的时候,将两个负数反码包括符号位按位取反再相加,最后在将符号位强行加1就可以了。
- 所以用反码计算减法问题就解决了:-2(原码:1010,反码:1101)
- 1+(-2)=(-1)----0001 + 1101 = 1110(反码)
- (-1)+(-2)=(-3)----反码:1110 + 1101=0011 (取反:0001+0010=0011后将结果符号位变1,1011(-3))
- 但是:1+(-1)=0-----反码:0001+1110 = 1111(-0),为什么是-0呢,这个问题还没有解决。
- 这里引入了补码。
补码:正数的补码是原码;
负数的补码是反码+1 (对于补码的思想,还值得研究,后面再研究吧)
连接:https://blog.csdn.net/afsvsv/article/details/94553228
机器语言、汇编语言、高级语言
低级语言:机器语言和汇编语言,高级语言就是C、c++、java等
第二章 80X86微处理器及系统结构
8086微处理器结构
8086的内部结构是16位(Byte)的,内外数据总线均为16条,可以处理16位和8位的数据
但是其地址总线是20位的,所以其寻址能力是:2^20B=1MB,范围是00000H ~ 0FFFFFH
- 8bit=1Byte
- 1B=8bit= 2 ^3bit(1B 就是一个存储单元)
- 1KB=1024B = 2^10B
- 1 MB = 1024 KB = 2^10*2^10=2^20B
- 1 GB = 1024 MB
- 1 T = 1024 GB
1.对于指令执行单元:EU
- 组成:ALU(算术逻辑单元)、标志寄存器、数据寄存器、EU控制单元组成,指令的执行过程中,取指部分和执行指令部分是分开的,当一条指令刚开始执行的时候,同时就可以取下一条指令放入指令缓冲器中排队,这样一但前一条指令一结束就可以立马从指令缓冲器里面取出下一条指令,大大提高了CPU的利用率和执行速度
- EU的主要功能:
1.根据指令进行算术和逻辑运算
2.EU计算出指令要 求 的寻址单元地址的偏移量,送到BIU,通过地址加法器形成一个20位的物理地址,到相应的位置去存取接下来的操作。(后面的寻址方式)
2.总线接口单元BIU:负责CPU和存储器之间的信息传送。
- 组成:
由地址加法器、段寄存器、指令指针IP、指令队列、总线控制逻辑组成
- 主要功能:
1.从内存的指定单元取出指令送入到指令队列中去排队。
2.指令执行过程中的所需要的操作数由BIU从指定的区域取,传送给EU去执行
上面我们有提到以下几个东西:
指令队列:其是一个大小为6字节的寄存器,所以指令队列里面最多存放6个字节指令,因为是一个队列,所以遵循先进先出的原则。当指令队列为空时,BIU自动执行总线的操作,取指令存入指令队列再执行。当程序发生转移的时候,BIU需要重新取指令执行,这时取的指令不用放到指令队列,而是直接存入EU去执行,执行的同时BIU依旧会不断的取指令。
地址加法器:是将指令指针IP和段寄存器CS或者将EU送来的偏移量与段寄存器DS形成一个20位的物理地址,从寄存器中取出指令或者数据。
- 其中指令执行单元EU和总线接口单元BIU的操作是独立进行的,所以两者可以一起工作,就是前面我说到的当EU在执行指令的同时,BIU就可以将下一条指令存放到指令队列里面。
过程如下:
寄存器
寄存器位于内存储器的特殊区域的说法是错误的。
寄存器是一种特殊的存储器,这样说才对。
微机一般分为主机(含CPU、内存)和外设(含外存、I/O设备)。
寄存器一般视为CPU的一部分,所以“寄存器是一种特殊的内存储器”根本不对。
如果按照冯·诺伊曼模型,分为I/O设备、运算器、控制器、存储器,这种分法又没有将内存储器单独提出来,所以这句话还是错的。
“寄存器是一种特殊的存储器”,这样说才对。
寄存器到后面会用到,用到再说
控制寄存器:IP、PSW(OF、CF、ZF、SF、PF、AF)
8086有两个控制寄存器:IP---指令指针寄存器,PSW或flags---标志寄存器或叫程序状态字寄存器
- IP
用来存放CPU要执行的下一条指令,存放代码段中的偏移地址,程序运行时,BIU自动自动修改IP,IP始终指向下一条指令的首地址,与段寄存器CS联合使用,指向下一条指令的物理地址CS:IP
- PSW
其中条件码标志有六个:
作用是用来记录程序运行结果的状态信息,运行的结果由CPU自动设置,后续主要用于条件转移控制的条件,所以叫条件码。
- OF(OverFow Flag):
溢出标志,仅仅对于有符号数。在运算过程中,如果操作数超出了机器所能表示的范围,OP自动置1(OF=1),否则置0。(如果是八位:+127 ~ -128,16位:+32767 ~ -32768 )
有符号数相加,如果结果的符号数和操作数的符号数相反,则OF=1
- CF(Carry Flag):
进位标志,仅仅对于无符号数,对于无符号数没有溢出的说法,只是说表示不下,超出范围,所以有进位,记录运算时是否有从最高有效位产生进位或者借位,有进位则CF=1,否则CF=0
- SF(Sign Flag):
符号标志位,表示有符号数运行结果的正负,结果为负时SF=1,否则SF=0;
- AF(Auxiliary Carry Flag):
辅助进位标志,记录运算时第3位产生的进位值,运算时第3位有进位值:AF=1,否则ZF =0
- ZF(Zero Flog):
零标志位,当运算结果为0时,ZF=1,运算结果不为0,则 ZF= 1
- PF(Parity Flag):
奇偶标志,当结果操作数(二进制数)中1 的个数为偶数个时:PF=1,为奇数个时PF=0,常用于检验是否产生数据传输错误。
控制标志有三个:
- DF(符号标志):
用于在进行串处理指令中控制处理信息的方向,当DF=1时,每次操作后SI和DI自动减小,实现了串处理时从高地址向低地址方向进行处理。DF=0时,SI和DI增大,使串处理从低地址向高地址方向处理。
- TF(陷阱标志):
也叫单步跟踪标志,在DOS环境下,调试程序用的T命令就是这个实现单步调试,TF=1时,每条指令后会产生陷阱,由系统控制计算机,TF=1时,CPU正常工作,不产生陷阱。
- IF(中断标志):
当IF=1时,运行CPU相应外部可屏蔽中断请求,否则关闭中断禁止外部中断请求,本标志对外部中断进行管理。
在DEBUG中,不会显示什么ZF=1或者CF=1,而是如以下显示
8086存储器的组织,存储单元的地址和内容
- 在存储器里是以字节为单位存储信息,为了正确存放和获得信息,给每一个字节单元一个唯一的存储地址,称为物理地址。地址都是从0开始标号的。
- 8086存放 存储地址 的寄存器字长为16位,因此每个存储单元若用16位二进制数表示地址,2^16=65536个,所以地址的表示范围是 0 ~ 65535,及64KB(1K=2^10=1024,64KB=2^10*2^6Byte),注意地址的编号是用十六进制,所以范围是0000H~FFFFH
- 同样,8086的地址总线为20位,所以其可以访问的字节单元地址范围为 00000H ~ FFFFF H
- 当机器的字长是16位时,而且大部分数据都是以字长为单位表示的,当一个字长数据存入存储器时要占用两个连续的存储单元,存放时,低地址放低字节,高地址放高字节
存储地址的分段
- 8086微处理器的地址总线,我们在编写程序的时候,要把存储器分段,其中每个段的地址可以是任意取的,取的大小只要在64KB的范围内都可以,然而段的起始地址是不可以随意取的,必须从每一段的首地址开始,而且是从0开始的。在1MB的地址空间里面,可以有64K个小段首地址,可以表示为00000H、00010H、00020H、……FFFF0H,为什么不是(FFFFFH,为什么后面都还有一个0,猜测有一位为偏移地址)。
- 在1MB的存储器里面,每一个存储单元都有一个唯一的20位地址,叫存储单元的物理地址。CPU访问想要访问的存储单元时,必须先要知道存储单元的物理地址。但是CPU里面都是16位的,然而存储器里面的存储单元都是一个20位的地址。所以有物理地址=段地址+偏移地址。
- 物理地址:
20位的物理地址由 16位的段地址 和 16位的偏移地址 组成,段地址就是前面说到的每一段的起始地址(也叫段基地址),因为其必须是小段的起始地址,所以其低四位一定是0000,所以段地址只取段起始地址的高16位值,偏移地址则是指段内相对于起始地址的偏移值,偏移地址的也是16位的。
- 以下图是物理地址的形成过程:而且我们可以知道,物理地址可以是唯一的,但是偏移地址和段地址可以是变化的,只要最后的结果计算出来是一个20位的物理地址即可。
- 在8086微处理器中,有四个专门用来存放段地址的寄存器,叫段寄存器
DS(数据段寄存器)、CS(代码段寄存器)、SS(堆栈段寄存器)、ES(附加数据段寄存器)。每一个段寄存器可以确定相应段的起始地址,每一个段都有自己各种的用途
CS(代码段):用来存放当前正在运行的程序(必须有)
DS(数据段):用来存放当前运行程序所用的数据。
SS(堆栈段):定义堆栈所在的区域,堆栈是一种数据结构,它开辟了一个比较特殊的存储区域,这个特殊的区域是通过先进后出的方式的来访问这一段区域。
ES(附加数据段):是附加的数据段,是一个辅助的数据区域,也是存串处理的指令的目的操作数的存放区域,
除非专门去指定,一般情况下,各段在存储器中的分配是由操作系统负责的,每个段可以独立占用64K的存储区。各段也是可以重叠的,重叠是指段区域的大小可以根据需要来指定大小,不一定要占64K,虽然说段的区域是由系统分配的,但是系统运行时程序员在必要时可以指定所需要的占用的内存空间。
第三章 操作数的寻址方式
处理器寻址方式的默认组合
接下来需要记好多的寄存器
- 以下是微处理器的默认组合,在使用的时候我们不用专门的给其指定组合,但是如果需要使用到非默认组合的关系,则必须使用段超越前缀加以说明。
预备知识:
计算机的指令由操作码字段和操作数字段组成,操作码字段是指明计算机所要执行的操作,比如后面我们的MOV,就是传送的意思,操作数是指令的处理对象。、
其中对于操作数,8086操作数可以是 0个操作数(比如后面会用到的:CLD),一个操作数(比如:JMP A),两个操作数(比如 MOV AX,BX)。其中分别也叫:零地址指令、一地址指令、二地址指令
源操作数src(OPS)是:用来存放运算的数据,目的操作数dst(OPD):存放运算的数据或者运算的结果。
- 零地址指令:主要是程序的控制类指令,没有具体放入操作数。
- 一地址指令:指有一个操作数,或者隐含操作数,也就是后面我们会学到有些指令的另一个操作数有隐含在默认的位置。
- 二地址指令:有两个操作数,源操作数OPS和目的操作数OPD。其中操作数的大小必须一致
操作数的类型
指令操作数可以存放在 指令 、 寄存器 、内存 、 端口中,其中端口是接口中的寄存器。
其中操作数可以分为三类
- 立即数:(1个)
操作数由指令直接给出,立即数就是一个数,或者可以是由确定值的表达式。
- 寄存器操作数:(2个)
就是前面我们所说的那14个寄存器,位置在内存的数据段,在指令中我们需要指明寄存器的名称,寄存器操作数可以是源操作数也可以是目的操作数。
- 存储器操作数:(5个)
也就是说操作数在内存中,其中操作数的地址就是它在内存里面的物理地址。
七种寻址方式
重点掌握:立即寻址、寄存器寻址、直接寻址
段地址:ES 偏移地址:EA
8086CPU有4个段寄存器,每个段寄存器用来确定一个逻辑段的起始位置,每种逻辑段均有各自的用途
CS(代码段):指明代码的起始位置 (必须要有)利用CS:IP来取得下一条要执行的指令
SS(栈堆段):指明栈堆段的起始位置 利用SS:SP操作堆栈顶的数据
DS(数据段):指明数据的起始位置,利用DS:EA存取数据段中的数据
ES(附加段):指明附加段的起始位置, 利用ES:EA存取附加段中的数据
注意:
EA是偏地址,称之为有效地址EA
若操作数在主存中,存取的方法有直接寻址方式,寄存器间接寻址方式,寄存器相对寻址方式 ,基址变址寻址方式和相对基址变址寻址方式。
立即寻址方式:
操作数类型是立即数,存放在指令中
常用于给寄存器或者内存单元赋值,在二地址操作数指令中,目的操作是不能是立即数。
- 操作数的类型为立即数,直接存放到指令中,可以是8位或者16位,类型可以是数据也可以是带单引号的字符,比如
MOV AX , 9732 H 指令执行后:(AX)= 9670 H
(这里要注意,如果没有写H,代表的是十进制,汇编的时候指令会将自动其转变为16进制)
MOV BH,‘A’ 指令执行后:(BH)= 41 H (41是A的ACSII码)
寄存器寻址方式:
操作数在寄存器中,在指令中指明寄存器的名称。
常用于寄存器之间传送数据。
- 操作数在寄存器中,指令中我们需要指明寄存器的名称,寄存器寻址方式不需要访问内存,其速度很快。比如:
MOV AX,BX 指令执行后:将BX的值给AX,但是BX的值不变。
前面我们知道,操作数的类型有三类:立即数 、寄存器操作数 、(内存)存储器操作数。除了以上的两种寻址方式,下面的五种寻址方式均为存储器操作数,讲述的是不同地址形式的指定操作数所在段的有效地址(也就是偏移地址EA)
以下均为存储器寻址方式。 存储器寻址用到 物理地址=段地址+偏移地址
直接寻址方式:
操作数默认在数据段(DS),其表示的是对应物理地址所对应的内容。
- 直接寻址方式 的操作数地址是16位的偏移量(也就是偏移地址)包含在指令中,操作数则默认在数据段。操作数的物理地址是数据段寄存器DS中的内容后移4位再加上指令给定的16位地址偏移量,也就是 物理地址(PA)= (DS)*16 + EA 用 [ 数据 ] 来表示地址,比如:
MOV AX,[1000H] 这里的1000加H表示16进制 ,不加的话,在汇编的时候会自动转化为十六进制。
前面我们说到默认段地址到DS里面,所以物理地址=DS*16+1000H,然后(AX)的值为对应物理地址所在内存单元里面的内容。
- 允许段超越
也就是说操作数是在附加段ES里面,操作数的物理地址为=(ES)*16 + [ ] ,
格式:MOV AX,ES:[1000H] (AX)=(ES)*16+[1000H]所对应的内存单元厘米的内容
- 如果程序里面写了程序,若ARRAY 表示的是符号的地址:
则:MOV AX,ARRAY------也是直接寻址方式。也可以写成:MOV AX,[ARRAY],和后面我们写的MOV AX,DATA-----就是这个意思。
寄存器间接寻址方式:
操作数在内存中 [ ] 方括号里面只能是BX,BP,DI,SI
- 其中,操作数的有效地址在 SI 或 DI 或 BX 或 BP 这四个寄存器里面,也只能是这四个寄存器。
- 其中如果没有指定段寄存器,则SI 、DI 、BX,的段寄存器是DS 数据段寄存器,BP则是SS 为默认段,其操作数在堆栈段里面。
- 比如
MOV AX ,[DI] ——物理地址= (DS)*16 +(DI),读取连续的两个存储单元内存
MOV AL,[BX] -----物理地址= (DS)*16 +(BX),读取一个存储单元的内容
MOV AX ,[BP]------物理地址 = (SS)*16 + (BP),偏移量默认在堆栈段
- 其中这些都允许段超越
MOV AX ,DS:[BP]-----物理地址 = (DS)*16 + (BP),段超越啦,所以BP的偏移量在DS里面。
寄存器的相对寻址方式:
其实就是上面的寄存器寻址方式加一个偏移量而已。
- 也就是说在寄存器间接寻址方式后面再加上一个一个位移量D(位移量为八位或者16位)
- 其中寄存器还是只能是前面说到的 SI 、 DI 、 BX 、BP ,其余内容与上面一样,只是再加上偏移量而已。
- 比如:
MOV AX,[ DI + 16 H ] ----- 物理地址 = (DS)*16+(DI)+16H
也可以写成 MOV AX ,16H[ DI ]
MOV CL , [ BP + 0205H ] -----物理地址 = (SS)*16 + (BP)+0205H,
BP寄存器的偏移量依旧是默认在堆栈段里面。我们发现这里的目的操作数是CL,是一个八位寄存器,所以读取的是物理地址里面的那个存储单元的内容,前面的16位寄存器是相应的读取两个连续的存储单元内容。
MOV AX,[ BUF + SI ] ======MOV AX,BUF[SI]------物理地址 =(DS)*16 + (SI)+BUF
其中BUF表示:具有确定值的8位或者18位的偏移量,读取2个字节的内容给AX寄存器。BUF是我们可以随便取的值
- 使用场景:常用于结构体、数组、二维数组。
基址变址寻址方式:
意思是用一个基址寄存器和一个变址寄存器的值相加为其偏移地址。(各一个,有4种情况)
- 上面我们可以知道:基址寄存器(BX,BP),变址寄存器(SI,DI),所以搭配方式有4种。
- 注意:当基址寄存器为BX时,段寄存器用DS,当为BP时,段寄存器用SS。
- 比如:
MOV AX,[ BX + SI] ---- 物理地址 = (DS)*16 + (BX)+(SI)
也可以写成 : MOV AX,[ BX ][ SI ]
MOV AX ,[ BP + DI ]-----物理地址 = (SS)*16 + (BP)+ (DI),BP的默认段为堆栈段
- 用于二维数组
相对基址变址寻址方式:
就是在基址变址的基础上加一个偏移量,寄存器的使用和基址变址的使用是一样的。
- 物理地址 = ( DS / SS )*16 + (BX / BP) + (SI / DI )+D (16位或者八位的偏移量)
- 比如:
MOV AX ,[ BP +SI + 06H ]-----物理地址= (SS)*16 +(BP)+(SI)+ 06H
也可以写成: MOV AX,06H[ BX+ BP ]
- 用于表格(结构)中的数组,二维数组。
第四章 汇编指令详解
在汇编语言中,汇编指令的基本格式:
标号 : 指令助记符(必须有) 目的操作数 , 源操作数 ;注释(汇编语言的注释是使用分号)
就像下面这样就是汇编指令。
数据传送指令:MOV、XCHG、XLAT、PUSH、POP、标志传送指令、地址传送指令
数据传送指令: MOV
格式:MOV OPD,OPS -----意思是将源操作数中的数据送入 目的操作数,源操作数不变
MOV指令的传送方向:没画箭头则表示不可以传送。
这个表格很重要。
所有的都不能传送到立即数:我们都知道立即数就是一个固定的数,所以当然不能给它传送东西呀。
MOV指令的常见格式:
- MOV reg / men ,imm ------ reg(寄存器)、men(内存单元)、imm (立即数)
MOV AX , 1010H ----- AX = 1010 H
MOV BYTE PTR [ BX ] ,10H ----- 将字节数据传送到物理地址= (DS)*16 + BX 的位置,
因为内存单元是不会像寄存器一样有默认的大小,所以,我们需要指明是字节还是字数据类型
一个 字节 单元:BYTE PTR 一个 字 单元:WORD PTR
- MOV seg / reg / mem ,reg ----seg(段寄存器)
MOV DS,AX
MOV SP,AX
MOV DH,CL
- MOV seg / reg ,mem
- MOV reg / men ,seg
- 观察下列指令,找出错误,答案紧跟后面
1.MOV DH,300H
2.MOV [ BX ],0
3.MOV DS , 1000H
- 答案
1.DH是6位寄存器,最大值是255 H,300超出了255的范围
2.[ BX ]代表的是一个物理地址,我们不知道其大小,所以要指明是字节类型还是字类型
3.立即数不能直接传给段寄存器,需要通过通用寄存器中转。
MOV 指令总结:
- 两个存储单元之间不可以直接传送数据,也就是内存单元之间不可以,适用于所有的指令。
- 目的操作数不能是 立即数 和 CS寄存器,CS寄存器的内容是由操作系统给出的。
- OPD和OPS的位数一定要一致(字类型或者字节类型)。也适用于所以的指令。
- 计算机中可以根据偏移地址寄存器,省略段寄存器。就是前面说到的寻址方式。
- 在内存和寄存器之间传送数据时,要指明是字类型还是字节类型。地址要和寄存器相匹配。
交换指令:XCHG
- 指令格式:XCHG OPD,OPS
- 指令功能:将源操作数和目的操作数交换。必须有一个是寄存器,所以不允许两个内存单元之间对换。
- 指令格式如下:
1. XCHG reg ,men
2.XCHG men,reg
3.XCHG reg,reg
查表指令:XLAT(用到BX和AL)
- 指令格式:XLAT TABLE 或者 XLAT
- 指令功能:把待查表格的一个字节内容送到AL寄存器。待查表格存于内存单元中,TABLE 是待查表格的首地址。
- 在执行这个指令之前,我们要先把待查表格的首地址TABLE 先送到 BX 寄存器中(是地址,不是内容),然后在将待查字节的大小也就是其待查字节与其距离首地址的位移量送到AL寄存器。
- 执行后,将有效地址(就是偏移地址)为(BX)+(AL)的内存单元里面的内容送到AL寄存器------也就是 (AL)=((BX)+(AL))
- 这里我们也可以发现,其使用了隐含寄存器,所以需要我们自己将隐含寄存器记下来,才能对源程序进行分析(源程序就是后面前面要写的代码)。
- 该指令不影响标志位。
堆栈指令:PUSH 和 POP
- 堆栈只有一个出口-----叫栈顶,所以其工作方式是 先进后出 。 默认16位,所以存或者取都是两个字节(也就是一个字)同时进行的。
- 堆栈位于堆栈段中,如果需要使用到这两个指令,就需要定义一个堆栈段,其段地址是SS段寄存器。
- 栈顶指针寄存器为SP,也就是说SP始终指向栈顶元素,就好像CS:IP始终指向下一条将要执行的指令一样。
- 进栈和出栈都是针对栈顶元素进行的两种操作。
- 数据进栈:叫PUSH ,SP会自动减2,也就是(SP)=(SP)-2
指令:PUSH OPD ---- 先是SP减2,再将OPD的数据放入SS:SP所指内存单元
- 数据出栈:叫POP,SP会自动加2,也就是(SP)=(SP)+2
指令:POP OPD ---- 先将SS:SP所指内存单元数据送入OPD,再将SP加2
- 正确的指令:
PUSH BP
PUSH CS
PUSH DATA;DATA 为16位的变量
POP DS
POP [ BX ] ; 将栈顶的字数据送到BX 寄存器所指向的内存单元(就是物理地址)。
- 错误的指令:
POP CS
PUSH BL
- 答案:
始终要记住,不能对CS 寄存器直接传送数据,POP 就是取数据,所以对CS是不可以的,但是PUSH为什么可以,因为PUSH CS 只是把CS 的内容送进栈。
标志传送指令:LAHF、SAHF、PUSHF、POPF
- 标志位送AH 指令的LAHF
指令格式:LAHF
指令功能:取标志寄存器PSW的低八位传送到AH。该指令不影响标志寄存器的内容。
把 DS:[ BX + AL ]为地址的待查表格的一个字节送到AL累加器
以下几个指令学了一个学期也没怎么用,具体怎么实验我不太懂,后面用到了我再来解释吧。
地址传送指令:LEA ,LDS ,LES
有效地址指令:LEA
指令格式:LEA OPD,OPS
指令功能:将源操作数的有效地址传送到目的地址。不影响标志位,注意传送的是有效地址。与MOV不一样,因为传送的是地址,所以源操作数必须是内存操作数。
比如:设BX=0100H,DI=0030H,DS:[ 0030 h]=2436H ,变量DATA 的有效地址为:0050H.
- LEA BP ,[ 3000H ]; BP= 3000H,如果是MOV 指令,则(BP)= DS*16 +3000H
- LEA BX , [ BX +DI ]; BX = 0100 + 0030 = 0130H
- LEA SI,DATA ; SI = 0050H
- LEA SI ,DI ; SI= 0030H
- MOV SI ,DI ; (SI)= DS*16 + DI = 2436H
(MOV是数据传送,所以传过去的是物理地址所对应的内容)
从这几个例子里面就能感受到LEA 指令与MOV指令的相同处于不同处了
- 取地址指令LDS 和 LES
指令格式: LDS OPD ,OPS | LES OPD,OPS
注意:OPD 为任意的一个16位寄存器,OPS 为存储地址
指令功能:将存储单元的连续4个单元 的内容分别传送到OPD(低) 和 (高)DS寄存器(LDS) 或者 ES 寄存器(LES)。
比如: LDS SI,[ 20 h]
设 (DS)= 4000H,(40020H)= 7765H,(40022H)= 2347 H
指令执行后:SI = 7765H ,DS = 2347 H;LES 的功能一样,只是传送的寄存器是ES;
这里也是涉及到隐含的寄存器,多做练习,后面就会懂了.
运算指令:ADD、ADC、INC 、SUB 、SBB、DEC、CMP
基本概念:用于实现算术运算的功能,有单操作指令,双操作指令,还有隐含操作指令。操作数可以是8位也可以是16位。不允许两个操作数都是存储单元,目的操作数不能是立即数,操作数位数要一致(这些前面都有提到,基本上适合所有的指令)
INC和DEC除了不影响CF位,其他的都影响,ADD、ADC、SUB.....等均影响标志寄存器。
- 加法指令:
ADD :加法指令
指令格式:ADD OPD, OPS
指令功能:就是OPD 和OPS 相加,然后再传送给OPD,OPD=OPD+OPS
ADC :带进位的加法指令
指令格式:ADC OPD,OPS
指令功能:就是在ADD的基础上再加上标志寄存器中CF 的值:OPD = OPD+ OPS + CF
INC:加一,类似于C语言的 i++,就是加一
指令格式:INC OPD
指令功能: OPD = OPD + 1;可以是寄存器和内存单元,如果是内存单元要指明是字节还是字单元。
找出以下指令的错误:
ADD BH ,CX
INC 106H
ADD AL ,100H
ADD [ BX ] ,20H
INC [ BX + SI ]
答案:BH和CX的操作数位数不一致 、 源操作数不能是立即数 、100H = 256 立即数超出寄存器位数 大小我们看的是十进制 所以要转化为十进制 转化方法如果忘记了可以重新回顾一下、后面两条指令都是没有指令是字节类型还是字类型.
加法指令对标志位均有影响,但是INC 指令对CF位无影响。
- 减法指令:与加法类似,只是加换成减
SUB:减法指令 OPD = OPD - OPS
SBB:带进位的减法指令 OPD = OPD - OPS - CF
DEC:自减一,就好像C语言的 i--
NEG :求补指令 NOT(非,也就是取反)
指令格式:NEG OPD(OPD可以是寄存器也可以是内存单元)
指令功能:就是对OPD 求补,求补就是对OPD 求反后加一,然后结果送回OPD
CMP :比较指令
指令格式:CMP OPD,OPS
指令功能:其实和SUB是类似的,只是说CMP指令做减法后,结果不送到OPD ,只是在一些特定的场合做一些比较,用来比较大小。
无符号比较:CF = 1 (表示有借位)OPD < OPS ;CF = 0 (表示无借位)OPD > OPS
有符号比较时,后面基本上会跟上一条转移指令,后面再说。
乘法指令:MUL、IMUL
- 无符号数乘法指令:MUL
指令格式:MUL OPD (是不是会疑惑,为什么就一个操作数)
指令功能:当OPD 为8位字节数据时为字节相乘,将AL 与 OPD 相乘,结果存到AX: AX = (AL)*OPD,存在隐含操作数AL。
当OPD 是16位字节数据时为字相乘,将AX 寄存器与OPD相乘,结果存到DX和AX寄存器:
(DX)(AX)= (AX)* OPD,AX 是隐含操作数。
比如:要实现78H(十进制:120)和0F1(241)相乘
分析:是八位字节相乘
MOV CL,78H
MOV AL,0F1H
MUL CL ;这条指令会自动去前面找AL的值是多少,然后来和CL相乘结果自动放到AX里面
- 有符号数乘法指令:IMUL
与MUL一样,只是专门用于有符号数相乘
- 乘法指令对标志位的影响是什么意思,我不太懂,如果有谁懂,欢迎到评论区留言
什么叫高一半为低一半的符号扩展啊,然后就有CF=0,OF= 0;否则的话:CF=1,OP=1
除法指令:DIV、IDIV
- 无符号除法:DIV
指令格式:DIV OPD (和乘法指令一样,只有一个操作数)
OPD 为8位字节数据时,被除数在AX里面,除数在OPD 里面,(AX)/OPD,而且余数到AX里面,商在AL里面,记忆方法:商低余高,AX是隐含操作数
OPD为16位字数据时,被除数在DX和AX中,除数在OPD 里面,(DX)(AX)/OPD,而且结果是余数在DX里面,商在AX里面,也是商低余高,DX和AX都是隐含寄存器
OPD 放的都是除数,而且会发现,除数和被除数只要有一个是16位,就是使用到DX和AX
- 有符号除法:IDIV
指令格式:IDIV OPD
与无符号除法类似,只是说用于有符号数的除法
- 除法指令对标志位的影响:除法指令对标志位没有定义。除法指令会产生结果溢出,当被除数远大于除数时,便产生结果的溢出,8086CPU在这时候就会产生0号中号中断,会运行相应的中断服务程序。在设计程序时,应当避免除法溢出。
符号扩展指令:CBW、CWD
符号扩展是指用一个操作数的符号位(就是指最高位,二进制)形成另外一个操作数,形成的操作数是各位全为0(最高位为0)或者各位全为1(最高位为1)。符号扩展不改变大小。
- 字节扩展为字:CBW (Byte---Word)
指令格式:CBW
指令功能:将AL的符号位扩展到AH,如果AL的最高位是0,则AH=00H,AL的最高位为1,则AH=0FFH。AL保持不变。
- 字扩展为双字:CWD (Word----Double Word)
指令格式:CWD
指令功能:将AX 的符号位扩展到DX,如果AX的最高位为0 ,则DX=0000H,如果AX的最高位为1,则DX=0FFFFH。AX保持不变
- 为什么要这个,因为除法指令要求被除数的位数是除数的倍长。符号扩展指令主要用于在有符号数除法中扩展被除数的位数。对无符号数除法可直接使高8位或者高16位清0,以获得倍长的被除数。或者有些时候,加减乘除两个操作数不一样的时候,可以用到符号扩展指令。
- 符号扩展指令也用于数据相加减时调整数据的位数
比如:设B1,B2,B3为有符号字节类型变量,写出完成(B1*B2+B3)/B2 的指令
MOV AL,B1
IMUL B2 ;结果在AX里面
MOV CX,AX ;为什么要写这一句,因为要保存结果的值
MOV AL,B3 ;B1 * B2 的结果为16位的数据,B3为8位的数据,不能相加,所以需要将B3扩展
CBW
ADD AX,CX
IDIV B2 ;最后,余数在AH,商在AL
十进制数调整指令:DAA、DAS、AAA、 AAS、AAM、AAD
十进制调整指令是对二进制运算的结果进行十进制调整,以得到十进制的运算结果。
为什么需要这个十进制的调整指令? 和前面说的BCD码牵扯到联系。
计算机用二进制运算规律进行十进制的运算,用4位二进制数表示一位十进制数,一位十进制数逢10进一,4位二进制数是逢16进1 ,结果大于9或者AF、CF等于1时需要调整。
压缩BCD码:是用4个二进制位表示一个十进制位
非压缩BCD码:用8个二进制位表示一个十进制位,低4位表示一个十进制位,高4位通常默认为0
BCD码的加、减、乘、除调整指令的调整对象均为隐含寄存器AL,BCD码运算只能使用以AL寄存器为目的操作数的8位数运算指令。
- 压缩BCD码加法调整指令:DAA
指令格式:DAA
指令功能:对两个压缩十进制相加运算存于AL中的结果进行调整,产生一个压缩组合十进制数在AL中,其进位在CF里。
调整的操作:若AL与0F > 9 或者AF= 1;则:AL = AL + 6 ,AF =1
若AL 与 F0H > 90 H ,或者CF =1,则:AL = AL + 60H ,CF = 1
指令紧跟在加法指令后,使压缩的十进制数相加后,存到AL里面的是一个压缩的十进制数。
- 压缩BCD码减法调整指令:DAS
指令格式:DAS
指令功能:对两个压缩的十进制数相减存于AL中进行调整,产生一个压缩组合的十进制到AL中。
与压缩BCD码是差不多的,只是相加变成相减。
- 非压缩BCD码加法调整指令:AAA
指令格式:AAA
指令功能:对两个未压缩十进制数相加存于AL中进行结果的调整,产生一个未压缩的十进制数在AX中。
- 非压缩BCD码减法指令:AAS
指令格式:AAS
指令功能:对两个未压缩的十进制数相减存到AL中进行调整,产生一个非压缩的十进制数在AX中。
- 非压缩BCD码乘法指令:AAM
指令格式:AAM
指令功能:对两个未压缩的十进制数相乘存于AX中,产生一个非压缩数存到AX中,其中,AL是商,AH是余数
- 非压缩BCD码除法调整指令:AAD
指令格式:AAD
指令功能:把AX中的两个未压缩的十进制数进行调整,然后按DIV指令实现两个未压缩的十进制除法运算,其结果为未压缩的十进制数的商(在 AL中)和余数(在AH中)。
指令是在除法指令之前使用,对AX中的压缩十进制数进行调整,然后调整后在进行二进制的除法运算,这个与前面的都不一样,前面的指令都是放在相应指令的后面,这个是放前面。
逻辑运算指令: AND、OR、XOR、TEXT
逻辑运算指令用于实现逻辑运算功能,对象是二进制
- 逻辑与 (且)运算指令:AND(全真才真)
指令格式:AND OPD,OPS
指令功能:实现与运算,将结果送回目的操作数
应用:可以对想要清 0 的位清0,屏蔽某些位(XOR也可以)
比如:AND AL,1110110 B;实现对AL第0位和第3位清0,其他位不变
AND AL,0FH ;0FH=0000 1111,实现将AL的高四位清0 ,低4位不变
- 逻辑 或 运算指令:OR (全假才假)
指令格式:OR OPD,OPS
应用:将某些位置1
比如:OR BL,0000 1001 B;将BL的第0位和第3位置1
OR AX,AX ; 目的操作数没有改变,但是改变了标志寄存器的值,
可以反应出AX 的标志状态
- 逻辑 非 指令:NOT (取非)
指令格式:OR OPD
- 逻辑 异或 指令:XOR (两个数位数不相同为1,相同为0 )
指令格式:XOR OPD,OPS
应用:对指定位求反
XOR BL,0FH ;0F H = 0000 1111,对BL 的 高4位不变,低4位求反
XOR AL , 55H ; 55H = 0101 0101 ,对AL 的偶数位不变,奇数位求反(这里的位是从1开始数)。
XOR AX,AX ;清除寄存器,及CF=0,常用
- 测试指令:TEXT
指令功能:TEXT OPD,OPS
指令功能:对两个操作数实现逻辑 与(且) 运算,但是结果不送会目的操作数,仅仅建立结果状态标志。通常用于检测一些条件是否满足。
应用:用于测试某些位是否为0 。
移位指令:SAL、SAR、SHL、SHR、ROR、ROL、RCR、RCL
移位指令都是两个操作数,一个是目的操作数,一个是需要移动多少位,其中,移动位数如果为1,可以直接写,如果移动位数大于一,需要先将移动位数放到CL寄存器,然后再作为移位指令的源操作数。两个操作数的位数不一定需要位数相同。
左是乘,右是除
逻辑移位指令:(无符号数),SHL:无符号数倍增,SHR:无符号数倍减
算术移位指令:(有符号数),SAL:有符号数倍增,SAR:有符号数倍减
- 一般的移位指令:
A(Arithmetic 算术)、H:逻辑 、L(Left 左)、R (Right 右)
SAL / SHL OPD , OPS ;算术、逻辑左移,操作数左移,低位补 0 ,最高位进CF
SAR OPD ,OPS ;算术右移,操作数右移,最高位不变,低位进CF
SHR OPD ,OPS ; 逻辑右移,操作数右移,最高位补 0 ,低位进CF
移位举例:
MOV CL ,4 ;CL =4
MOV AL ,0C5H ; AL = 0C5H = 1100 0101 B
SHL AL,1 ; 逻辑左移1位, 低位补0 ,高位进CF = 1,AL = 1000 1010B = 8AH
SHR AL ,1 ;逻辑右移一位,高位补0 ,低位进CF=0,AL = 0100 0101 B = 45H
SAR AL ,1 ; 算术右移一位,高位不变,低位进CF= 1 ,AL = 0010 0010 = 22 H
SAL AL,CL;算术左移4位,高位补0 ,低位进CF = 0 ;AL = 0010 0000 = 20 H
算术右移是 除 2,算术左移是 乘 2
比如:求 Z = ((X + Y)*8 - X )/ 2
MOV AX,X
ADD AX,Y
MOV CL,3
SAL AX,CL
SUB AX , X
SAR AX,1
MOV Z ,AX
- 循环移位指令:
是指操作数从一端移除的位返回到另一端形成循环,分成不带进位或者带进位的,以及左移和右移。
指令格式:
ROL OPD,OPS ;不带进位循环左移
ROR OPD,OPS ;不带进位循环右移
RCL OPD,OPS ;带进位循环左移
RCR OPD,OPS ;带进位循环右移
举例:
MOV AX,458FH ; AX= 458F H = 0100 0101 1000 1111
MOV CL,4 ;CL=4
ROR AX ,CL;AX循环右移4位, AX = 1111 0100 0101 1000 = 0F458H
ROR AX,CL ;AX 循环右移4位,AX = 1000 1111 0100 0101 = 8F45 H
控制转移指令: JMP、JCC、LOOP、CALL、RET
对于汇编的源程序,程序是都是按照顺序进行的,但是如此程序的每一步都按照顺序来执行,如果遇到需要执行相同过程的程序,就没有必要都写出了,或者说是没必要花费时间在这上面。所以我们可以改变程序的执行顺序。
以下介绍:五种控制转移指令
无条件转移指令、条件转移语句、循环控制指令、子程序调用及返回指令、程序返回指令
无条件转移指令:JMP
指令格式:JMP LABLE(目标的位置)
指令功能:程序无条件跳转到指定的地址,从地址指令处开始执行程序,必须指明跳转的地址。
LABLE:是程序要跳转的地址,其中LABLE是否与当前指令在一个代码段,所以无条件转移指令又分为 段内转移 和 段间转移
段内转移:
在当前代码段的范围64KB内转移(正负32KB范围)称为近转移(NEAR PTR ),
转移范围在段内 -128~ - 127 称为短转移(SHORT)。
段内转移CS段地址不变,只改变IP 偏移地址。
段间转移:
从当前代码段转移到另一个代码段,转移范围是1MB,需要改变CS和IP的偏移地址,因此目的地址必须用一个32位的表达式。
比如:JMP FAR PTR LABLE ;转移到LABLE 的位置,IP = LABLE,CS = LABLE 的的代码段的段地址。
比如:JMP FAR PTR mem ,其中mem 是内存单元的地址,从men 开始的4个连续的单元里面存放着2个16位的地址,一个是目标的偏移地址(低地址单元),一个是目标的段地址(高地址单元):即 IP = [ mem ] , CS = [ men + 2 ] 。
而对于 LABLE 的不同的寻址方式又分为:
直接寻址:转移地址在指令代码中
间接寻址:转移地址在寄存器或者内存单元中
在汇编语言中,汇编程序会自动根据目标的地址距离,自动处理成短转移、近转移、远转移。我们只需要根据需要设置相应的操作符即可:SHORT 、 NEAR PTR 或者 FAR PTR 强制。
条件转移语句:JCC
注意:条件转移语句都是端内短转移
语句格式:JCC LABLE
指令功能:如果上一条指令的条件满足,则发生转移,不满足则不发生转移,继续执行下一条语句。转移的范围与SHORT 相同。转移范围在段内 -128~ - 127 。
指令中的条件即为状态标志的标志。在8086中有16种可用的条件
这些调整可分为:判断单个标志位的状态、比较无符号数的高低、比较有符号数的大小。
1.判断单个标志位的状态:
Z (Zero 0)、E (Equal 相等)、S(Sign 符号)、O(Over 溢出)
P(Parity 奇偶)、C(Carry 进位)
|
JZ 、JE |
ZF = 1 |
结果为0、两数相等 |
|
JNZ、JNE |
ZF = 0 |
结果不为0 、两数不相等 |
|
JS |
SF = 1 |
结果为负 |
|
JNS |
SF = 0 |
结果为正 |
|
JO |
OF = 1 |
结果溢出 |
|
JNO |
OF = 0 |
结果不溢出 |
|
JP、JPE |
PF = 1 |
结果的低8位含有偶数个“1” |
|
JNP、JPO |
PF = 0 |
结果的低8位含有奇数个“1” |
|
JC、JB、JNAE |
CF = 1 |
加法有进位、减法有借位、其他 |
|
JNC、JNB、JAE |
CF = 0 |
加法无进位、减法无借位、其他 |
2.无符号数比较高低(高:Above 低:Below):条件为一个标志或者标志组合
CF 来确定高低、ZF确定相等
( < )JB、JNAE、JC |
CF = 1 |
低于、不高于不等于 |
( > =)JNB、JAE、JNC |
CF = 0 |
不低于、高于等于 |
( <= )JBE、JNA |
CF=1或ZF=1 |
低于等于、不高于 |
( > )JNBE、JA |
CF=0或ZF=0 |
不低于不等于、高于 |
3.有符号数比较大小(大:Greater 小:Less):条件为标志组合。
( < )JL、JNGE |
SF 不等于 OF |
小于、不大于不等于 |
( >= )JNL、JGE |
SF = OF |
不小于、大于等于 |
( <= )JLE、JNG |
SF 不等于 OF 或者 ZF =1 |
小于等于、不大于 |
( > )JNLE、JG |
SF = OF 或者 ZF = 0 |
不小于不等于、大于 |
4.测试CX 值为0 的指令,CX = 0,则条件转移
指令格式:JCXZ LABLE
循环控制指令
循环结构是程序设计中使用最多的一种数据结构。
8086 提供了三条专用指令。循环指令默认利用CX寄存器,属于段内短转移 。
指令格式:
LOOP LABLE
先是CX 的值自动减一,判断是否为0,如果CX为0则执行下一条语句,退出循环,如果CX不等于0 ,则转移到地址LABLE 处执行指令
LOOPZ / LOOPE LABLE
CX 先减一,如果CX 不等于0 且ZF =1 ,转到LABLE处执行指令,否则退出循环,执行下一条指令
LOOPNZ / LOOPNE LABLE
CX 先减一,如果CX 不等于0 且ZF =0 ,转到LABLE 处执行指令,否则退出循环
其中:CX一般设置在标号LABLE 的前面,ZF=0和ZF=1 的意思:LOOP 执行前ZF的状态。
子程序调用及返回指令:CALL
子程序是完成特定功能的一段程序,写程序的过程中,经常使用到子程序的调用。子程序的调用可以提高编程的效率,使程序的结构更加清楚,便于维护。
子程序的调用指令:CALL----->程序转移到子程序的起始处开始执行。
程序执行CALL指令时,会自动把下一条指令的段地址和偏移地址压入堆栈,保护起来。
CALL指令 位于主程序,CALL调用的子程序与CALL指令可以处于同一代码段也可以在不同的代码段,所以可以分为段间调用和段内调用,调用时可以是直接寻址也可以是间接寻址
所以指令有4种格式:
段内直接调用:CALL NEAR PTR LABLE
段内间接调用:CALL 寄存器16位
段间直接调用:CALL FAR PTR LABLE
段间间接调用:CALL 内存单元
程序返回指令:RET
RET指令是子程序最后执行的指令,作用为断点出栈,就是将CALL自动保存的下一条指令的CS :IP 出栈
根据子程序与主程序是否处于同一个代码段内,返回指令也分为段内返回和段间返回(指令的助记符都是LEA,执行时,由程序自动识别)
指令格式:
RET ;无参数段内或者段间返回,
RET n ;有参数段内或者段间返回,n 为一个16位的立即数,
将堆栈指令SP加上n ,SP = SP+n
段内返回:只需要将IP出栈,IP = SS :[ SP],SP =SP+2
段间返回:IP 和CS出栈,IP = SS:[ SP ],SP =SP +2 ,CS = SS :[ SP ] ,SP = SP +2
字符串操作指令:MOVS(B/W)、STOS(B/W)、LODS(B/W)、CMPS(B/W)、SCAS(B/W)、REP、REPZ、RZPNZ
在存储器中存放一组连续数据,称为数据串,对数据串进行操作的指令称为串操作指令。操作数可以是字节(B)也可以是字(W)
串操作数是存放在内存中的,串的首地址存放在指定的寄存器中,指每执行一次串操作令,串操作数的地址会自动进行调整,这样就可以对字符串进行操作。
以下将依次介绍:
串传送指令、串存储指令、串读取指令、串比较指令、串扫描指令、重复前缀指令
串操作数的寻址:
- 源操作数是用寄存器 SI 寻址,默认在数据段 DS 中,允许段超越:ES:[ SI ]。
- 目的操作数用寄存器 DI 寻址,默认在附加段 ES 中,不允许段超越:DS:[ DI ]。、
- 每执行一次串操作指令,SI和DI都会自动增加或减少1个或者两个字节。
- 我们根据需要,利用CLD和STD 来确定是需要将地址增加还是减少,根据DF=1 、0 来确定
- CLD:指令执行后,DF = 0,地址指针自动增加 1 或者 2。
- STD:指令执行后,DF = 1,地址自动自动减少 1 或者 2。
- 注意,在串操作指令执行前,都要明确的知道源操作数地址、目的操作数地址、数据串长度(存放到CX寄存器中)、地址的变化方向(CLD 、STD)。
- 串传送的方向可以是正向也可以是反向,有些特定的情况只能是正向或者反向,具体题目具体分析。
串传送指令:
- 串传送指令就是将一串连续存放的的数据移动到内存的另外一个地方,分为字传送和字节传送。指令不影响标志位。
- 指令格式:MOVSB
字节传送指令,将源字节串传送到目的地址,地址自动增加1,
即 DI:[ SI ]--->ES:[ DI ] , SI=SI+1, DI = DI +1
- 指令格式:MOVSW
字传送指令,将源字串传送到目的地址,地址自动增加2,
即 DI:[ SI ]--->ES:[ DI ] , SI=SI+2, DI = DI +2
- 比如:将DATA1 说指的50个字节传到DATA2中
分析:大小是50个字节,DATA1传到DATA2,
所以DATA1(是源串:SI),DATA2 (是目的串:DI)
以下介绍三种方法实现,后面的重复前缀指令还有一种方法。
法1:
法2:
法3:
如果不用字符串传送指令,将是像下面这样传送,对比一下,就知道为什么要有串传送指令了
串存储指令:
- 将 AL 或者AX 里面的数据传送到目的地址。串为目的操作数,地址为:ES:[DI]
指令不影响标志位
- 指令格式:STOSB
字节串存储指令,将AL寄存器里面的内容送到目的地址,ES:[ DI ],地址自动增减1
AL—>ES:[ DI ] , DI = DI +1 或者 DI=DI-1
- 指令格式:STOSW
字串存储指令,将AX寄存器里面的内容送到目的地址,ES:[ DI ],地址自动增减2
AX—>ES:[ DI ] , DI = DI +2 或者 DI=DI-2
- 比如:将附加段偏移地址为300H开始的100个存储单元的内容全部清0;
分析:就是要像将0传到300开始后的100个单元里面,利用STOSW ,地址指针加2(CLD)
串读取指令:
- 将指定主存单元的数据送给AL或者AX,数据串为源操作数,地址为[SI],不影响标志位
- 指令格式::LODSB
字符串读取指令,将[SI]中的内容送到AL寄存器,地址指针自动增减1
- 指令格式:LODSW
字串读取指令,将[SI]中的内容送到AX寄存器,地址指针自动增减2
- 串读取指令,每次都会改变AX或者AL寄存器的内容,所以,指令不带重复前缀。
串比较指令:
- 串比较指令用于比较两个字符串是否相等。将主存中的源操作减去目的操作数,通过比较标志位的状态来判断两个操作数之间的关系。指令按照减法指令设置标志位。
- 指令格式:CMPSB
将源字符串的操作数减去目的字符串的操作数,地址指令自动增减1。
- 指令格式:CMPSW
将源字串的操作数减去目的字串的操作数,地址指令自动增减2。
- 比如:比较字符串STR1和STR2,字符串的长度为20,
如果字符串相等AL置0,不等AL置0FFH
串扫描指令:
- 从数据串中搜索一个我们想要的数据,这个数据叫关键字,放到AL或者AX里面。数据串为目的操作串。将AL或者AX减去目的操作数,根据标志状态比较AL或者AX与操作数之间的关系。指令也是按照减法指令规则设置标志。
- 指令格式:SCASB
字符串扫描指令,将AL寄存器的内容减去目的串ES:[DI]的内容,地址指针自动增减1.
- 指令格式:SCASW
字串扫描指令,将AX寄存器的内容减去目的串ES:[DI]的内容,地址指针自动增减2.
- 比如:搜索STR的字符串,查找是否有空格,有则转去执行FIN。
重复前缀指令:(类似于LOOP指令)
- 串操作指令执行一次,对数据串的一个字节或者字进行操作。串操作指令前都可以加重复前缀指令,用来实现串操作的重复执行,其中重复的次数隐含在CX寄存器里,重复前缀指令不能单独使用,要写在串操作指令之前。
- 重复前缀分为两类 RET是子程序返回,REP是重复前缀
与MOVS、STOS、LODS指令配合的前缀REP,不影响标志位
与CMPS、SCAS指令配合的前缀REPZ和REPNZ,影响标志位ZF
- 指令格式:REP MOVS / STOS / LODS
指令功能:如CX=0,退出串操作,CX不等于0,CX=CX-1 ,重复执行REP 后跟的串操作指令,重复次数是由CX控制。
- 指令格式:REPZ CMPS / SCAS
指令功能:如CX=0或者ZF=0,退出串操作。当CX不等0,且ZF=1时,CX=CX-1,重复执行REPZ 后跟的串操作指令,重复次数是由CX控制。
- 指令格式:REPNZ CMPS / SCAS (N就是NOT的意思)
指令功能:如CX=0或者ZF=0,退出串操作。当CX不等0,且ZF=0时,CX=CX-1,重复执行REPNZ 后跟的串操作指令,重复次数是由CX控制。
- (1)注意:REP 指令使串操作重复CX规定的次数,REPZ、REPNZ使串操作的重复可能会提前结束,根据ZF指的变化。
(2)重复前缀指令和LOOP循环指令的区别:LOOP是先做CX减1 ,再判断;REP是判断再见1。
- 例如1:前面串传送指令的例题;还可以这样实现
题目:将DATA1 说指的50个字节传到DATA2中
- 例如2:利用重复前缀指令来编写程序
- 重复前缀串比较指令用于比较两个数据串是否相等的4种情况:
(1)CX=0,ZF =1,全比完,相同
(2)CX=0,ZF=0,全比完,最后一个数据不同
(3)CX不等于0,ZF=1,未比完,遇到不同的字符,比较结束
(4)CX不等于0,ZF=0,未比完,没有不同的字符,继续比较
- 使用带重复前缀的串比较和串搜索指令时,REPZ 和REPNZ 的选择
(1)对于字符串的比较,比较两个字符串是否相等用REPZ
(2)如果要求找出两串相等的位置,利用PERNZ(数据不相等继续比较)
- 对串扫描指令SCAS,一般使用PERNZ ,也可以用REPZ
- 对串存储指令LODS,一般不与重复前缀一起使用。
处理器控制指令:NOP、LOCK、HLT、ESC、WAIT
概念:处理器控制指令用于控制CPU的操作,实现对CPU的管理,主要有:
有标志寄存器,使CPU通过暂停、等待、与外部设备同步,使CPU空操作等。
- (1)空操作指令:NOP
- (2)指令封锁前缀指令:LOCK
- (3)暂停指令:HLT
- (4)交权指令:ESC
- (5)等待指令:WAIT
- (6)标志操作指令:
指令格式:CLC 进位标志位置0(clear carry)
STC 进位标志位置1(set carry)
CMC 进位标志位求反(complement carry)
CLD 方向标志位置0(clear direction)
STD 方向标志位置1(set direction)
CLI 中断允许标志位置0(clear interrupt)
STI 中断允许标志位置1(set interrupt)
输入/输出指令: IN、OUT
概念:输入输出指令是控制CPU与外设交换数据的指令。
- 端口:PC(个人计算机)通过总线与CPU相连的芯片出来存储器外,还有其他的一些芯片可以存放信息,这些芯片都有一组可以由CPU读写的寄存器,这些寄存器我们叫其为端口。与内部的区分开来。
- 这些寄存器在物理上处于不同的芯片中,但他们也都是和CPU通过总线相连,每个端口在地址空间都有一个固定的地址。CPU通过对I/O设备接口中端口的读写实现与外部设备的数据交换。
- 输入输出指令:IN和OUT(不影响标志位)
IN:数据由端口—> CPU,输入就是指从外面写到CPU
OUT:数据由CPU—>端口 ,输出就是指从CPU写东西到外面去。
在IN和OUT指令中,只能同寄存器AX或者AL寄存器来存放从端口读入的数据或者要发到端口中的数据。
指令格式:
IN AX,n IN AL,n IN AL,DX IN AX,DX
OUT n,AL OUT n,AX OUT DX,AL OUT DX,AX
当端口地址n为8位数据时 ,当输入字节数据时,将端口地址n的内容送到AL中,当输入字数据时,将端口地址n送到AL中,端口地址n+1送到AH中,和成AX
当端口地址为16位的数据时,将16位的端口地址先送到DX寄存器中。当输入的数据是字节数据时,将DX作为端口中的内容送到AL,当输入字数据时,将DX作为端口地址送到AL,[(DX)+1]送到AH。
- 比如:
(1)对8位端口(0~255)进行读写
IN AL,20H;从端口20H读入一个字节
OUT 20H,AL;往端口20H中写入一个字节
(2)对16位端口(256~65535)进行读写时,端口号要提前放到DX里面
MOV DX,2080H;将端口号2080H 放到DX里面
IN AL,DX;从2080H的端口中读入一个字节
OUT DX,AL;从CPU向端口2080H中写入一个字节数据
中断指令和中断返回指令:INT、IRET
概念:中断也是一种改变程序执行顺序的方法。
中断是指:CPU暂停现在运行的程序,转去处理 I/O 设备的请求或者某系紧急的事件,紧急事件处理结束后,CPU会返回原来的程序运行,这个过程就叫做中断过程。
引起中断的事件或者设备叫做“中断源”,原程序被中断的地方叫做“断点”。CPU被中断后转去执行的程序叫做“中断处理程序”或者“中断子程序”。
- 中断类型:
外部非屏蔽中断NMI:中断源来自CPU之外,不接受IF控制的中断,通常情况下,CPU必须相应这类中断。
外部可屏蔽中断INTR:中断源来自CPU之外,是否相应中断受IF的控制,IF=1时CPU相应中断。涉及相关资料有关中断CLI,和开中断STI。
内部中断:中断为程序执行的过程中由程序引发的中断事件,内部中断有4种。
(1)除法错误产生的中断:被0除或者除法溢出时,叫:0号中断
(2)单步中断:当单步执行标准TF=1时,每执行一条指令就产生中断,就是我们平时调试 程序用到的T指令。叫:1号中断
(3)溢出中断:执行中断指令INTO时,如OF=1,则产生溢出中断。叫:4号中断
(4)INT指令中断:执行中断调用指令INT n ,产生指令中断,其中n=0~255
- 中断处理程序:
中断处理程序是指对中断信息进行处理的一段指令,在开机时存于内存的固定位置,它的第一条指令的地址为中断处理程序的入口地址。
CPU要执行某个中断处理程序,必须先获得给程序的入口地址,因此在中断信息(中断类型号)与中断处理程序入口地址间需要建立某种联系。
- 中断向量表:
为了便于CPU管理中断处理程序,将所有的中断处理程序的入口地址都集中的在一起,放在绝对地址为00000~003FFH中,叫做中断向量表。每个中断都有一个类型号,每个中断中断处理程序的入口地址占4个字节(CS和IP各占两个字节)。
中断处理程序的入口地址=中断类型号*4。如4号中断的中断处理程序的入口地址(CS和IP)存放在0010H(4*4=16转化为十六进制:10H)开始的连续的4个字节中。
CPU根据中断类型号通过中断向量表找到相应的中断处理程序的入口地址。
其中,中断类型号0~1FH为BIOS中断;20H~3FH为DOS中断;60H~67H为用户中断。
- 中断指令和中断返回指令:INT、IRET
中断指令:INT
指令格式:INT n;中断调用指令,产生n号中断,n为8位的立即数
溢出中断指令:INTO
指令格式:INTO ;溢出中断指令,若标志位OF=1时,说明发生溢出,产生4号中断
中断返回指令:IRET
指令格式:IRET
- 中断与子程序的关系:
(1)相同点:CPU都暂停当前程序的执行,转去执行另外的程序,当改程序执行时,CPU都会自动恢复到原来的程序去执行。
(2)不同点:
子程序的调用是我们在写程序时事先安排好的,是可知的,而中断是由中断源根据自身的需要产生的,是不可预知的(INT指令引起的中断除外)。
子程序调用用CALL来实现,而中断只有发出中断请求的事件,没有调用中断的指令。
子程序的返回指令是RET(不是REP),而中断服务程序的返回指令是IRET。
一般情况:子程序由开发人员写,中断服务程序由系统软件设计者编写。
第五章 系统功能的调用(五个初学者必须掌握的)
系统功能的调用:一般是指调用DOS的INT 21提供的子程序。调用BIOS提供的中断子程序称为“BIOS调用”
DOS的调用过程
(1)将系统的功能号送到AH
(2)在指定的寄存器中设置有关的入口参数
(3)INT 21H ;这是DOS的中断处理程序,对于不同的系统的功能号,可以完成对不同设备的控制。这个是一段中断子程序,调用后会自动改变AH、AL的内容。注意:在DEBUG的调试过程中,遇到INT 21H只能使用P指令,不能用T。
常用的功能调用:
1.单个字符的输入(1号功能的调用)
格式:
MOV AH,1
INT 21H
功能:等待用户从键盘输入一个字符,并将输入字符的ACSII码送到AL寄存器(输入的字符我们要在AL寄存器里面去找),同时到屏幕上面显示。
说明:执行该调用时,计算机的屏幕上会出现一个闪亮的光标,等待用户输入单个字符,当随便按下一个键,该键的ASCII码将被放入AL寄存器,并将该字符在显示器上显示,不需要按Enter键结束。
2.单个字符输出、显示(2号功能调用)
格式:
MOV AH,2
MOV DL, 字符的ASCII码
INT 21H
功能:在屏幕当前的位置显示DL寄存器中的字符,并将光标后移一格
3.字符串输出、显示(9号功能调用)
格式:
MOV AH,9
MOV DX ,字符串的首地址
INT 21H
功能:将当前数据区DS:DX 所指向的以 $ 结尾的字符串送到显示器上显示。
4.字符串输入(10号功能的调用)
格式:
MOV AH,10
MOV DX,字符串的首地址
INT 21H
功能:从键盘接受一个 字符串,并存入用户定义的输入缓冲区。
该指令的调用,要求输入缓冲区按照规定的格式去定义,并且一定要在当前的数据段,
缓冲区的格式如下定义:
BUF DB n
DB ?
DB n DUP (?)
定义的输入缓冲区,
第一个字符表示:缓冲区能容纳的字符个数
第二个字节表示:保留一个字节单元,由系统自动存入用户从键盘输入的字符个数(就是我们实际输入的字符个数,不包括回车字符)。所以我们输入的字符是从第三个字节开始存放用户从输入的ASCII码的(这里包括回车字符)。当实际输入的字符个数小于缓冲区的大小时,缓冲区的其余字节自动填0,当实际输入的字符大于缓冲区的大小时,多余的字符会丢失,并且扬声器发出警示音。
5.返回DOS调用(4CH号功能的调用)
格式:
MOV AH,004CH
INT 21H
功能:4CH号功能的调用,结合当前正在执行的程序,返回DOS系统,无入口参数。
第六章 零碎小知识
第七章 汇编语言的程序格式
汇编语言格式
(1)指令语句格式:[标号:] 指令助记符 操作数[,操作数] [;注释]
标号:标号的名字由用户自定义,标号后面必须有冒号,代表该指令在代码段中的偏移地址,为分支,循环,调用等指令提供目的地址。标号是不能以数字开头的字符、数字串,长度不超过31个字符,不能使用保留字,保留字包括指令助记符、伪指令助记符、寄存器符号等。
注释:汇编程序在翻译源程序时不对它们做任何处理。
(2)伪指令语句:伪指令是在程序汇编期间由汇编程序处理的操作。
[名字] 伪指令助记符 参数,参数…[;注释]
名字:是反映伪指令偏移地址的标识符,后面没有冒号。取名与标号的取名一样。
伪指令助记符:表示伪指令的所要完成的操作。
参数:为伪指令要求的内容,常数、变量、表达式,允许多个。
比如:
汇编语言的程序格式
完整的汇编语言由若干个代码段、数据段、附加段、和堆栈段组成,段与段之间的顺序可以随意调换。
可运行的程序必须包括代码段,并需要指明程序的起始语句,数据段、堆栈段、附加段都不是必须的
指令语句必须位于某个代码段内,伪指令可按需要位于任一段内。
汇编语句参数
语句参数分数值型参数(立即数)和地址型参数(标号、变量)
数值型参数
1.常数 ,表示一个固定的数值,就是一个数,(十进制、字符串、ASCII码、符号常数等都是)
2.符号常数定义伪指令(EQU 、=)
- 指令格式:
符号名 EUQ 数值表达式(表达式)
符号名 EUQ 字符串
符号名 = 数值表达式
- 功能:给符号定义一个数值或者把符号定义成一个字符串,EUQ两边的等式等效,可以互换
- 等价语句不会给符号分配存储空间,符号名不可以与其他符号同名,也不能被重新定义
- 程序中经常使用到符号常数,而不使用具体数值,这样可以提高程序的易读性,也使程序易于修改。
- EQU和“=”两边可以出现符号,但是该符号必须是有确定值
- 比如:
3.数值表达式:
由常数、寄存器、变量及标号名等用运算符连接起来的式子
(1)算术运算符:+、-、*、/、MOD(取余)、SHL、SHR
(2)逻辑运算符:AND、OR、XOR、NOT
(3)关系运算符:
EQ(等于)、NE(不等于)、GT(大于)、LT(小于)、GE(大于等于)、LE(小于等于)
地址型参数
指:标号,变量,地址表达式
包括变量名、段名、过程名
标号和变量都具有三种属性:段属性、偏移地址属性、类型属性
例如:
例:BUF的段地址是0500H,偏移地址为0015H,BUF为字类型变量。
BUF DW 1111H, 2255H, 3333H
BUF1 DB 9 DUP (1)
求下列指令执行后寄存器的值。
MOV SI, OFFSET BUF ;SI=0015H ;offset:变量或者标号的偏移地址
MOV BX, SEG BUF ;BX=0500H ;SEG 变量或者标号的段地址
MOV DI, TYPE BUF ;DI=2 ;返回类型大小(DB、DW、DD、DF、DQ、、、)
MOV CX, LENGTH BUF1 ;CX=9 ;变量的单元数
MOV DX, SIZE BUF1 ;DX=9 ;变量的字节数=LENGTH * TYPE
MOV AL, BYTE PTR BUF+3 ;AL=22H
特殊运算符
(1)强制类型转换:(WORD、BYTE)PTR
(2)数值返回操作符:
OFFSET |
变量或者标号的偏移地址,与LEA类似 |
SGE |
变量或者标号的段地址 |
TYPE |
表达式是变量:DB=1,DW=2,DD=4 比如:BUF DW 1111H,2222H,3333H MOV DI,TYPE BUF ;DI=2 表达式是标号:NEAR=-1,FAR=-2 表达式是常数:=0 |
length |
变量的单元数,占多少大小,注意:仅仅对DUP语句有效,其他均为1 比如:BUP DB 9 BUP(1) MOV CX,length BUF;CX = 9 |
SIZE |
变量的字节数 = length * TYPE |
第十章 调试DEBUG相关
DUBUR命令
-
反汇编命令:U
可以在后面指定反汇编的地址和结束地址,或者反汇编的长度,如果不指定,默认从当前CS:IP所指位置开始
-
显示内存单元内容命令:D
从指定地址开始显示一定范围内存单元的内容,也可以是数据段的内容
比如:D DS:0000
D 1256:0
-
修改内存单元内容命令:E
将数据输入到内存中指定的地址。
比如:E 1000:10
-
查看或者修改寄存器的内容:R
R 显示当前所有寄存器的内容
R 寄存器名 (显示并修改寄存器的内容)
-
跟踪命令:T
-
跟踪一条指令或者一个子程序:P
CALL、INT 21H等
-
运行程序命令:G
跳转到指定地址执行
-
退出DEBUG:Q
-
想要在debug里面(内存)直接写入汇编语句:A
期末考试记录
例:BUF的段地址是0500第H,偏移地址为0015H,BUF为字类型变量。
BUF DW 1111H, 2255H, 3333H
BUF1 DB 9 DUP (1)
求下列指令执行后寄存器的值。
MOV SI, OFFSET BUF ;SI=0015H
MOV BX, SEG BUF ;BX=0500H
MOV DI, TYPE BUF ;DI=2
MOV CX, LENGTH BUF1 ;CX=9
MOV DX, SIZE BUF1 ;DX=9
MOV AL, BYTE PTR BUF+3 ;AL=22H
例:BUF的段地址是0500H,偏移地址为0015H,BUF为字类型变量。
BUF DW 1111H, 2255H, 3333H
BUF1 DB 9 DUP (1)
求下列指令执行后寄存器的值。
MOV SI, OFFSET BUF ;SI=0015H
MOV BX, SEG BUF ;BX=0500H
MOV DI, TYPE BUF ;DI=2
MOV CX, LENGTH BUF1 ;CX=9
MOV DX, SIZE BUF1 ;DX=9
V AL, BYT PTR BUF+3 ;AL=22H