《程序员的自我修养》第二章 编译和链接

正文

第二章主要介绍了编译的具体步骤、汇编以及链接这一步骤的由来与作用。

2.1 被隐藏了的过程

计算机的 IDE 将编译和链接合并成一步,称为构建(Build)。分别介绍了构建的四个步骤:预处理编译汇编链接

  • 预处理:主要处理代码中,以“#”开始的预编译指令,如“#include”,“#define”等。展开宏定义,处理条件预编译指令,删除注释,保留 #pragma(因为编译器需要使用),递归引入文件(#include)。
  • 编译:将预处理完的文件,经过词法分析、语法分析、语义分析、代码优化后产出汇编代码。
  • 汇编:将汇编代码转换成机器可以执行的指令,输出目标文件。这个过程相对比较简单。因为汇编代码和机器指令是一一对应,翻译即可。
  • 链接:将多个目标文件链接起来,输出可执行文件。

2.2 编译器做了什么

编译器的作用包括:

  • 让开发者不用依赖于某个特定平台,使用机器指令或者汇编代码从事开发工作,而是使用更高级更通用的语言进行开发。
  • 高级语言让开发者更加关注程序的逻辑本身,而不用考虑计算机限制,开发效率和可移植性更高。

编译器的各个步骤介绍:


比如我们有一行 C 语言代码如下:

array[index] = (index + 4) * (2 + 6)
  • 词法分析:将源代码输入到扫描器当中,根据一种有限状态机的算法,将代码分割成一系列的记号(Token)。记号可分为:关键字、标识符、字面量(数字、字符串)、特殊符号(如加号、等号)。
  • 语法分析语法分析器扫描器输出的一系列记号,处理生成以表达式为节点的语法抽象树。
  • 语义分析语义分析器根据静态语义,将整个语法抽象树上的表达式都赋予类型。如类型和声明的匹配、类型的隐式转换,都在这一步完成。
  • 中间语言生成:将语法抽象树,转化为中间代码。代码会有多个层次的优化,源码级优化器负责在源码上实现优化,比如将2 + 6 直接简化为确定的8。常用的中间代码有三地址码,其形式为 z = x op y。

到这一步为止,属于编译器前端干的事情。编译器前端负责产生与机器无关的中间代码。而编译器后端将中间代码转换成目标机器代码。

  • 目标代码生成与优化:包括了代码生成器目标代码优化器代码生成器负责将中间代码生成特定的由目标机器类型决定的目标代码。目标代码优化器负责在目标代码层面进行优化,包括了:选择合适的寻址方式,使用位移来代替乘法运算、删除多余指令等。

疑问:index 和 array 的地址还没有确定。如果要把目标代码通过汇编器转换为在机器上可以执行的指令,我们从哪里获得 index 和 array 的地址呢?如果 index 和 array 定义在跟上面源代码同一个编译单元时,可以由编译器为 index 和 array 分配空间。可如果没有在同一个编译单元时呢?

2.3 链接器年龄比编译器长

机器语言时代


假设有一种计算机,它的每条指令为1个字节,也就是8位。假设有一种跳转指令,高4位是0001,表示这是一条跳转指令,低4位存放的是跳转目的地的绝对地址。如上图,可以看出程序中的第1条指令会跳转到第5条指令。问题在于,程序不是不是一成不变的,如果在第5条指令之前,新插入一条语句,程序员就需要重新计算所有在新插入语句后的语句位置。这个过程称为重定位。对于程序员来说,这个过程实在太过于繁琐,必须想一个办法解决。

汇编语言:引入符号的概念,利用符号来指代指令和地址。避免人工的重定位工作,由计算机来搞定。“jmp”指代跳转命令,“foo”指代第五条指令。那么就可以把第一条指令修改为非常简洁易懂的

jmp foo

随着代码规模的增加,代码模块化就显得非常有必要了。但是划分完以后,各个模块之间如何通信又成了一个问题。
链接:模块间的符号引用可以解决这个问题。类似于模块的拼接。

2.4 模块拼装——静态链接

链接的主要工作:把各个模块相互引用的部分都处理好,使得每个模块能够正确地衔接。
链接过程包括:地址和空间分配、符号决议、重定位。


如上图,每个模块的源代码文件经过编译器和汇编器生成目标文件,目标文件和库链接在一起,形成可执行文件。最常见的库是运行时库,它是支持程序运行的基本函数的集合。

最后讲讲是如何修正这些在其他模块的变量和函数的地址的?
比如我们在程序模块 main.c 引用了另一个模块 fun.c 中的函数 foo()。在单独编译过程中,main.c 模块无法确切知道 foo() 指令的目标地址,先暂行搁置。等到最后的链接过程中,链接器负责寻找foo() 的目标地址,并进行修正。

结束

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

推荐阅读更多精彩内容