【汇编语言 】物理地址与段寄存器

前言

当CPU在访问内存单元的时候,需要给出内存单元的地址。所有内存单元构成了一个一维的线性地址空间,每个内存单元在整个空间都有一个唯一的地址,这个唯一的地址被称之为物理地址。

CPU通过地址总线送入存储器中的地址,必须是一个物理地址,存储器才能读写该内存单元。

不同的CPU形成物理地址的方法不同,本篇讨论的是8086形成物理的过程,并且涉及到内存地址的数字皆为16进制。

1. 16位结构的CPU

16位的CPU拥有下面几种特性

  • 运算器一次最多可以处理16位的数据
  • 寄存器的最大宽度为16位
  • 寄存器和运算器之间的通路为16位

即在8086内部,能够一次性处理,传输、暂时存储的信息长度最大为16位。

2. 物理地址的合成

2.1 物理地址的来源

但是8086的地址总线宽度却为20位,可以传送20位的地址,寻址能力达到 1 MB。但是从8086的内部构造来看,它只能送出16位的地址,寻址能力仅仅只有64KB,CPU内部的信息处理能力和外部的硬件最大传送能力不匹配,这无疑是对地址总线宽度的浪费。

8086CPU内部为了匹配地址总线的寻址能力,采用了两位16位的地址合成一个20位的地址。

即使用了段地址 + 偏移地址的概念。

当CPU需要读写内存时,需要提供20位的物理地址,地址合成如下:

  • CPU中的相关部件提供两个16位的地址,一个为段地址,一个为偏移地址
  • 段地址和偏移地址通过内部总线送到地址加法器这个器件中
  • 地址加法器将两个16位的地址合成为一个20为的物理地址
  • 被合成后的物理地址通过内部总线送到输入输出控制电路中
  • 输入输出控制电路器件将地址送入外部总线中的地址总线中
  • 20位的地址被传送到内存中
image-20210806204824769

2.2 物理地址的合成过程

地址加法器采用物理地址 = 段地址 * 16 + 偏移地址的方式对物理地址进行合成。

计算机中的所有信息通过二进制的方式进行存储,16位的地址扩展为20位,那么只需要将段地址左移4位,也就是段地址 * 16

合成过程如下:

如果计算机需要访问一个内存地址为123C8H的内存单元,这是一个20位的地址

因为地址是通过16进制的方式表示,在16进制中,一个数码需要使用4个bit表示。123C8H拥有5个数码,H是16进制的后缀,所以5个16进制的数码 = 5 * 4 = 20位

将这个内存地址进行拆分,123C8H = 12300H + 00C8H

image-20210806211932992image-20210806211947753

image-20210806212008090image-20210806212023796

得到物理地址后将物理地址由输入输出电路输出即可。

二进制的 100 * 2 = 1000

十进制的 100 * 10 = 1000

同理

十六进制的 100 * 16 = 1000

2.3 段地址 + 偏移地址的本质含义

段地址 + 偏移地址本质上就是利用一个基础的地址和一个相对于基础地址的偏移地址相加,得到具体的物理地址

在8086CPU中,通过基础地址(段地址 * 16)+ 相对于段地址的偏移地址得到一个具体的物理地址。这里的基础地址是通过段地址 * 16获取。

但是可能在其他的CPU中,基础地址可能是通过基础地址 * 32 实现,也有可能通过段地址 * 64实现。

2.4 内存并未分段

因为段地址这个概念的出现,可能有人认为内存是分成一个一个段的,每一个段有一个段地址,但是内存并没有分段,分段的划分来自CPU,内存是连续的,并没有分段。

在一维坐标轴中,想要表示一个范围内的数据,也就是将坐标轴分段,通常使用区间进行表示。

  • 区间表示法:

想要表示 3 到 7 这个区间,使用 [3, 7] 进行表示,但是还可以使用另外一种方法进行表示

  • 起点 + 范围表示法:

起点是 3, 范围大小区间为 [0, 4](正反向),也能表示 [3, 7] 这个范围。

而段地址 + 偏移地址和第二种方法神似。

所以偏移地址的大小决定了一个段最大的长度

在8086中,偏移地址是16位的,所以一个段的最大长度位 216 Byte,也就是64KB

