前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CPU是如何运行程序的

CPU是如何运行程序的

作者头像
前端柒八九
发布2022-08-25 14:10:42
1.4K0
发布2022-08-25 14:10:42
举报
文章被收录于专栏:柒八九技术收纳盒

一语中的

  1. CPU = 运算单元 + 数据单元 + 控制单元
  2. CPU 只能识别「二进制」的指令
  3. 总线像连接 CPU 和内存这两个设备的高速公路
  4. 执行高级语言的两种方式:1. 解释执行 2. 编译执行
  5. 汇编语言和机器语言是一一对应的
  6. 内存中的每个存储空间都有其对应的独一无二的地址
  7. CPU时钟周期:取出指令、分析指令、执行指令这三个过程

文章概要

  • 计算机工作模式
  • CPU和内存如何配合工作的
  • 机器语言/汇编语言/高级语言
  • CPU如何执行程序

计算机工作模式

对于计算机来讲,最核心的就是「CPU」(Central Processing Unit,中央处理器)

CPU 和其他设备连接,要靠一种叫作「总线」(Bus)的东西,其实就是主板上密密麻麻的集成电路,这些东西组成了 CPU 和其他设备的高速通道。

在这些设备中,最重要的是「内存」(Memory)。因为单靠 CPU 是没办法完成计算任务的,很多复杂的计算任务都需要将中间结果保存下来,然后基于中间结果进行进一步的计算。CPU 本身没办法保存这么多中间结果,这就要依赖内存了。

总线上还有一些其他设备,例如显卡会连接显示器、磁盘控制器会连接硬盘、USB 控制器会连接键盘和鼠标等等。

CPU和内存如何配合工作的

CPU:包括三个部分,运算单元、数据单元和控制单元。

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

每个程序都有一个「项目执行计划书」,里面是一行行程序执行的指令。每个进程都有一个程序放在硬盘上,是「二进制」的,再里面就是一行行的指令,会操作一些数据。

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

程序运行的过程中要操作的数据和产生的计算结果,都会放在数据段里面。

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

机器语言/汇编语言/高级语言

机器语言

把 CPU 看成是一个非常小的运算机器,为了能够完成复杂的任务,为 CPU 提供了一大堆指令来实现各种功能,这一大堆指令称为指令集(Instructions)。也就是「机器语言」

❝CPU 只能识别二进制的指令 ❞

汇编语言

但是,二进制代码难以阅读和记忆,又将二进制指令集转换为人类可以识别和记忆的符号 -- 「汇编指令集」

代码语言:javascript
复制
1000100111011000  机器指令
mov ax,bx         汇编指令

CPU 不能直接识别汇编语言,还需要一个「汇编编译器」,其作用是将汇编代码编程成机器代码。

「汇编语言的弊端」

  • 不同的 CPU 有着不同的指令集
  • 需要了解和处理器架构相关的硬件知识

高级语言

所以, 诸如 C、C++、Java、C#、Python、JavaScript 等高级语言应用而生。

和汇编语言一样,CPU也不能直接识别由高级语言所编写的代码。

根据对高级语言转换的过程中是否生成「机器代码」,把执行高级语言分为

  1. 解释执行
  2. 编译执行

解释执行

先将源代码通过解析器编译成中间代码,之后「直接」使用解释器解释执行中间代码,然后「直接输出结果」

并不把整个程序 变成目标码,而是按顺序,读一句,解释一句,执行一句,所以,没给完整程序,它就可以执行了。

例如,浏览器处理网页,网页程序,每下来一句,就可以解释执行一句,不用等整个网页下来后再处理。

编译执行

先将源代码通过「解析器」编译成中间代码,编译器再将中间代码编译成「机器代码」(编译成的机器代码以二进制文件形式存储), 执行这段程序的时候直接执行二进制文件。

必须给出完整程序,编译器通过几次扫描,翻译,编排,链接,变成exe文件执行。

CPU如何执行程序

我们通过针对一段C代码,进行编译执行,来看看CPU是如何执行程序的。(像JS这种解释执行,有另外一套逻辑和实现方式,后期会有介绍)

代码语言:javascript
复制
// test.c
int main (void)
{
   int x =1;
   int y = 2;
   int z = x + y;
   return z;
}

CPU 并不能直接执行这段 C 代码,需要对其进行编译,将其转换为二进制的机器码, CPU 才能按照顺序执行编译后的机器码。

通过 GCC 编译器将 C 代码编译成二进制文件。gcc -O0 -o code_prog test.c。(在Mac环境下,可以通过brew[1]来进行gcc[2]的下载) 随后, 文件夹中生成名为 code_prog 的「可执行程序」

通过objdump将编译出来的 code_prog 程序进行反汇编。objdump -d code_prog

  • 左边就是编译生成的机器码,每一行其实都是一个指令,该指令可以让 CPU 执行指定的任务
  • 中间的部分是汇编代码, 汇编代码采用助记符(memonic)来编写程序,原本是二进制表示的指令,在汇编代码中可以使用单词来表示。「汇编语言和机器语言是一一对应的」

编译后的程序是由一堆二进制代码组成的(二进制代码是由一条条指令构成的)

准备工作

在程序执行之前,程序需要被「装进内存」。CPU 可以通过指定内存地址,从内存中读取数据,或者往内存中写入数据。(内存是一个临时存储数据的设备, 因为断电之后,内存中的数据都会消失)

「内存中的每个存储空间都有其对应的独一无二的地址」

在内存中,每个存放字节的空间都有其唯一的地址,而且地址是按照顺序排放的

代码被编译成可执行文件, 而可执行文件中包含了二进制的机器码。当二进制代码被加载进了内存后,内存中的每条「二进制代码」便都有了自己对应的地址。

CPU时钟周期

❝CPU时钟周期:取出指令、分析指令、执行指令这三个过程 ❞

CPU取指令

CPU 中有一个 PC 寄存器,它保存了将要执行的指令地址。当二进制代码被装载进了内存之后, 系统会将二进制代码中的第一条指令的地址写入到 PC 寄存器中。

到了下一个时钟周期时,CPU 便会根据 PC 寄存器中的地址,从内存中取出指令。

CPU分析指令

PC 寄存器中的指令取出来之后,将下一条指令的地址更新到 PC 寄存器中,并分析取出的指令。

CPU执行指令

取出的指令分两部分

  1. 一部分是做什么操作,例如是加法还是位移;
  2. 一部分是操作哪些数据。

要执行这条指令,就要把第一部分交给运算单元,第二部分交给数据单元。

数据单元根据数据的地址,从数据段里读到数据寄存器里,就可以参与运算了。运算单元做完运算,产生的结果会暂存在数据单元的数据寄存器里。最终,会有指令将数据写回内存中的数据段。

如此往复的对内存中的指令,进行取出、分析、执行。直到PC寄存器到达指令的最后。

参考资料:

  1. 趣谈Linux操作系统
  2. Google V8

Reference

[1]

brew: https://formulae.brew.sh/formula/gcc#default

[2]

gcc: https://gcc.gnu.org/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-01-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端柒八九 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一语中的
  • 文章概要
  • 计算机工作模式
  • CPU和内存如何配合工作的
  • 机器语言/汇编语言/高级语言
    • 机器语言
      • 汇编语言
        • 高级语言
          • 解释执行
          • 编译执行
      • CPU如何执行程序
        • 准备工作
          • CPU时钟周期
            • CPU取指令
            • CPU分析指令
            • CPU执行指令
            • Reference
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档