上一篇 计算机基础(一):面向CPU编程 介绍了计算机的起源,以及CPU的主要结构,并引入了 ISA 的概念。本篇继续总结计算机基础相关的内容。
我们知道了ISA是定义了面向CPU编程的 0、1 组合起来的指令规则,最开始人们就是这样按照 ISA 指令集中的定义来编写成语,但这样由0和1组合起来的指令编写、维护起来并不容易,一旦出错也很难定位问题,因此,人们发明了一种使用助记符来编写指令的方式,即:汇编语言。继而后期,又在汇编语言的基础上抽象出了C语言、及其他众多的语言。这就是后话了。
汇编语言其实并没有什么高深的,它是一门与 ISA 指令集一一对应的产物,只是通过对人类更加友好的助记符来进行编写和维护,CPU其实还是识别的ISA指令,执行的还是二进制。那么,也就是说,汇编语言必须转换为 ISA指令 后,才能被 CPU 执行。谁来做这个转换的工作呢?它就是汇编器!
汇编语言的最终作用,其实也和 ISA 一样,抽象机器语言,操作CPU,去控制其他硬件完成操作。具体来说:操作CPU的控制单元,控制存储单元、运算单元去对来自缓存的数据进行CRUD操作。
上一篇在介绍ISA时提到,指令是由操作码和操作数构成,操作码定义了这个指令要干什么,操作数指明当前指令参与操作的东西(立即数、寄存器、内存中的值等等),汇编语言中的指令其实也类似,只不过,将二进制转换为了更加友好一些的助记符,比如:
具体这些指令的使用说明哪里有定义呢?它是由 CPU 厂家进行的定义,那我们常用的 Intel 公司的 CPU 来说,他们提供了其汇编指令的定义,具体是在 Intel 开发手册(下载地址 )查看。
Intel开发手册包含很多信息,不只是汇编指令的说明。手册总共分为4卷,采用总分结构:
可以看到,想系统了解底层 CPU 硬件提供的支持,可以详细查看该手册,第一卷、第二卷介绍一些原理、基础方面的内容,第二卷就是对具体指令的索引说明,第四卷是对特定寄存器的说明,因此可以把 2、4 卷看作是字典来查即可。比如我们要查看 mov 汇编指令的描述,直接定位到第二卷的 4.2 节即可。
我们知道了CPU执行指令的基本底层原理(通过 汇编指令/ISA 控制CPU中的控制器,继而控制其他组件),而接下来了解下 CPU 运行时的数据来源:内存。
以上总结起来,就是下面这张内存结构的示意图:
栈内存的实现有两种方式,一种是连续内存、一种是不连续的内存,我们这里讨论连续内存的情况。
我们知道了栈内存空间,是为了指令动态执行时分配私有数据用的,而指令嵌套执行时,只能访问当前指令段自己的私有空间,仅此将栈内存进一步的进行了划分,栈的一片空间里,保存了自己指令段的私有数据的区域,叫做:栈帧。
指令片段通过 call、ret 指令调用、退出其他指令段时,也就意味着栈帧在栈空间的入栈、出栈操作。比如,当指令段A调用指令段B,指令段B调用指令段C的时候,整体的栈帧结构示意图如下:
之所以叫示意图,是因为它并不是十分准确,因为要实现栈的操作,我们还需要搭配 CPU 的寄存器。CPU中有两个专门的寄存器,分别指向当前执行栈结构中的栈底和栈顶,这两个足够必要,因为我们要动态开辟、回收栈空间,必须依赖这两个寄存器中保存的内存地址。(哦,对了,之前我们还没有引入过内存地址。要想访问某个内存,肯定也是需要对我们的内存进行编码的嘛,给每一个内存单元一个地址,我们的CPU才能访问得到呀。)
说回栈底和栈顶寄存器,保存了当前指令片段栈帧中的地址,最初始时的状态是这样:
通过移动栈顶寄存器,实现动态分配、回收栈中的数据。
当代 码段A 调用 代码段B 的时候呢,就需要开辟一个新的栈帧了,这时候A的栈顶、栈底是不是也得需要保存一下呢??(换一组寄存器保存?那寄存器肯定不够用嘛,我们还得复用这两个寄存器)实际只需要保存栈底空间即可,因为A的栈顶我们可以通过 代码段B 的栈底自动识别到。因此在为代码段B开辟新的栈帧的时候,需要将A的栈底地址保存一下,然后将栈底寄存器更新为B的栈底寄存器:
随着代码段B的执行,栈帧不断扩展,栈顶寄存器向上移动开辟空间,当调用代码段C的时候,也是类似的,会开辟新的栈帧,因此,实际的示意图如下:
嵌套代码段退出时,类似的,弹出栈帧,弹出保存着的上一级的栈底地址,更新栈底寄存器,继续执行。以上,便是指令片段执行时,栈空间操作的基本流程。
CPU与内存的交互,通过总线(计算机组成原理)传递信息来实现,总线分为三类:控制总线(CB)、地址总线(AB)、数据总线(DB)
地址总线:决定了处理器将从内存中读取数据或写入数据的内存位置。
数据总线:包含已从内存位置读取或将写入内存位置的数据内容。
控制总线:管理组件之间的信息流,指示操作是读取还是写入,并确保操作在正确的时间发生。
寄存器主要分为两大类:专用寄存器、通用寄存器。专用寄存器只能用于其特有的功能,比如上面我们提到的栈底寄存器、栈顶寄存器;通用寄存器除了用于自己特有表明的功能外,还可以用作其他用途。
本篇总结了汇编语言的出现、计算机运行时的内存结构划分,以及总结了栈内存空间在程序运行时的示意图。