您的位置 首页 java

实模式下CPU如何获取数据及指令

摘要

  1. 寄存器
  2. 实模式下的CPU寻址方式
  3. 寄存器寻址
  4. 立即数寻址
  5. 内存寻址

1. 寄存器

寄存器是一种物理存储原件,速度可以跟上CPU的速度,所以CPU内部使用各种类型的寄存器供读取数据来使用。这里可以看出寄存器的主要用途:

  • 为CPU存储数据
  • 解决从其他硬件获取数据与CPU执行速度不匹配的问题

CPU中的寄存器大致分为两类:

  • 内部使用,对程序员不可见(不可使用):GDTR(全局描述符表寄存器)、IDTR(中断描述符表寄存器)、LDTR(局部描述符表寄存器)、TR(任务寄存器)、CR0~3(控制寄存器)、(IP)指令指针寄存器、flags(标志寄存器)、DR0~7(调试寄存器)
  • 程序员可见(可以直接操作)的寄存器:段寄存器、通用寄存器

实模式下默认用到的寄存器都是16位。

1.1 内部寄存器

内部寄存器虽然不可以直接使用,但是部分寄存器必须要通过我们的代码进行初始化。

  • GDTR需要通过lgdt指令为其指定全局描述符表的地址及偏移量
  • IDTR需要通过lidt指令为其指定中断描述符表的地址
  • LDTR需要通过lgdt指令为其其指定局部描述符表ldt
  • TR需要通过ltr指令为其指定一个任务状态段tss

1.2 可见寄存器

1.2.1 段寄存器

段寄存器是CPU用来寻址使用,CPU默认的寻址方式是**”段基址”:”段内偏移地址”**,段基址就是用段寄存器来进行存储。

在我们计算机加载我们的程序以后,会将我们的应用程序在内存大致分为三个部分:

  • 代码段:该内存区域存储了我们应用程序的指令
  • 数据段:该内存区域存储的是我们需要使用到的数据
  • 栈段:CPU运行时的必须

段寄存器主要由以下分类:

  • CS(代码段寄存器):存储代码段的起始地址
  • DS(数据段寄存器):存储数据段的起始地址
  • SS(栈段及寄存器):存储栈的起始地址
  • ES、CS、GS(附加段寄存器)

可见寄存器CS:内部寄存器IP存储了CPU下一条待执行指令的地址。

1.2.2 通用寄存器

通用寄存器主要由以下几类组成:

  • AX(累加器):由低8位的AL寄存器和高8位的AH寄存器组成,常用于算数运算、逻辑运算、保存外设输入输出的数据
  • BX(基址寄存器):由低8位的BL寄存器和高8位的BH寄存器组成,常用于存储内存地址,用此地址作为基址遍历一片内存区域
  • CX(计数器):由低8位的CL寄存器和8位的CH寄存器组成,常用于计数(循环指令中的循环次数)
  • DX(数据寄存器):由低8位的DL寄存器和高8位的DH寄存器组成,常用于保存外设控制器的端口号地址
  • SI(源变址寄存器):常用于字符串操作中的数据源地址(被传送的数据在哪里)
  • DI(目的地址寄存器):常用于字符串操作中的数据目的地址(数据被传送到哪里)
  • SP(栈指针寄存器):段基址寄存器是SS,用来指向栈顶。push和pop会修改SP的值
  • BP(基址指针):SP永远指向栈顶,我们无法访问栈顶和栈底之间的数据,如果想要访问这期间的数据就需要借助SS:BP

2. 实模式下的CPU寻址

指令都是由操作码和操作数组成,操作数可以是源操作数、目的操作数,寻址就是寻找操作数的地址。

寻址的方式主要分为以下三类:

  • 寄存器寻址
  • 立即数寻址
  • 内存寻址

2.1 寄存器寻址

只要牵涉到寄存器的操作,无论是源操作数还是目的操作数,都是寄存器寻址。

 ; 将0x10存入ax寄存器
