腾讯三面:源代码是怎样转化成进程的

307次阅读  |  发布于2年以前

你好,我是大白。前两篇文章讲解了[计算机是怎样工作的] 以及[操作系统具体做了什么] 。接下来的文章就要开始详细讲操作系统了。接下来会有多篇文章详细讲进程,进程是操作系统中十分重要的一个虚拟化产物,我们一起来详细学习下吧!之前从[系统调用的角度讲过怎样创建进程] ,今天我们来看看怎样把源代码转化成一个进程!

一个阳光明媚的中午,大白在领导办公室

‍ 大白:领导我......

‍ 领导:行行行,你哪疼快去看哪吧!

--------------------当日下午,腾讯大楼,面试开始--------------------

1为什么需要进程

‍ 面试官:这是第三轮面试了,前几轮问的差不多了,今天我想考查下你的基本功,我就想咱们详细的分析下从代码到进程要经过哪些步骤!你能先讲下我们为什么需要进程这个东西吗?

‍ 大白:好的,我在我上一篇写的系列文章中也提到过,大家都希望能同时在电脑上运行多个程序。比如看直播的同时也能开着微信聊天,还能同时看看邮件等等。但是我们知道,一个 CPU 在一瞬间只能同时处理一个运行着的程序,所以我们就需要通过虚拟化的技术来让操作系统用一个 CPU 营造出无数个 CPU 可用的假象。为了达到这个目的,我们首先要把运行着的程序进行抽象,把正在运行的程序抽象成所谓的进程。有利于后面的一系列操作。

2源代码转化为进程的步骤

‍ 面试官:不错,那你再讲下把源代码转化成一个进程一共需要哪几步吧?

‍ 大白:好的,程序转换为进程需要五个阶段,分别是预处理、编译、汇编、链接、装载。我下面画个图,看的更直观一些。这个流程都是以 Linux 系统和 C 语言为例的。

‍ 面试官:不错不错,那再讲下每个阶段分别再做什么吧!

‍ 大白:没问题,咱们一个个的看。

3目标文件的格式

‍ 面试官:打断一下,预处理和编译处理后的结果大家应该比较容易理解。第一步是一些代码的预处理,编译就是把 C 转化为汇编的代码。但是经过第三步处理后生成的 .o 目标文件是什么样我就不太清楚了。这里详细讲一下吧!

‍ 大白:好的!其实目标文件在不同的平台上是不一样的,比如在 Windows 上的目标文件为 .obj 文件,而在 Linux 上目标文件为 .o 文件,格式被称为 ELF(Executable and Linkable Format, 可执行与可链接格式)。

大家有兴趣可以按照我下面给出的命令看下。首先写一段 C 语言代码,可以命名成 dabai.c 。然后用 “gcc -c dabai.c” 编译下文件会生成一个同名的 .o 文件,然后用命令 “readelf -a dabai.o” 输出就可以看啦。

我把重要的部分在下面单拿出来讲下,.o 文件的结构长下面这样。

图仿极客时间《趣谈 Linux 操作系统》 https://time.geekbang.org/column/article/90855

具体各部分的表示为

.text:放编译好的二进制可执行文件

.data:已经初始化好的全局变量

.rodata:只读数据,例如字符串常量、const 的变量

.bass:未初始化全局变量,运行时会置为0

.symtab:符号表,记录的则是函数和变量

.strtab:字符串表、字符串常量和变量名

.rel.text:代码段重定位表,描述代码段中出现的函数、变量的引用地址信息等

.rel.data:数据段重定位表

4链接

‍ 面试官:好的,你接着说下链接是做什么的!

‍ 大白:好的,链接 需要把各个模块之间相互引用的部分处理好,使得各个模块之间能够正确衔接。比如代码文件 A.c 引用了代码文件 B.c 中的函数,在编译时对应生成的是 A.oB.o。那么 A.o 中的 .rel.textrel.data 就应该记录了引用信息。通过链接把多个人 .o 文件就合并成了.out 文件。这个 .out 文件和 .o 文件相似,也是采用 ELF 格式的,只不过是 ELF 文件的另一种格式。具体长下面这样。转化成下面这样后就可以往内存中加载了。

此图仿极客时间《趣谈 Linux 操作系统》 https://time.geekbang.org/column/article/90855

‍ 面试官:你刚才说的是静态链接的方法吧?他有什么优缺点呢?

‍ 大白:是的,上面采用的是静态链接的方法,静态链接库一旦链接进去就合并了,以后程序运行就不会依赖链接库了。但这样的缺点就是一段代码如果被多个程序使用,那么内存里面就会存在多份。所以就又出现了一种动态链接,具体做法是将一个动态链接库链接到一个程序文件中时,最后的程序文件并不包括动态链接库中代码,而仅仅包括对动态链接库的引用。动态链接我就不特别详细的展开讲了,细节有点不太熟。

‍ 面试官:好的,那你说下装载是在做什么吧!

‍ 大白:经过上面的一系列操作已经把代码转化为可执行文件了,把可执行文件 装载 到内存中就可以执行了。装载可执行文件并且执行需要做以下三件事:

  1. 创建一个独立的虚拟地址空间。
  2. 读取可执行文件头,并且建立虚拟空间与可执行文件的映射关系。
  3. 将 CPU 的指令寄存器设置成可执行文件的入口地址,启动执行。这里面自然又涉及到一系列的技术,今天时间不早了,我们以后再讲呀!

‍ 面试官:我是第一次遇见有人想主动加面的!

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8