汇编03:寄存器

Posted yinyunmoyi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了汇编03:寄存器相关的知识,希望对你有一定的参考价值。

寄存器

一个CPU由以下几个部分组成:

1、运算器:负责信息处理

2、寄存器:进行信息储存

3、控制器:控制各种器件进行工作

4、内部总线:连接各种器件(外部总线实现CPU和主板其他部件的联系)

通用寄存器

8086CPU的所有寄存器都是16位的,可以存放两个字节,AX、BX、CX、DX这4个寄存器通常用来存放一般性的数据,被称为通用寄存器。它的上一代CPU中的寄存器都是8位的,为了保证兼容,使原来基于上代CPU编写的程序稍加修改就可以运行在8086之上,8086CPU的AX、BX、CX、DX这4个寄存器都可以分成2个可独立使用的8位寄存器使用:如AX可以分为AH和AL、BX可以分为BH和BL:

技术图片

AX的低8位组成了AL寄存器、高8位组成了AH寄存器,它们分别都可以独立使用。当分别使用这两个寄存器时,这两种寄存器是独立的,一个寄存器的进位不会影响另一个寄存器。在汇编指令中,不能让操作对象的位数不一致,如果一个是8位,一个是16位(比如在16位寄存器和8位寄存器之间传递数据、将大于最大容量的数据直接存放在寄存器中等),就会出错。

8086CPU可以一次性处理以下两种尺寸的数据:字节byte(8bit)、字word(2byte)

”2地址字单元“表示该字单元(2bytes即2个内存单元)的起始地址为2。在存入一个字的时候,高字节在高地址位,低字节在低地址位。

物理地址

8086CPU是16位CPU,16位CPU意味着:

1、运算器一次最多可以处理16位的数据

2、寄存器的最大宽度为16位

3、寄存器和运算器之间的通路为16位

8086CPU有20位地址总线,如果只是将地址从内部简单的发出,它只能发出16位的地址,8086CPU采用一种在内部用两个16位地址合成的方法形成一个20位的物理地址:

技术图片

CPU内部提供两个16位的地址,一个称为段地址一个称为偏移地址,这两个地址通过内部总线送入一个称为地址加法器的部件,合成为一个20位的物理地址,然后通过输入输出电流将该物理地址送入地址总线,最后传送到存储器。

地址加法器中完成的计算是:物理地址=段地址*16+偏移地址。(乘16相当于段地址左移4位),这个公式其实是:物理地址=基础地址+偏移地址。

段并不是内存地址空间的基本划分,而是抽象出来的一个概念,在编程时根据具体情况,将若干地址连续的内存单元看成一个段,这个段有起始地址(起始地址=段地址*16),有大小。同一个内存地址空间,可以根据不同情况有多种划分:

技术图片

根据段地址和物理地址的转换规则,段的起始地址一定是16的倍数,因为偏移地址最大为16位,有64KB的寻址能力,所以一个段的最大长度为64KB。

“数据在内存21F60H单元中”等价于“数据存在内存的2000H段中的1F60H单元中”

在8086CPU中,段地址在段寄存器中存放,段寄存器有四种:CS、DS、SS、ES。

CS和IP寄存器

这两个寄存器是8086CPU中最关键的两个寄存器,它们指示了CPU当前要读取指令的地址。CS为代码段寄存器,IP为指令指针寄存器。设CS中的内容为M,IP中的内容为N,8086CPU将从内存M*16+N开始,读取一条指令并执行。也可以表述为:CPU将CS:IP指向的内容当做指令执行。

当从对应物理地址取出一条指令执行时,IP中的值就要增加,如果指令长度为3字节,对应IP的值就要加3个字节的地址,然后继续取指令执行。指令从内存中取出,传送到CPU的指令缓冲器中,然后送到执行控制器中执行。一直重复这个过程。

在8086CPU加电启动或者复位后,CS和IP分别被置为FFFFH和0000H,然后开始执行上述过程,FFFF0H单元中的指令是8086PC机开机后执行的第一条指令。

CS和IP寄存器的另一个特殊之处在于mov指令无法修改它们两个的值,修改CS和IP寄存器的指令是jmp指令,它的基本格式是"jmp段地址:偏移地址",如"jmp 2AE3:3"代表CPU将从2AE33H中读取指令,其中CS寄存器中的值被修改为2AE3H,IP寄存器中的值被修改为0003H。此外,还可以直接执行"jmp ax"指令来直接将ax寄存器中的值赋值给IP寄存器,这个指令可以直接修改IP寄存器的值。

DS寄存器和[address]

DS寄存器是段寄存器的一种,经常用来存放要访问数据的段地址。

读取10000H的内容:

mov bx,1000H			将1000H这个数放到寄存器bx中
mov ds,bx				将bx寄存器的值放入ds寄存器中
mov al,[0]				将段地址为1000H,偏移量为0的内存地址的值放入al寄存器中

注意仅知道偏移量是无法唯一确定地址的,还需要知道段地址,指令执行的时候会自动从ds寄存器中读取段地址。而且不能直接将1000H数据放入ds寄存器中,8086CPU不支持这种操作,这与其硬件设计有关,所以只能先用一个寄存器进行中转了。

同理,将al寄存器中的数据放入内存单元中:

mov bx,1000H			
mov ds,bx
mov [0],al				将al寄存器中的值放入段地址为1000H,偏移量为0的内存地址

mov指令访问内存单元的时候,方括号只是标出了偏移地址,段地址默认存在DS寄存器中。

mov、add、sub指令

mov可以用来在寄存器之间、寄存器和内存单元传递数据,还可以把数据直接赋值到寄存器中(注意在汇编源程序中,数据不能以字母开头,如A000h,必须写为0A000h):

mov ax, 8				将数字8赋值给ax寄存器
mov ax, bx				将bx寄存器的值赋值给ax寄存器
mov ax, [0]				将偏移量为0的内存单元的值赋值给ax寄存器

mov可以传1个字,也可以传递1个字节,这取决于目标寄存器的容量。

add和sub也有两个操作对象,它们的用法和mov类似,也可以操作内存和寄存器:

add ax, 8				将寄存器ax中的值加8
sub ax, bx				将寄存器ax中的值减去bx寄存器中的值,然后存入ax中

入栈和出栈指令:(8086CPU的入栈和出栈操作都是以字为单位进行的)

push ax				将ax寄存器中的值送入栈中
pop ax				将栈顶数据取出送入ax寄存器中

当然这些指令也可以使用内存地址和段寄存器作为操作对象。

有两个寄存器存放栈顶的地址,分别是段寄存器SS和寄存器SP,任意时刻下,SS:SP指向栈顶元素。

当执行push或pop指令的时候,都伴随着寄存器SP中值的修改,其中的地址要偏移两个字节(push时指针向低地址移动,pop时向高地址移动)。

8086CPU不保证对栈的操作正确,当栈满的时候push,或栈空的时候pop,都可能会影响栈以外的数据,引发一连串错误,所以在编程的时候要注意这个问题(或许我们可以设置两个寄存器装着栈空间的范围,每次操作的时候检查是否超出范围,但是8086CPU中没有这样的设计)

push和pop本质上是内存传送指令,只不过它要访问的内存单元的地址不是在指令中给出的,而是由两个寄存器给出的,而且这两个指令在操作时还要改变SP寄存器中的值。

以上是关于汇编03:寄存器的主要内容,如果未能解决你的问题,请参考以下文章

Linux汇编教程03:大小比较操作

意外覆盖通用寄存器

8086汇编 段寄存器

汇编 LEA 指令

8086汇编学习之代码段数据段栈段与段地址寄存器

汇编小记16/3/23