第五章------链接
一.编译器组成
1.是由 预处理器 、语法和语义检查器 、代码生成器 、汇编程序、优化器、链接器,还包括一个调用所有这些程序并向各个程序传递正确选项的驱动器程序。
2.链接器:编译器创建一个输出文件,这个文件包含了可重定位的对象,这些对象就是与源程序相应的数据和机器指令。
3.目标文件并不能直接执行,它首先需要载入到链接器中。
链接器确认main函数为初始进入点(程序开始执行的地方),把符号引用绑定到内存地址,把所有的目标文件集中在一起,再加上库文件,从而产生可执行文件。
4.链接分为动态和静态两种:
静态链接:函数库的一份拷贝是可执行文件的物理组成部分
动态链接:如果可执行文件只是包含了文件名,让载入器在运行时能够寻找程序所需要的函数库
二、动态链接
1.动态链接的优点:可执行文件的体积非常小,虽然运行速度缓慢,但它可以更加有效的利用磁盘空间,而且链接-编辑阶段时间会缩短;
2.目的:为了把程序和它们使用的特定的函数库版本中分离出来。
—约定由系统向程序提供一个接口,该接口保持稳定,不随时间和操作系统的后续版本变化而变化。
—并且程序可以调用接口所承诺的服务,它是介于应用程序和函数库二进制的可执行文件提供的服务之间的接口,简称应用程序二进制接口
3.从两方面提高性能:
(1)可执行文件的体积比功能相同的静态链接小,它可以更加有效的利用磁盘空间和虚拟内存,因为函数库只有在需要时才会被映射到进程中去,避免了内核爆炸。
(2)所有动态链接到某个特定函数库的可执行文件在运行时共享该函数库的一个单独拷贝,而不是像静态链接每个文件都拥有一份函数库的拷贝,非常浪费!
4.动态链接选择函数库
(1)动态链接运行用户在运行时可以选择需要执行的函数库,为了提高速度或内存使用效率或包含调试功能而创建新版本的函数库都是有可能的,可以根据自己的喜欢,在程序执行时用一个库文件取代另一个库文件。
(2)动态链接是一种“just-in-time”链接,意味着程序在运行时必须能够找到它们所需要的函数库,所以文件路径非常重要,即使是移植,也要保证函数库的文件路径一致!
三、函数库链接的五个特殊秘密
1.动态库文件的拓展名是“.so”,而静态文件的拓展名是".a"。
2.例如,你通过-lthread选项,告诉编译链接到libthread.so。
—传给编译器的命令行参数并没与提到函数库的完整路径名,甚至是函数库目录该文件的完整名字都没有!
3.编译器期望在确定的目录找到库
4.观察头文件,确认所使用的函数库。
—可以观察程序所使用的#include 指令,每个头文件都可能代表一个必须链接的库
—但是,函数库包含许多函数的定义,可这些函数的原型声明却散布在多个头文件中
5.与提取动态库中的符号相比,静态库中的符号提取方法限制更严
(1)动态链接中,所有库符号进入输出文件的虚拟地址空间中,所有的符号对于链接在一起的所有文件都是可见的;
(2)静态链接中,在处理archive时,它只是在archive中查找载入器当时所知道的未定义符号。(共享archive的问价是一个过渡形式,从静态转变成动态)
四、警惕:Interpositioning
1.含义:通过编写与库函数同名的函数来取代库函数的行为,但需要格外小心,很容易发生自己代码中某个符号的定义取代函数库中的相同符号的意外。
2.tips:不要让任何符号成为全局的,除非有意把它们作为程序接口之一,而且标识符还需要避免使用库里规定的标识符,也就是关键字。