汇编之寄存器
文章目录
寄存器
概述
一个典型的CPU主要由运算器,控制器,寄存器等器件构成,它们靠内部总线相连(内部总线实现CPU内部各机器件间的联系,外部总线实现CPU和主板上其他器件之间的联系)。
本篇博文叙述CPU中的寄存器,程序员可以通过指令读写寄存器,从而实现对CPU的控制。不同的CPU其寄存器的个数与结构也不相同,以8086CPU为例,其有14各寄存器,每个寄存器有一个名称,且所有寄存器都是16位的,可以存放两个字节,分别为:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW,后面将一一进行介绍。
通用寄存器
AX,BX,CX,DX为四个通用寄存器,用于存放一般性数据(所谓一般性数据指的是那些并非用于CPU控制的数据)。如前所述,8086CPU使用的是16位寄存器,为了兼容之前针对8位CPU编写的程序,每个通用寄存器都可以分为两个8位寄存器来独立使用,即AX可分为AH和AL,BX可分为BH和BL,CX可分为CH和CL,DX可分为DH和DL。如下图所示:
通过汇编语言使用通用寄存器:(汇编语言中不能直接相加两个数字,而是要通过寄存器来做加法)
|
|
**【注】:**在写一条汇编指令或一个寄存器名称时不区分大小写。
代码段寄存器与指令指针寄存器
要说明这两个寄存器,首先我们要理解一下几个概念。
物理地址
每个内存单元都有一个编号,而这就是内存单元唯一的地址,也就是物理地址。
16位结构的CPU
一个16位结构的CPU意味着该CPU具有以下特征:
- 运算器一次最多可以处理16位的数据
- 寄存器的最大宽度位16位
- 寄存器与运算器之间的通路为16位
8086CPU给出的物理地址方法(分段结构)
8086CPU的物理总线的宽度为20,而CPU内部只能处理和传输16位地址,那么如果将地址从内部简单的发出,那么只能送出16位的地址,表现出的寻址能力只有64KB,因此,8080CPU添加了了一个地址加法器,将两个16位地址合并为一个20位的物理地址。其中两个16位地址分别位段地址和偏移地址,地址加法器的计算方法为:物理地址 = 段地址 * 16 + 偏移地址
, 即物理地址 = 段地址 << (20 - 16) + 偏移地址
。如下图所示:
代码段寄存器CS,指令指针寄存器IP
8086CPU含有4个段寄存器(存放段地址):CS,DS,SS,ES。本节只说明CS。CS为代码段寄存器,IP为指令指针寄存器,8086CPU从CS*16 + IP
单元开始读取一条指令并执行,即通过CS寄存器找到段地址,IP则记录的是偏移地址,通过二者可以找到要执行的指令代码。
**其过程如下:**将段地址和偏移地址送至地址加法器,之后通过地址总线送至内存芯片,随后内存芯片将对应地址空间中的内容(指令)通过数据总线送达CPU,此时CPU将增加IP寄存器的值(增加值为所读取指令的长度),以便读入下一条指令。
修改CS、IP的指令
mov指令可以用于修改大部分寄存器的值,但不可以用于修改CS、IP的内容。若想修改,可以使用如下语法:*jmp 段地址 : 偏移地址*,例如:jmp 2AE3:3
执行后 cs = 2AE3H
, IP = 0003H
。若仅想修改IP的内容,可用形如:*jmp 某一合法寄存器* 来完成,比如 jmp ax
或 jmp bx
,那么该语句执行后便会用寄存器中的值修改IP寄存器。
数据段寄存器DS和偏移地址[address]
8086CPU中有一个DS寄存器,通常用于存放要访问数据的段地址,在配合偏移地址[address]来使用,则可以读取指定内存单元中的数据,如:
|
|
上述代码描述了mov指令可以完成的四种操作:1)將数据直接写入寄存器;2)将一个寄存器中的内容送至另一个寄存器;3)将一个内存单元中的内容送至寄存器;4)将寄存器中的数据送入内存单元。
**【注】:**8086CPU不支持将数据直接送入段寄存器,因此修改DS寄存器需要从另一个寄存器移入。
栈寄存器
出栈入栈指令
汇编语言的出栈入栈指令为PUSH和POP,其使用方式如下:
|
|
栈段寄存器SS与偏移寄存器SP
栈顶通过段寄存器ss与偏移寄存器SP指出。在任意时刻SS:SP总是指向栈顶元素,即最后入栈的数据。每次入栈时,push指令都将先移动栈顶指针再写入数据。当栈为空时,栈顶指针SS:SP指向比栈底地址高一个元素大小的位置(栈由高地址向低地址增长)。
**【注】:**将一段地址当作栈段仅仅是编程时的一种安排,而CPU并不会区别的对待这段内存地址空间。
Debug工具
Debug是供程序员使用的程序调试工具,可以用它检查内存中任何地方的字节以及修改任何地方的字节。
-r命令
r命令用于查看和改变CPU寄存器的内容,使用如下图所示
-d命令
可以通过"d 段地址:偏移地址"的格式查看从指定地址起的内存块中的内容。
-e命令
改写内存单元的内容
-a命令
以汇编指令的形式改写指定的内存单元。如下所示:
-t命令
执行-t命令后,CPU将执行CS:IP指向的指令。如下图所示:
小结
- CPU访问内存时,必须向内存提供内存单元的物理地址。8086CPU在内部用段地址和偏移地址移位相加的方法形成最终的物理地址
结论:CPU可以使用不同的段地址和偏移地址形成同一个物理地址
偏移地址16位,变化范围为0~FFFFH,仅用偏移地址来寻址最多可寻64kb个内存单元
在8086PC机,存储单元的地址用两个元素来表述————段地址和偏移地址
可以根据需要,将地址连续,起始地址为16的倍数的一组内存单元定义为一个段
段地址在8086CPU的段寄存器中存放。当8086CPU要访问内存时,由段寄存器提供内存单元的段地址。8086CPU有四个段寄存器,其中CS用来存放指令的段地址
CS存放指令的段地址,IP存放指令的偏移地址
8086机中,任意时刻,CPU将CS:IP指向的内容当作指令来执行
8086CPU的工作执行过程:
- 从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器
- IP指向下一条指令
- 执行指令(转到步骤1,重复这个过程)
8086CPU提供转移指令修改CS:IP的值(jmp指令)
字在内存里存储时,要用两个连续的地址单元来存储,字的低位字节存放在低地址单元中,高位字节存放在地址单元中
用mov指令访问内存单元,可以在mov指令中只给出内存单元的偏移地址,此时,段地址默认在DS寄存器中
[address]表示一个偏移地址为address的内存单元
在内存和寄存器之间传送字型数据时,高地址单元和高8位寄存器,低地址单元和低8位寄存器相对应
mov、add、sub是具有两个操作对象的指令。jmp是具有一个操作对象的指令
在8086CPU提供了栈操作机制:SS段寄存器存放栈顶的段地址,在SP寄存器里存放栈顶的偏移地址。提供入栈和出栈的指令,它们根据SS:IP指示的地址,按照栈的方式访问内存单元
push:①SP=SP-2;②向SS:IP指向的字单元中送入数据
pop:①从SS:IP指向的字单元中读取数据;②SP=SP+2
任意时刻,SS:IP指向的栈顶元素
8086CPU只记录栈顶,栈顶空间大小,是否栈溢出等需要我们自己管理
可以用栈来保存需要恢复寄存器的内容
我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的内存单元。
我们可以用一个段存放数据,将他定义为“数据段”
我们可以用一个段存放代码,将他定义为“代码段”
我们可以用一个段当作栈,将他定义为“栈段”
不管我们如何安排,CPU将内存中的某些内容当作代码,是因为CS:IP指向了那里;CPU将内存中的某些内容当作栈,是因为CS:IP指向了那里
所以,一段内存既可以是代码的存储空间,又可以是数据的存储空间,还可以是栈空间,也可以是栈空间,也可以什么都不是。关键在于CPU寄存器的设置,即CS、IP、SS、SP、DS的指向。
文章作者 cold-bin
上次更新 2022-11-30