计算机工作原理(一)编译和链接

对于平常的应用程序开发,我们很少需要关注编译和链接过程,因为通常的开发环境都是流行的集成开发环境(IDE),这样的IDE一般都将编译和链接的过程一步完成,通常将这种编译和链接合并到一起的过程称为构建(Build)。

一、那些被隐藏了的过程

当我们运行一个程序的之前,通常要经过4个步骤,分别是:

1、预处理(Prepressing)

2、编译(Compilation)

3、汇编(Assembly)

4、链接(Linking)

(一)预处理

预处理又称预编译,预编译过程主要处理那些源代码文件中的以"#"开始的预编译指令。比如#include#define等,主要处理规则如下:

  • 将所有的#define删除,并且展开所有宏定义。
  • 处理所有条件预编译指令,比如#if#ifdef#elif#else#endif
  • 处理#include预编译指令,将被包含的文件插入到该预编译指令的位置。注意,这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。
  • 删除所有的注释。
  • 添加行号和文件名标识,以便于编译时编译期产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号。
  • 保留所有的#pragma编译器指令,因为编译器须要使用它们。

经过预编译后的文件(.i文件)不包含任何宏定义,因为所有的宏已经被展开,并且包含的文件也已经插入到.i文件中,所以当我们无法判断宏定义是否正确或头文件包含是否正确时,可以查看预编译后的文件来确定问题。

(二)编译

编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生产相应的汇编代码文件,这个过程往往是我们所说的整个程序构建的核心部分。

(三)汇编

汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。所以汇编器的汇编过程相对于编译器来说比较简单,它没有复杂的语法,也没有语义,也不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译就可以了。

(四)链接

链接通常是一个让人比较费解的过程,为什么汇编器不直接输出可执行文件而是输出一个目标文件呢?链接过程到底包含了什么内容?为什么要链接?这是很多人的疑惑,所以我们会在本篇文章具体的分析静态链接。

二、编译器做了什么

从最直观的角度来讲,编译器就是将高级语言翻译成机器语言的一个工具。编译过程一般可以分为6步:扫描、语法分析、语义分析、源代码优化、代码生成和目标代码优化。

我们将结合这个过程来简单描述从源代码到最终目标代码的过程,以一段很简单的C语言的代码为例子来讲述这个过程,比如我们有一行C语言的源代码如下:

array[index] = (index + 4) * (2 + 6)

(一)词法分析

首先,源代码程序被输入到扫描器,通过特定算法轻松地将源代码的字符序列分割成一系列的记号。比如上面的那行代码,总共包含了28个非空字符,经过扫描以后,产生了16个记号,比如:

记号 类型
array 标识符
[ 左方括号
index 标识符
] 右方括号

(二)语法分析

接下来的语法分析器将对由扫描器产生的记号进行语法分析,从而产生语法树。简单的讲,由语法分析器生成的语法树就是以表达式为结点的树,我们知道。C语言的一个语句是一个表达式,而复杂的语句是很多表达式的组合。上面例子中的语句就是一个由赋值表达式、加法表达式、乘法表达式、数组表达式、括号表达式组成的复杂语句。

(三)语义分析

(四)中间语言生成

现代的编译期有着很多层次的优化,往往在源代码级别会有一个优化过程。我们这里所描述的源码级优化器在不同编译器中可能会有不同的定义活有一些其他的差异。源代码级优化器会在源代码级别进行优化,在上面那段代码中,(2+6)这个表达式可以被优化掉,因为它的值在编译期就可以被确定。

(五)目标代码生成与优化

源代码优化器产生中间代码标志着下面的过程都属于编译器后端。编译器后端主要包括代码生成器和目标代码优化器。

代码生成器:将中间代码转换成目标机器代码。

目标代码优化器:对上述的目标代码进行优化,比如选择合适的寻址方式、使用位移来代替乘法运算、删除多余的指令等。

经过这些扫描、语法分析、语义分析、源代码优化、代码生成和目标代码优化,编译器忙活了这么多个步骤以后,源代码终于被编译成了目标代码,但是这个目标代码中有一个问题是:index和array的地址还没有确定。如果我们要把目标代码使用汇编器编译成真正能够在机器上执行的指令,那么index和array的地址应该从哪得到呢?如果index和array定义在跟上面的源代码同一个编译单元里面,那么编译器可以为index和array分配空间,确定他们的地址,那如果是定义在其他的程序模块呢?

这个问题就涉及到了链接的过程。

三、链接器年龄比编译期长

我们都知道,上古时期没有高级语言,用的都是机器语言,甚至连汇编语言都没有,当程序需要被运行时,程序员人工将他所写的程序写入到存储设备上,最原始的存储设备就是纸带,即在纸带上打孔。

假设有一种计算机,它的每条指令是1个字节,也就是8位,我们假设有一种跳转指令,它的高4位是0001,表示这是一条跳转指令,低4位存放的是跳转目的地的绝对地址。当程序修改的时候,这些位置都要重新计算,绝对地址都会改变,重新计算的过程十分繁琐又耗时,并且很容易出错,这种重新计算各个目标的地址过程被叫做重定位。

四、模块拼装 - 静态链接

程序设计的模块化是人们一直在追求的目标,因为当一个系统十分复杂的时候,我们不得不将一个复杂的系统逐步分割成小的系统以达到各个突破的目的。一个复杂的软件也如此。人们把每个源代码模块独立地编译,然后按照须要将他们“组装”起来,这个组装模块的过程就是链接。链接的主要内容就是把各个模块之间相互引用的部分都处理好,使得各个模块之间能够正确的衔接。链接器所要做的工作其实跟前面所描述的“程序员人工调整地址”本质上没什么两样,只不过现代的高级语言的诸多特性和功能,使得编译器、链接器更为复杂,功能更为强大,但从原理上讲,它的工作无非就是把一些指令对其他符号地址的引用加以修正。链接过程主要包括了地址和空间分配、符号决议和重定位等这些步骤。

对于最基本的静态链接过程,每个模块的源代码文件经过编译器编译成目标文件(Object File,一般扩展名为.o活.obj),目标文件和库(Library)一起链接形成最终可执行文件。而最常见的库就是运行时库(Runtime Library),它是支持程序运行的基本函数的集合。库其实是一组目标文件的包,就是一些最常用的代码编译成目标文件后打包存放。

比如我们在程序模块main.c中使用另外一个func.c中的函数foo(),我们在main.c模块中每一处调用foo的时候都必须确切知道foo这个函数的地址,但是由于每个模块都是单独编译的,在编译器编译main.c的时候它并不知道foo函数的地址,所以它暂时把这些调用foo的指令的目标地址搁置,等待最后链接的时候由链接器去将这些指令的目标地址修正,这个地址修正的过程也被叫做重定位,每个要被修正的地方叫一个重定位入口,重定位所做的就是给程序中每个这样的绝对地址引用的位置“打补丁”,使他们指向正确的地址。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容