高级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资源的热修复,就 ...
随机推荐
- git-bash使用ctrl C无法终止nodemon的执行
原因: git的bug 解决:git版本降级为2.10.0好了
- 使用POI做的一个生成Excel的工具类。包含了导出Excel和解析Excel方法
PoiExcelUtils.java /** * */ package com.common.office; import java.io.File; import java.io.FileInput ...
- GitLab 安装与入门
GitLab介绍: GitLab是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目. GitLab拥有与Github ...
- Hibernate关联关系映射之一对一关联关系
人和身份证之间就是一个典型的一对一关联关系.实现一对一关联关系映射的方式有两种一种是基于外键,一种是基于主键,下面我们先看基于外键的关联方式 首先看他们的实体类 Person类 ? 1 2 3 4 5 ...
- 一图看懂join、left join、right join、fulljoin间的区别
INNER JOIN 关键字在表中存在至少一个匹配时返回行. LEFT JOIN 关键字从左表(table1)返回所有的行,即使右表(table2)中没有匹配.如果右表中没有匹配,则结果为 NULL. ...
- PAT1073. Scientific Notation (20)
#include <iostream> using namespace std; string a; int expo; int dotPos; int expoPos; int i; i ...
- Bootstrap——优秀的开源前端框架
Bootstrap是著名的社交网站.微博的先驱Twitter在2011年8月推出的开源WEB前端框架,集合CSS和HTML,使用了最新的浏览器技术,为快速WEB开发提供了一套前端工具包,包括布局.网格 ...
- Angularjs注入拦截器实现Loading效果
angularjs作为一个全ajax的框架,对于请求,如果页面上不做任何操作的话,在结果烦回来之前,页面是没有任何响应的,不像普通的HTTP请求,会有进度条之类. 什么是拦截器? $httpProvi ...
- spring3: 表达式5.2 SpEL基础
5.1 概述 5.1.1 概述 Spring表达式语言全称为“Spring Expression Language”,缩写为“SpEL”,类似于Struts2x中使用的OGNL表达式语言,能在运行 ...
- C++(二十三) — 内存泄漏及指针悬挂
1.内存泄漏 动态申请的内存空间没有正常释放,但也不能继续使用. ; pch1 = new char('A'); // 此处申请的空间未被释放. char *pch2 = new char; pch1 ...