高级C/C++编译技术之读书笔记(二)之库的概念

最近有幸阅读了《高级C/C++编译技术》深受启发,该书深入浅出地讲解了构建过程(编译、链接)中的各种细节,从多个角度展示了程序与库文件或代码的集成方法,提出了面向代码复用和系统集成的软件架构设计方法,以及系统开发过程中疑难问题的解决方案。
以下将回头记录下其中的关键要点,以便后面查阅。
本节思维导图

1. 位置无关代码(PIC)
首先,需要理解加载域与运行域的概念。加载域是代码存放的地址,运行域是代码运行时的地址。为什么会产生这2个概念?这2个概念的实质意义又是什么呢?
在一些场合,一些代码并不在储存这部分代码的地址上执行地址,比如说,放在norflash中的代码可能最终是放在RAM中运行,那么中norflash中的地址就是加载域,而在RAM中的地址就是运行域。
在汇编代码中我们常常会看到一些跳转指令,比如说b、bl等,这些指令后面是一个相对地址而不是绝对地址,比如说b main,这个指令应该怎么理解呢?main这里究竟是一个什么东西呢?这时候就需要涉及到链接地址的概念了,链接地址实际上就是链接器对代码中的变量名、函数名等东西进行一个地址的编排,赋予这些抽象的东西一个地址,然后在程序中访问这些变量名、函数名就是在访问一些地址。一般所说的链接地址都是指链接这些代码的起始地址,代码必须放在这个地址开始的地方才可以正常运行,否则的话当代码去访问、执行某个变量名、函数名对应地址上的代码时就会找不到,接着程序无疑就是跑飞。但是上面说的那个b main的情形有点特殊,b、bl等跳转指令并不是一个绝对跳转指令,而是一个相对跳转指令,什么意思呢?就是说,这个main标签最后得到的只并不是main被链接器编排后的绝对地址,而是main的绝对地址减去当前的这个指令的绝对地址所得到的值,也就是说b、bl访问到的是一个相对地址,不是绝对地址,因此,包括这个语句和main在内的代码段无论是否放在它的运行域这段代码都能正常运行。这就是所谓的位置无关代码。
由上面的论述可以得知,如果你的这段代码需要实现位置无关,那么你就不能使用绝对寻址指令,否则的话就是位置有关了。
2. 静态库的创建
静态库是通过编译器编译源代码文件并将生成的目标文件打包生成后的归档文件,我们通过名为归档器(archiver)的工具来生成静态库
$ gcc -c first.c second.c
$ ar rcs libstaticlib.a first.o second.o
ar工具还可以完成以下任务:
(1)从库文件中删除一个或多个目标文件
(2)从库文件中替换一个或多个目标文件
(3)从库文件中提取一个或多个目标文件
3. 丢失符号可见性和唯一性的可能性
链接器将静态库的节拼接到客户二进制文件,当链接完成后,静态库的节将与客户二进制文件中的原有的目标文件节进行无缝链接,静态库中的符号成为客户二进制文件符号列表中的一部分,并且保留了其原有的可见性,静态库中的全局符号成为客户二进制文件的全局符号,同样地,静态库的局部符号也称为客户二进制文件的局部符号。
但是,当客户二进制文件是一个动态库时,上面的原则还是不是一样呢?
动态库的设计原则规定只提供(即接口可见性)满足与外部通信的接口,采用该设计原则最终会影响到静态库符号的可见性,静态库的符号不会作为全局可见的符号保留,而是会变成私有符号或被忽略(即动态库的符号表中没有这个静态库符号)
另外一个非常重要的特性是:动态库能够完全自主管理其局部符号,实际情况是会有许多动态库被加载到相同的进程中,一个动态库会包含与其它动态库具有相同名称的局部符号,而链接器能够避免命名的冲突。
4. 静态库使用禁忌
(1)当链接一个静态库需要多个动态库时,可能不应该使用静态库,选择使用动态库可能会比较有利
(2)应该使用同一库的已存在的动态库版本
(3)如果你所实现的功能需要存在一个类的单个示例中,最好使用动态库
5. 静态库链接的具体规则
在linux下链接静态库需要遵循下列规则
(1)依次链接静态库,每次一个静态库
(2)链接静态库从传递给连接器的静态库列表的最后一个静态库开始(通过命令或者makefile),且会反方向逐个链接,直到列表中的第一个位置
(3)链接器会对静态库进行详细的检索,在所有的目标文件中,只有包含客户二进制文件实际所需符号的目标文件才会进行链接
由于这些特定的规则,我们有时需要在传递给链接器的静态列表多次添加同一个静态库,当一个静态库同时提供了多种完全不同的功能时,就会遇到这种多次添加的情况
6. 将静态库转换成动态库
(1)使用打包工具(ar)来提取所有静态库中的目标文件
$ ar -x <static library>.a
执行该命令会把静态库中的目标文件集合提取到当前目录
(2)链接器使用提取出来的目标文件集合来构建动态库
7. 静态库在64位linux平台上的问题
在64位linux平台上使用静态库会遇到一个非常特殊的情况
(1)将静态库链接到可执行文件与在32位linux上进行操作没有任何区别
(2)但是,静态库链接到共享库则要求静态库需要用-fPIC或-mcmodel-large编译器选项来进行构建(编译器在编译过程中的错误打印输出时的建议)
静态库的导入选择条件:当客户端二进制文件链接静态库时不会把整个静态库的内容链接进来,智慧链接目标文件中必要的符号
动态库的导入选择条件:当客户端二进制文件链接动态库时,选择的条件是在符号表这个层面上,只会选择包含在符号表中实际需要的动态库符号,但是在其它所有方面,这个选择条件实际上是不存在的,无论动态库功能中具体需要的代码有多少都会将整个动态库链接进来。
高级C/C++编译技术之读书笔记(二)之库的概念的更多相关文章
- 高级C/C++编译技术之读书笔记(一)之编译/链接
最近有幸阅读了<高级C/C++编译技术>深受启发,该书深入浅出地讲解了构建过程(编译.链接)中的各种细节,从多个角度展示了程序与库文件或代码的集成方法,提出了面向代码复用和系统集成的软件架 ...
- 高级C/C++编译技术之读书笔记(三)之动态库设计
最近有幸阅读了<高级C/C++编译技术>深受启发,该书深入浅出地讲解了构建过程(编译.链接)中的各种细节,从多个角度展示了程序与库文件或代码的集成方法,提出了面向代码复用和系统集成的软件架 ...
- 高级C/C++编译技术之读书笔记(四)之定位库文件
最近有幸阅读了<高级C/C++编译技术>深受启发,该书深入浅出地讲解了构建过程(编译.链接)中的各种细节,从多个角度展示了程序与库文件或代码的集成方法,提出了面向代码复用和系统集成的软件架 ...
- 高级C/C++编译技术之读书笔记(五)之动态库版本控制
最近有幸阅读了<高级C/C++编译技术>深受启发,该书深入浅出地讲解了构建过程(编译.链接)中的各种细节,从多个角度展示了程序与库文件或代码的集成方法,提出了面向代码复用和系统集成的软件架 ...
- 深入理解linux网络技术内幕读书笔记(二)--关键数据结构
Table of Contents 1 套接字缓冲区: sk_buff结构 1.1 网络选项及内核结构 1.2 结构说明及操作函数 2 net_device结构 2.1 MTU 2.2 结构说明及操作 ...
- Struts2技术内幕 读书笔记二 web开发的基本模式
最佳实践 在讨论基本模式之前,我们先说说一个词:最佳实践 任何程序的编写都得遵循一个特定的规范.这种规范有约定俗称的例如:包名全小写,类名每个单词第一个字母大写等等等等;另外还有一些需要我们严格遵守的 ...
- webkit技术内幕读书笔记 (二、三)
可视区和网页 通常网页比屏幕的可视区面积要大,因此当网页内容在可视区中放不下时,一般浏览器会提供滚动条. 从URL到构建完DOM树的过程 当用户输入网页URL的时候,WebKit调用其资源加载器加载该 ...
- 深入探索Android热修复技术原理读书笔记 —— 代码热修复技术
在前一篇文章 深入探索Android热修复技术原理读书笔记 -- 热修复技术介绍中,对热修复技术进行了介绍,下面将详细介绍其中的代码修复技术. 1 底层热替换原理 在各种 Android 热修复方案中 ...
- 深入探索Android热修复技术原理读书笔记 —— 资源热修复技术
该系列文章: 深入探索Android热修复技术原理读书笔记 -- 热修复技术介绍 深入探索Android热修复技术原理读书笔记 -- 代码热修复技术 1 普遍的实现方式 Android资源的热修复,就 ...
随机推荐
- 验证码插件代码:image.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...
- Android Studio 入门级教程
引用原文:http://www.cnblogs.com/abao0/p/6934023.html 写博客是为了记住自己容易忘记的东西,另外也是对自己工作的总结,文章可以转载,无需版权.希望尽自己的努力 ...
- [BZOJ1823]满汉全席
Description 满汉全席是中国最丰盛的宴客菜肴,有许多种不同的材料透过满族或是汉族的料理方式,呈现在數量繁多的菜色之中.由于菜色众多而繁杂,只有极少數博学多闻技艺高超的厨师能够做出满汉全席,而 ...
- HBase 协处理器---基本概念和regionObserver的简单实现
1. 简介 对于HBase的协处理器概念可由其官方博文了解:https://blogs.apache.org/hbase/entry/coprocessor_introduction 总体来说其包含两 ...
- hdu1596 find the safest road - floyd
2017-08-04 14:42:56 writer:pprp 题意: Problem Description XX星球有很多城市,每个城市之间有一条或多条飞行通道,但是并不是所有的路都是很安全的,每 ...
- NumPy数组创建例程
NumPy - 数组创建例程 新的ndarray对象可以通过任何下列数组创建例程或使用低级ndarray构造函数构造. numpy.empty 它创建指定形状和dtype的未初始化数组. 它使用以下构 ...
- D3.js学习笔记(四)—— 使用SVG坐标空间
目标 在这一章,你将要使用D3.js基于一些数据把SVG元素添加到你想要的坐标位置上. 我们的目标就是使用下面的数据集: var spaceCircles = [30,70,110]; 并使用D3.j ...
- vue组件化开发-vuex状态管理库
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.Vuex 也集成到 Vue 的官方调试工具 ...
- C++(十五) — sizeof 运算符
1.基本数据类型 sizeof 是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小. sizeof 运算符可用于获取类.结构.共用体和其他用户自定义数据类型的大小. 使用 sizeo ...
- maven 其他远程仓库配置
在平时的开发中,我们往往不会使用默认的中央仓库,默认的中央仓库访问的速度比较慢,访问的人或许很多,有时候也无法满足我们项目的需求,可能项目需要的某些构件中央仓库中是没有的,而在其他远程仓库中有,如JB ...