要了解的内容: 80x86处理器的寄存器 两个最主要的指令:MOV和ADD指令 寻址方式是通过指令体现出来的。 代码段、数据段、堆栈段、附加段 代码段:存放程序的代码,存储用来完成功能的指令 数据段:存放代码操作的数据 堆栈段:存放临时性的信息 附加段:另外一段数据段
逻辑地址和物理地址
堆栈的操作:PUSH和POP
标志寄存器,标志位的作用 控制标志和状态标志
80x86
CPU内部可以分成三个部分:ALU(运算单元)、寄存器、控制单元 8086内部的寄存器有8位的,也有16位的 通用的数据寄存器:AX、BX、CX、DX,都是16位的寄存器 每一个都可以分为两个8位的寄存器来使用 AX分为AH和AL两个8位寄存器。 指针寄存器:BP(基址指针)、SP(堆栈指针)、IP IP(指令指针):就是PC(程序计数器),指向下一条指令的地址 变址寄存器:SI(源)、DI(目标) 控制寄存器:IP、FR FR:标志寄存器16位的,包含了9个标志(其余7个位预留或没定义) 段寄存器CS、ES、SS、DS,也是16位的。 CS(code segment):代码段 DS(data segment):数据段 SS(stack segment):堆栈段 ES(extra segment):附加段 指令寄存器对汇编语言程序员是不可见的,其他寄存器都是可见的。
寄存器 约定从D0到D7代表寄存器的低八位,从D8到D15代表寄存器的高八位 AX、BX、CX、DX除了通用的数据寄存器的功能之外,还分别可以有以下特殊功能 AX可以作为累加器(隐含的寄存器)
BX可以作为基址寄存器(间接寻址的时候) 可以存储要访问的内存单元的地址信息(偏移量) CX可以作为循环的计数器 循环计数器的初始值赋值到CX中 DX在I/O操作的时候作为指向数据的指针,做除法的时候保留被除数或者余数
汇编语言程序设计 引入汇编语言程序设计的目的:记忆二进制代码比较困难,所以引入助记符,帮助编程设计 编写的汇编语言程序并不是CPU能直接执行的代码,要通过汇编器转化为机器代码,才能被CPU直接执行。 典型的汇编器:MASM
MOV指令 操作:数据的传送 MOV destination source 把数据从source复制到destination 源操作数可以是立即数也可以是在寄存器或者存储器中。 目标操作数是寄存器或者内存中。 如何找到源操作数或者目标操作数? 这条指令中,对于不同的源操作数和目标操作数可以采用不同的寻址方式。
可以传送8位的数据,也可以传送16位的数据。 传送8位: MOV CL 55H 传送16位: MOV CX 1255H
MOV指令的规则: 目标操作数不能是立即数。 源操作数和目标操作数都是寄存器的时候,两个寄存器的长度要匹配,要么都是8位,要么都是16位,不能是一个8位一个16位。 标志寄存器FR不能直接用操作数赋值 段寄存器不能直接用操作数赋值 要对段寄存器赋值,只能先送到通用寄存器,然后再送到段寄存器中。 如:MOV DI 1400H MOV SS DI 如果传送的立即数不够寄存器的位数,那么是高位补零,不能立即数的位数不能超过寄存器的位数。 寻址的时候源操作数和目标操作数不能同时位于内存中。
ADD指令 操作:加法运算 ADD destination source 把source和destination相加后存放到destination 规则和MOV指令的规则基本一样。 目标操作数不能是立即数
段:在内存中划分出来的一块块区域 程序在执行的时候至少可以分为代码段、数据段、堆栈段 附加段有时候有,有时候没有,可以把它当做数据段。 一个程序可以有一个或者多个代码段和数据段,但是堆栈段只能有一个。 段的大小?段是如何访问的? 8086的地址是20位,可以访问的地址是1M。 一个段最大的大小是64K。 为什么是64K? 64K需要16个二进制数,需要的地址总线是16位。由于之前的8080的地址线是16位的,位了兼容之前的版本,所以就设计成64K。 寄存器的长度是16位,所以最大能寻址的也是64K。 由于1M需要20位,寄存器只有16位,所以也只能分段来寻址。 首先要知道在哪个段中,找到该段的起始地址,然后找到它在段中的偏移量,由段的起始地址+偏移量就可以寻址特定的数据了。 因为一个段最大位64K,所以偏移量小于64K,所以能用16位寻址。 寻址某个段:
默认每个段的首地址的末四位二进制数为0,十六进制数表示中即最后一位为0。高16位就用寄存器来标志。
物理地址与逻辑地址 物理地址:内存单元对应的20位的地址 逻辑地址:包含段的起始地址和偏移量,都是用16位的二进制数来表示的。
表示方法:CS:IP,CS代表段地址,IP代表偏移量,中间用冒号分隔。
将逻辑地址转化为物理地址: 如:2500H:95F3
1、 读取CS:2500H
2、 左移CS:25000H(这就是段首地址)
3、 加偏移量:25000H + 95F3H = 2E5F3H(寻址的物理地址)
数据段 如果要实现25H+12H+ABH,可以这样实现: MOV AL 00 ADD AL 25H
ADD AL 12H ADD AL ABH
这个程序可以完成这个功能,但是只能完成这三个数相加的功能,如果改动任何一个数据,则必须重新写程序。
解决方法是不要把数据写到指令当中,而是放到数据段中,指令中用直接寻址来找到数据,这样修改数据的时候就不需要修改到程序。 先把数据写到某个内存单元中。
DS:0200 = 25H;DS:0201 = 12H;DS:0202 = ABH 然后再用直接寻址相加。
MOV AL 00 ADD AL [0200] ADD AL [0201] ADD AL [0202]
这样的程序也可以解决问题,但是不够优化,如果有多个数据则指令会比较繁杂,可以采用循环来做。
MOV AL 00H MOV CX 05H MOV BX 0200
ADD_LP: ADD AL [BX]
INC BX DEX CX JNZ ADD_LP 判断是否结束,循环执行。
主程序和调用的子程序位于同一个段中,则称为近程调用,只需要给出偏移地址就可以了,不需要给出段地址。属性为near
如果不在同一个段中,则称为远程调用,需要给出段地址和偏移地址,属性为far
小端规则 引入端的规则的原因:一个寄存器只能存储8位,但是我们需要存储16位的数据,要确定寄存器的顺序。
小端规则:最低有效位存储在低地址单元中。
如:35F3要保存到数据段偏移量为[1500]的内存中,则存储为: DS:1500 = F3;(低8位) DS:1501 = 35(高八位) 堆栈段
堆栈:用来存储临时信息
CPU内部的寄存器可以用来存储临时信息,但是寄存器数量太少了,所以在内存中开辟一段空间来存储临时信息。
堆栈的两个重要操作:入栈(PUSH),出栈(POP) 寄存器:SS、SP SS(stack segment):堆栈段的首地址 SP(stack point):堆栈指针,始终指向堆栈的顶部,是一个偏移量
SP可以指向最后一个压入的数据的位置,这种堆栈称为满堆栈 SP也可以指向下一个压入的数据要存放的位置,称为空堆栈 PUSH:
递增的堆栈:按照地址递增的方向存储数据,PUSH后SS:SP的值增加了 递减的堆栈:按照地址递减的方向存储数据,PUSH后SS:SP的值减小了 在设计处理器的时候就要设计好堆栈的递增递减,x86中是用递减堆栈的。 每一次出栈入栈操作的数据都是16位的,所以SP每次加或者减的值都是2。 PUSH BX:把BX的值压入栈中
POP BX:把栈顶的数值弹出,然后放到BX中
x86中是没办法一次性把所有寄存器压入栈中,每条指令最多能把一个寄存器压入栈
中。
操作栈的时候并不是只能用栈顶的数据,如果需要访问到非栈顶的数据,可以利用堆栈指针BP,先给BP赋值,然后直接对BP直接寻址就可以找到需要的数据了。
MOV BP 0800H MOV AL [BP] 逻辑地址与物理地址的更多了解 一个逻辑地址只对应一个物理地址,而从物理地址到逻辑地址却可以有多种对应关系。 如:物理地址为15020,可以对应1000:5020,也可以对应1100:4020
这代表着一个内存单元可以对应多个段,多个段可以交替,共享同一个内存单元。 对于FF590:FFFF,它已经超过了1M的内存空间,x86采用了循环交替的方式,超过了1M的部分从00000开始继续排列,也就是说无论哪个内存单元都可以分配到一个64K的段中。
标志寄存器
6个标志寄存器,称为条件标志(或者状态标志),有:
CF(carry flag):最高位的进位或者借位,1(CY)代表最高位有进位或者借位,0(NC)代表最高位没有进位或者借位
PF(parity flag):运算结果的低8位中1的个数,奇数个1则为0,偶数个1则为1 AF(auxiliary carry flag):第四位D3到第五位D4是否有进位 经常用来检测两个BCD码相加有没有进位 ZF(zero flag):是否为零
SF(sign flag):符号,与最高位相同,正数为0,负数为1 OF(overflow flag):溢出,1代表有溢出
这6个标志位是在ALU执行指令的时候来改变的。 3个控制标志位,在指令执行之前需要判断 DF(direction):方向标志位 在指令执行之前约束指令如何执行 按照地址递增来传递数据还是地址递减的方向来传送数据 IF(interrupt flag):中断标志位 屏蔽中断可以去设置标志位。 TF(trap flag):陷阱标志 如单步调试,每执行一步,就停下来,这就利用到了这个标志位,设置为1
指令的寻址方式
1、 寄存器寻址
数据就在寄存器中 MOV BX DX
注意两个寄存器的位数一定要匹配 2、 立即数寻址
MOV AX 0030H
不能用立即数给段寄存器或者标志寄存器赋值 3、 直接寻址
MOV DL, [2400]
默认数据在DS(数据段)中,故只给出偏移量 4、 寄存器的间接寻址
只有BX,SI,DI,BP能用在MOV指令的间接寻址中 寄存器存放的是数据的偏移地址 MOV AL, [BX] 默认段寄存器DS,寻址的时候是寻址DS:BX 5、 相对基址寻址
MOV CX, [BX]+10 MOV CX, [BX+10] 寻址DS:BX+10 6、 相对变址寻址
跟上面一样,只不过是用变址寄存器SI和DI MOV DX, [SI]+5 7、 基址变址寻址
基址在BX和BP中二选一 变址在DI和SI中二选一
格式:[基址][变址]+相对偏移量 MOV CL, [BX][DI]+8 寻址DS:BX+DI+8 MOV CL, [BP][SI]+8
寻址:SS:BP+SI+8
可以人为改变默认的数据段,如BP也可以用在数据段中,只要加上前缀就可以了 DS:BP