3. CS和IP

3.1 CS和IP的概念

CS寄存器(代码段寄存器), IP寄存器(指令指针寄存器),这两个寄存器是CPU中最重要的两个寄存器。

它们指示了CPU当前需要读取的指令在内存上的物理地址。通过上面的物理地址的合成,需要段地址和偏移地址对一个物理地址进行合成,CS中就存放着段地址,IP中就存放着偏移地址

在冯诺伊曼机器中,我们知道计算机指令应该是顺序执行的,计算机应当知道需要执行的下一条执行的指令的地址,那下一条指令的地址如何而来,下一条指令的地址就存放于 CS * 16 + IP 这个物理地址上。

每当CPU需要执行指令的时候

  • CPU会将 CS 和 IP 的两个寄存器中的地址合成为物理地址
  • 通过内部总线将地址发送到输入输出控制电路
  • 输入输出控制电路将物理地址中发送到外部总线的地址总线上
  • 内存在收到物理地址的时候,会将对应的物理地址上的指令通过数据总线发送给CPU
  • CPU就能执行对应的命令
  • 执行命令后IP寄存器中的值会自动加上上一条执行指令的长度,以指向下一条需要执行的指令

如果CPU需要执行其他位置的指令,修改CS和IP寄存器中的内容,即可挑选CPU需要执行的指令的地址。

在内存中,我们知道指令和数据没有任何的区别,都是二进制数据,那么CPU在工作的时候,肯定不能将指令看为数据,肯定不能将数据看为指令,在我们看来完全一样的数据,CPU是怎么区分的呢?也就是什么时候将二进制数据看为指令,什么时候将二进制数据看为数据。

其实我们只需要负责CS:IP寄存器指向的内容就好,也就是CPU将永远认为CS:IP寄存器指向的内存单元中的二进制数据就是指令。

3.2 CS和IP的修改

3.2.1 不能使用mov指令

当我们想要修改AX,BX,CX,DX等通用寄存器中的内容的时候,我们需要使用mov指令进行修改。

但是CS寄存器和IP寄存器中的内容不能使用mov指令修改。

示范:

;错误
MOV CS, 037F 

;错误
MOV AX, 037F 
MOV CS, AX 

3.2.2 可以使用jmp指令

一、同时修改CS和IP

使用jmp指令可以修改CS和IP寄存器中的内容

格式:jmp 段地址:偏移地址

例如:

假设 CS = 7777, IP = 8888

现在执行指令 jmp 9999:0000

执行了指令之后CS = 9999,IP = 0000

二、只修改IP寄存器

使用jmp指令加上通用寄存器,即可修改IP寄存器中的内容

格式:jmp 寄存器

例如:

假设 CS = 7777, IP = 8888,AX = 0000

现在执行指令 jmp AX

执行了指令之后 CS = 7777, IP = 0000

4. debug下的测试

4.1 测试思路

1000:0000 为程序入口

执行:mov ax, 1000 ;mov bx, 2000

执行后 ax = 1000, bx = 2000

执行: jmp 2000:0000

执行后:CS = 2000, IP = 0000

跳转到内存中的 2000:0000 单元

执行: add ax, bx

执行后:ax = 3000,

执行: jmp ax

执行后: CS = 2000,IP = 3000

跳转到内存中的2000:3000

执行:mov cx, 1234

执行后:cx = 1234

image-20210807163507224

4.2 测试

  1. 向内存中写入对应的指令
    image-20210807165329327

  2. 修改CS和IP的指向,使CS和IP指向程序的入口
    image-20210807165833921

  3. 执行mov ax, 1000 和 mov bx, 2000
    image-20210807170126774

  4. 执行了jmp 2000:0000之后,CS寄存器中的内容从1000改成2000,IP改成了0000;而接下来即将执行的指令也变成了2000:0000处的 add ax, bx ;执行后 ax = 3000
    image-20210807170525995

  5. 执行jmp ax 后,IP = 3000;而2000:3000处的指令为mov cx, 1234,执行了之后CX中的内容为1234
    image-20210807171028164

猜你喜欢

转载自blog.csdn.net/qq_45978890/article/details/119489581
今日推荐