• 【Linux】x86结构


    【Linux】x86结构

    x86 平台:开放、统一、兼容

    1 计算机的工作模式

    CPU(Central Processing Unit,中央处理器) 是计算机中最核心的单元,负责数据的计算。CPU 通过 总线(Bus) 与其他设备相连,在这些设备中,最重要的是 内存(Memory)。因为单靠 CPU 是没办法完成计算任务的,很多复杂的计算任务都需要将中间结果保存下来,然后基于中间结果进行进一步的计算。CPU 本身没办法保存这么多中间结果,这就要依赖内存了。

    image-20221104195329083

    CPU 和内存是完成计算任务的核心组件,那他们是如何配合完成工作的呢?

    CPU 实际上是由三个部分组成:

    • 运算单元只管运算,如加法、位移等;
    • 控制单元;统一的指挥中心,它可以 获得下一条指令,然后执行这条指令。这个指令会指导运算单元取出数据单元中的某几个数据,计算出个结果,然后放在数据单元的某个地方;
    • 数据单元:包括 CPU 内部的缓存和寄存器组,空间小,但速度快,暂存数据和运算结果

    进程一旦运行,比如图中两个进程 A 和 B,会有独立的内存空间,互相隔离,程序会分别加载到进程 A 和进程 B 的内存空间里面,形成各自的代码段(实际上更加复杂)。

    image-20221104195755504

    CPU 的控制单元里面,有一个 指令指针寄存器,它里面存放的是下一条指令在内存中的地址。控制单元会不停地将代码段的指令拿进来,先放入指令寄存器。

    当前的指令分两部分:

    • 做什么操作,例如是加法还是位移;
    • 操作哪些数据

    要执行这条指令,就要把第一部分交给运算单元,第二部分交给数据单元。数据单元 根据数据的地址,从数据段里读到数据寄存器里,就可以参与运算了。运算单元 做完运算,产生的结果会暂存在数据单元的数据寄存器里。最终,会有指令将数据写回内存中的数据段。

    CPU 和内存来来回回传数据,靠的都是总线。其实总线上主要有两类数据,一个是地址数据,也就是我想拿内存中哪个位置的数据,这类总线叫 地址总线(Address Bus);另一类是真正的数据,这类总线叫 数据总线(Data Bus)。

    地址总线的位数,决定了能访问的地址范围到底有多广。 例如只有两位,那 CPU 就只能认 00,01,10,11 四个位置,超过四个位置,就区分不出来了。位数越多,能够访问的位置就越多,能管理的内存的范围也就越广

    数据总线的位数,决定了一次能拿多少个数据进来。 例如只有两位,那 CPU 一次只能从内存拿两位数。要想拿八位,就要拿四次。位数越多,一次拿的数据就越多,访问速度也就越快

    2 8086处理器原理

    我们来看 x86 中最经典的一款处理器,8086 处理器。虽然它已经很老了,但是咱们现在操作系统中的很多特性都和它有关,并且一直保持兼容。

    image-20221104200901401

    2.1 数据单元

    为了暂存数据,8086 处理器内部有 8 个 16 位的通用寄存器,也就是刚才说的 CPU 内部的数据单元,分别是 AX、BX、CX、DX、SP、BP、SI、DI。这些寄存器主要用于在计算过程中暂存数据。

    这些寄存器比较灵活,其中 AX、BX、CX、DX 可以分成两个 8 位的寄存器来使用,分别是 AH、AL、BH、BL、CH、CL、DH、DL,其中 H 就是 High(高位),L 就是 Low(低位)的意思。

    2.2 控制单元

    IP 寄存器 就是 指令指针寄存器(Instruction Pointer Register),指向代码段中下一条指令的位置。CPU 会根据它来不断地将指令从内存的代码段中,加载到 CPU 的指令队列中,然后交给运算单元去执行。

    每个进程都分代码段和数据段,为了指向不同进程的地址空间有 4 个 16 位的段寄存器,分别是 CS、DS、SS、ES。其中,CS 就是 代码段寄存器(Code Segment Register),通过它可以找到代码在内存中的位置;DS 是 数据段的寄存器(Data Segment Register),通过它可以找到数据在内存中的位置。SS 是 栈寄存器(Stack Register)

    对于一个段,有一个起始的地址,而段内的具体位置,称为 偏移量(Offset)。在 CS 和 DS 中都存放着一个段的起始地址。代码段的偏移量在 IP 寄存器中,数据段的偏移量会放在通用寄存器中

    这时候问题来了,CS 和 DS 都是 16 位的,也就是说,起始地址都是 16 位的,IP 寄存器和通用寄存器都是 16 位的,偏移量也是 16 位的,但是 8086 的地址总线地址是 20 位。怎么凑够这 20 位呢?方法就是“起始地址 *16+ 偏移量”,也就是把 CS 和 DS 中的值左移 4 位,变成 20 位的,加上 16 位的偏移量,这样就可以得到最终 20 位的数据地址。

    2.3 计算单元

    不展开,可看csapp,后续再填坑。

    3 从 8086 进行扩展与兼容

    首先,通用寄存器有扩展,可以将 8 个 16 位的扩展到 8 个 32 位的,但是依然可以保留 16 位的和 8 位的使用方式。其中,指向下一条指令的指令指针寄存器 IP,就会扩展成 32 位的,同样也兼容 16 位的。

    image-20221104201851371

    而改动比较大,有点不兼容的就是 段寄存器(Segment Register)。CS、SS、DS、ES 仍然是 16 位的,但是不再是段的起始地址。段的起始地址放在内存的某个地方。这个地方是一个表格,表格中的一项一项是 段描述符(Segment Descriptor)。这里面才是真正的段的起始地址。而段寄存器里面保存的是在这个表格中的哪一项,称为 选择子(Selector)。

    这样,将一个从段寄存器直接拿到的段起始地址,就变成了 先间接地从段寄存器找到表格中的一项,再从表格中的一项中拿到段起始地址

    因而到了 32 位的系统架构下,我们将前一种模式称为 实模式(Real Pattern),后一种模式称为 保护模式(Protected Pattern)。当系统刚刚启动的时候,CPU 是处于实模式的,这个时候和原来的模式是兼容的。

  • 相关阅读:
    代码随想录Day_52打卡
    如何改进企业旧式工时管理系统?
    【英语思考】How to think in English: Building Your English Brain
    如何计算质心
    high perfermance computer usage
    LSTM缓解梯度消失问题
    《程序员延寿指南》登GitHub热榜,最多可增寿20年?
    java基础 韩顺平老师的 面向对象(高级) 自己记的部分笔记
    Java即时通讯源码 IM即时通讯系统源码
    一题带你写出图论算法模板!!!
  • 原文地址:https://blog.csdn.net/weixin_41960890/article/details/127695697