当前位置:首页 > 单片机 > 架构师社区
[导读]计算机如何执行你写的代码?知乎上有人提问:电脑怎样执行编程语言的?很多刚刚入坑的小白可能对此完全没有概念,或者模模糊糊知道个大概,我们写下的一行行代码,计算机到底是如何在执行的呢?我们以x86架构的CPU为研究对象,从一个例子出发,来尝试解答这个问题。1、高级语言为了方便编程,伟...

计算机如何执行你写的代码

知乎上有人提问:电脑怎样执行编程语言的?

一行代码,揭开CPU执行原理!
很多刚刚入坑的小白可能对此完全没有概念,或者模模糊糊知道个大概,我们写下的一行行代码,计算机到底是如何在执行的呢?

我们以x86架构的CPU为研究对象,从一个例子出发,来尝试解答这个问题。

1、高级语言

为了方便编程,伟大的计算机先驱们发明了一个又一个的编程语言,使得我们可以用人类最容易理解的语法规则去告诉计算机完成我们想要的功能。

比如,一个C语言程序员写下了一行代码:

int sum = a   b;
一句简单的不能再简单的C语言语句。

但即便是如此简单,聪明绝顶的计算机却还是看不懂:这是弄啥捏?

这时候就需要一个翻译,负责把人类编写的高级语言“翻译”成计算机能看得懂的东西,这个翻译就是编译器

2、编译链接

上面的高级语言语句经过编译器编译链接后,生成了一个目标运行平台为x86架构的可执行程序exe/elf,使用反编译工具IDA进行分析,可以看到这行代码编译后的样子是这样的:

一行代码,揭开CPU执行原理!
mov eax, a    : 将变量a的值存入eax寄存器中

add eax, b    : 把变量b的值和eax寄存器的值相加,并将结果保存在eax寄存器中

mov sum, eax  : 将计算结果从eax寄存器写入sum变量

看到了吗,就像把大象关进冰箱需要分三步,计算机完成程序员的一条加法语句,也分了三步:取出被加数、加上加数、写入结果。

3、机器指令

上面的汇编指令只是为了人类理解方便的助记符,计算机同样也不认识这玩意,那几条指令在内存中实际上是这样的一串数据:

十六进制:

8B 45 EC 03 45 E0 89 45 F8

十六进制是为了书写方便,计算机真正能看到的只有二进制的比特流:

10001011 01000101 11101100 00000011 01000101 11100000 10001001 01000101 11111000

接下来,计算机要做的事情就是识别这些二进制流都是什么意思,转换成一条条的指令来执行。

在开始执行之前,先来了解一下指令格式。

4、指令格式

x86架构CPU指令集中的指令格式如下:

一行代码,揭开CPU执行原理!
主要有六个部分:

  • [非必需] 指令前缀:我们经常用到的原子操作指令前面有一个lock前缀,就属于指令前缀。
  • [必需] 操作码:指令最核心的部分,标识这条指令是什么功能。
  • [非必需] ModR/M:内存/寄存器操作数字节
  • [非必需] SIB:索引寻址描述字节
  • [非必需] Displacement:常数偏移字节/半字/字
  • [非必需] Immediate:立即数字节/半字/字
需要注意的是,并不是每一条指令都包含上面的所有部分,许多指令只包含其中一部分字段。

根据操作码的长度不同,指令分为单字节操作码指令双字节操作码指令三字节操作码指令

5、执行指令

计算机中真正负责指令执行的核心部件是中央处理器CPU,在CPU中有一个指令寄存器IP,全称是Instruction Pointer,在32位下,它叫EIP,在64位下它叫RIP

下面开始执行:

指令寄存器EIP指向了第一条指令,开始读取第一个字节:10001011,也就是0x8B。

开始指令译码,翻译出这是一条什么指令。

下面是x86架构的CPU指令操作码表:

一行代码,揭开CPU执行原理!
CPU中的指令译码模块拿到手一看,呀,不是指令前缀,是个单字节操作码的mov指令,要往eax寄存器里面塞数据,数据从哪来呢?

再往后一看,0x45,再来译码:

一行代码,揭开CPU执行原理!
好家伙,原来是根据ebp寄存器的值 一个8位的偏移来读取数据。

再往后读取一个字节,就是偏移值:EC。

现在第一条指令就译码出来了:将ebp 0xEC位置处的4个字节的数据取出来,放到eax寄存器中。,这就是这一条指令要干的事情。

同时CPU还得出了另一个信息:这一条指令长度是3个字节,下一条指令的起始地址是在3个字节之后,随后,指令寄存器EIP向后拨动,指向下一条指令的地址:$ 3。

指令译码完成之后,开始来正式执行它。

执行完一条以后,又来到指令寄存器EIP指向的地方,随后再次指令译码、执行,不断重复这个过程,依次执行每一条指令。

这其实就是CPU工作最基本的原理。

拓展

上面描述的过程是CPU在硬件电路层面完成的,但这种设计思想在软件领域也同样适用。

大家如果去研究Java虚拟机JVM和Python的解释器源代码时,也会发现有相似之处:JVM和解释器通过定义一套自己的“指令集”,然后它们的编译器使用这套指令集将Java和Python代码编译成对应的程序。

运行的时候也类似,虚拟机或者解释器不断识别每一条指令,译码、执行,和CPU执行指令的过程颇有几分相似。

一行代码,揭开CPU执行原理!
C/C 语言编译的程序,最后是直接编译成了CPU的指令,所以跨平台能力差,如果换到ARM架构平台,原来的程序将无法执行,需要重新编译成新的平台的程序。

而Java、Python这类语言,是自己在软件层面的指令集,因为其自身已经开发了针对不同CPU平台的虚拟机、解释器,所以这些语言编写的程序移植性好,真正做到一次编写,到处运行。

总结

我们使用高级语言C、C 编写的程序代码,经过编译器的编译链接,最终变成CPU可以理解的机器指令,随后CPU在执行时通过不断的译码、执行,最终实现高级语言所描述的功能。

现在你知道你用编程语言写下的程序是如何跑起来的了吗?

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