最近有幸阅读了《高级C/C++编译技术》深受启发,该书深刻浅出地讲解了构建过程(编译、连接)中的各类细节,从多个角度展现了程序与库文件或代码的集成方法,提出了面向代码复用和系统集成的软件架构设计方法,以及系统开发过程当中疑难问题的解决方案。
如下将回头记录下其中的关键要点,以便后面查阅。
首先,须要理解加载域与运行域的概念。加载域是代码存放的地址,运行域是代码运行时的地址。为何会产生这2个概念?这2个概念的实质意义又是什么呢?linux
在一些场合,一些代码并不在储存这部分代码的地址上执行地址,好比说,放在norflash中的代码可能最终是放在RAM中运行,那么中norflash中的地址就是加载域,而在RAM中的地址就是运行域。架构
在汇编代码中咱们经常会看到一些跳转指令,好比说b、bl等,这些指令后面是一个相对地址而不是绝对地址,好比说b main,这个指令应该怎么理解呢?main这里到底是一个什么东西呢?这时候就须要涉及到连接地址的概念了,连接地址实际上就是连接器对代码中的变量名、函数名等东西进行一个地址的编排,赋予这些抽象的东西一个地址,而后在程序中访问这些变量名、函数名就是在访问一些地址。通常所说的连接地址都是指连接这些代码的起始地址,代码必须放在这个地址开始的地方才能够正常运行,不然的话当代码去访问、执行某个变量名、函数名对应地址上的代码时就会找不到,接着程序无疑就是跑飞。可是上面说的那个b main的情形有点特殊,b、bl等跳转指令并非一个绝对跳转指令,而是一个相对跳转指令,什么意思呢?就是说,这个main标签最后获得的只并非main被连接器编排后的绝对地址,而是main的绝对地址减去当前的这个指令的绝对地址所获得的值,也就是说b、bl访问到的是一个相对地址,不是绝对地址,所以,包括这个语句和main在内的代码段不管是否放在它的运行域这段代码都能正常运行。这就是所谓的位置无关代码。函数
由上面的论述能够得知,若是你的这段代码须要实现位置无关,那么你就不能使用绝对寻址指令,不然的话就是位置有关了。工具
静态库是经过编译器编译源代码文件并将生成的目标文件打包生成后的归档文件,咱们经过名为归档器(archiver)的工具来生成静态库spa
$ gcc -c first.c second.c 架构设计
$ ar rcs libstaticlib.a first.o second.o设计
ar工具还能够完成如下任务:xml
(1)从库文件中删除一个或多个目标文件blog
(2)从库文件中替换一个或多个目标文件接口
(3)从库文件中提取一个或多个目标文件
连接器将静态库的节拼接到客户二进制文件,当连接完成后,静态库的节将与客户二进制文件中的原有的目标文件节进行无缝连接,静态库中的符号成为客户二进制文件符号列表中的一部分,而且保留了其原有的可见性,静态库中的全局符号成为客户二进制文件的全局符号,一样地,静态库的局部符号也称为客户二进制文件的局部符号。
可是,当客户二进制文件是一个动态库时,上面的原则仍是不是同样呢?
动态库的设计原则规定只提供(即接口可见性)知足与外部通讯的接口,采用该设计原则最终会影响到静态库符号的可见性,静态库的符号不会做为全局可见的符号保留,而是会变成私有符号或被忽略(即动态库的符号表中没有这个静态库符号)
另一个很是重要的特性是:动态库可以彻底自主管理其局部符号,实际状况是会有许多动态库被加载到相同的进程中,一个动态库会包含与其它动态库具备相同名称的局部符号,而连接器可以避免命名的冲突。
(1)当连接一个静态库须要多个动态库时,可能不该该使用静态库,选择使用动态库可能会比较有利
(2)应该使用同一库的已存在的动态库版本
(3)若是你所实现的功能须要存在一个类的单个示例中,最好使用动态库
在linux下连接静态库须要遵循下列规则
(1)依次连接静态库,每次一个静态库
(2)连接静态库从传递给链接器的静态库列表的最后一个静态库开始(经过命令或者makefile),且会反方向逐个连接,直到列表中的第一个位置
(3)连接器会对静态库进行详细的检索,在全部的目标文件中,只有包含客户二进制文件实际所需符号的目标文件才会进行连接
因为这些特定的规则,咱们有时须要在传递给连接器的静态列表屡次添加同一个静态库,当一个静态库同时提供了多种彻底不一样的功能时,就会遇到这种屡次添加的状况
(1)使用打包工具(ar)来提取全部静态库中的目标文件
$ ar -x <static library>.a
执行该命令会把静态库中的目标文件集合提取到当前目录
(2)连接器使用提取出来的目标文件集合来构建动态库
在64位linux平台上使用静态库会遇到一个很是特殊的状况
(1)将静态库连接到可执行文件与在32位linux上进行操做没有任何区别
(2)可是,静态库连接到共享库则要求静态库须要用-fPIC或-mcmodel-large编译器选项来进行构建(编译器在编译过程当中的错误打印输出时的建议)
静态库的导入选择条件:当客户端二进制文件连接静态库时不会把整个静态库的内容连接进来,智慧连接目标文件中必要的符号
动态库的导入选择条件:当客户端二进制文件连接动态库时,选择的条件是在符号表这个层面上,只会选择包含在符号表中实际须要的动态库符号,可是在其它全部方面,这个选择条件其实是不存在的,不管动态库功能中具体须要的代码有多少都会将整个动态库连接进来。