第一章 计算机基础知识
概述计算机系统
硬件
软件
计算机中的数制
十进制、二进制、十六进制转化
BCD码
原码、反码、补码
机器语言、汇编语言、高级语言
微处理器及系统结构-toc" style="margin-left:0px;">第二章 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命令
期末考试记录
第一章 计算机基本知识
计算机系统的概述
- 汇编语言:是一种直接在硬件上面工作的编程语言。
- 汇编语言:是面向机器的语言。
- 汇编语言:重点是如何利用硬件系统的编程结构和指令集有效灵活的控制系统进行工作。
- 完整的计算机系统由硬件系统(就是指我们所能莫到的实物)和软件系统(就是虚拟的,在计算机里面的东西)。
- 硬件是软件建立和依托的基础,软件是计算机系统的灵魂。两者不可分割。
- 用机器指令语句、伪指令语句、宏指令语句表示的一种面向机器的语言称为 汇编语言 。
- 用该语言编写的程序需要经过 汇编 翻译,成为计算机能直接识别并执行的程序称机器语言。
硬件
下图所示
- 虚线表示:控制信号,起控制的作用
- 实线表示:数据或者指令,在计算机内部,数据指令都是以二进制的形式存储的
总线(用来传送以下三种信息)有:
- 地址总线(20位):传送地址信息
- 数据总线(16位):传送数据信息
- 控制总线(16位):传送控制信号
输入设备:如键盘、鼠标、扫描仪等,当计算机要进行数据处理时,必须将程序和数据送到内存转化为计算机所能识别的电信号(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的利用率和执行速度
- 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---标志寄存器或叫程序状态字寄存器
- 用来存放CPU要执行的下一条指令,存放代码段中的偏移地址,程序运行时,BIU自动自动修改IP,IP始终指向下一条指令的首地址,与段寄存器CS联合使用,指向下一条指令的物理地址CS:IP
其中条件码标志有六个: 作用是用来记录程序运行结果的状态信息,运行的结果由CPU自动设置,后续主要用于条件转移控制的条件,所以叫条件码。
- 溢出标志,仅仅对于有符号数。在运算过程中,如果操作数超出了机器所能表示的范围,OP自动置1(OF=1),否则置0。(如果是八位:+127 ~ -128,16位:+32767 ~ -32768 ) 有符号数相加,如果结果的符号数和操作数的符号数相反,则OF=1
- 进位标志,仅仅对于无符号数,对于无符号数没有溢出的说法,只是说表示不下,超出范围,所以有进位,记录运算时是否有从最高有效位产生进位或者借位,有进位则CF=1,否则CF=0
- 符号标志位,表示有符号数运行结果的正负,结果为负时SF=1,否则SF=0;
- 辅助进位标志,记录运算时第3位产生的进位值,运算时第3位有进位值:AF=1,否则ZF =0
- 零标志位,当运算结果为0时,ZF=1,运算结果不为0,则 ZF= 1
- 奇偶标志,当结果操作数(二进制数)中1 的个数为偶数个时:PF=1,为奇数个时PF=0,常用于检验是否产生数据传输错误。
- 用于在进行串处理指令中控制处理信息的方向,当DF=1时,每次操作后SI和DI自动减小,实现了串处理时从高地址向低地址方向进行处理。DF=0时,SI和DI增大,使串处理从低地址向高地址方向处理。
- 也叫单步跟踪标志,在DOS环境下,调试程序用的T命令就是这个实现单步调试,TF=1时,每条指令后会产生陷阱,由系统控制计算机,TF=1时,CPU正常工作,不产生陷阱。
- 当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(附加数据段寄存器)。每一个段寄存器可以确定相应段的起始地址,每一个段都有自己各种的用途
除非专门去指定,一般情况下,各段在存储器中的分配是由操作系统负责的,每个段可以独立占用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)
直接寻址方式:
- 直接寻址方式 的操作数地址是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-----就是这个意思。
寄存器间接寻址方式:
- 其中,操作数的有效地址在 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是我们可以随便取的值
- 使用场景:常用于结构体、数组、二维数组。
基址变址寻址方式:
- 上面我们可以知道:基址寄存器(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 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.立即数不能直接传给段寄存器,需要通过通用寄存器中转。
- 两个存储单元之间不可以直接传送数据,也就是内存单元之间不可以,适用于所有的指令。
- 目的操作数不能是 立即数 和 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 DSPOP [ 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累加器
以下几个指令学了一个学期也没怎么用,具体怎么实验我不太懂,后面用到了我再来解释吧。
- SAHF
- PUSHF
- POPF
地址传送指令: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+OPSADC :带进位的加法指令 指令格式:ADC OPD,OPS 指令功能:就是在ADD的基础上再加上标志寄存器中CF 的值:OPD = OPD+ OPS + CFINC:加一,类似于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 - OPSSBB:带进位的减法指令 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 ;这条指令会自动