mov ax, 0x10
;将0x9存入dx寄存器
mov dx, 0x9
;求ax和dx的乘积,高16位在dx寄存器,低16位在ax寄存器
mul dx  

这三条命令都属于寄存器寻址。

2.2 立即数寻址

指令都是由操作码和操作数组成,如果操作数可以直接存在指令中,拿过来即可使用,那么该数成为立即数。

 mov ax, 0x10
mov dx, ax  

第一条命令的源操作数是0x10,目的操作数是ax寄存器,所以第一条命令即是寄存器寻址又是立即数寻址。

第二条命令只涉及到寄存器,因此它只是寄存器寻址。

2.3 内存寻址

寄存器寻址和立即数寻址中,源操作数和目的操作数不在内存中。相反操作数在内存中的寻址方式则称为内存寻址。

实模式下CPU访问内存采用的是 段基址:段内偏移 的形式,计算方式是 物理地址 = 段基址*16(相当于左移4位) + 段内偏移地址,默认情况下,数据段寄存器是DS。

内存寻址的方式主要有:

  • 直接寻址
  • 基址寻址
  • 变址寻址
  • 基址变址寻址

2.3.1 直接寻址

直接寻址就是将操作数的内存地址在指令中直接给出。

 mov ax, [0x1234]
mov ax, [fs:0x5678]  

第一条指定是将内存地址为(DS*16 + 0x1234)的值写入ax寄存器。

第二条指定是将内存地址为(FS*16 + 0x5678)的值写入ax寄存器。

2.3.2 基址寻址

基址寻址是指操作数用BX寄存器或BP寄存器作为地址的开始,地址的变化都以其为基础。实模式下只能使用BX或BP寄存器作为基址,保护模式下则无这种限制。

BX寄存器的默认段寄存器为DS,BP寄存器的默认段寄存器为SS。

 int a = 0;
function(int b, int c) {
    int d;
}
a++;  

2.3.3 变址寻址

变址寄存器类似于基址寄存器,寄存器由BX、BP换成了SI、DI。SI是指源索引寄存器、DI是指目的索引寄存器。默认的端寄存器都是DS。

 mov [di], ax
mov [si+0x1234], ax  

第一条指令是将寄存器AX中的值存入DS:DI指向的内存地址处。

第二条指令是将寄存器AX中的值存入DS:(DI+0x1234)指向的内存地址处。

2.3.4 基址变址寻址

基址变址寻址就是采用基址变址+变址寻址的组合。如下:

 mov [bx+di], ax  

该条指令的含义就是将寄存器AX中的值存入DS:(BX+DI)指向的内存地址处。

3. 栈

栈是一种什么数据结构这里就不说了,我们这里讲的栈是一片内存区域,栈中的内存地址也是采用 段寄存器SS中的值*16 + 栈指针寄存器SP 来访问。

硬件提供了相应的方法来存取栈,即PUSH和POP指令。

栈是从高地址往低地址发展,因此栈顶的指针指向的地址会越来越低。

我们在访问栈的时候,访问的内存依然是从低地址到高地址,假设当前栈顶是0x1233E,栈顶数据如果占2字节的话,则范围是0x1233E~0x1233F。

PUSH指令压入数据的过程:

  1. 将SP减去字长(CPU一次可处理的数据长度,实模式下为16位)
  2. 所得的差存入SP,栈顶更新完成
  3. 将数据压入SP所指向的内存地址处

POP指令弹出数据的过程:

  1. 弹出栈顶的数据(SP指向的内存地址)
  2. 将SP加上字长
  3. 所得的和存入SP,栈顶更新完成。

本期寄存器及实模式下CPU的寻址方式就介绍到这,“ 点赞 ”+“ 关注 ,我们下期再见!

文章来源:智云一二三科技

文章标题:实模式下CPU如何获取数据及指令

文章地址:https://www.zhihuclub.com/187527.shtml

关于作者: 智云科技

热门文章

网站地图