猜你喜欢
高级C/C++编译技术(典藏版)

高级C/C++编译技术(典藏版)

书籍作者:米兰·斯特瓦诺维奇 ISBN:9787111717300
书籍语言:简体中文 连载状态:全集
电子书格式:pdf,txt,epub,mobi,azw3 下载次数:3813
创建日期:2023-05-25 发布日期:2023-05-25
运行环境:PC/Windows/Linux/Mac/IOS/iPhone/iPad/Kindle/Android/安卓/平板
内容简介
学习如何编写C和C++代码仅仅是个开始。如果你希望从事系统底层开发工作,或想深入理解操作系统、编译器及它们之间内在的关联,成为编程专家,那么就必须充分了解编译器生成的二进制文件(目标文件、静态库、动态库和可执行文件)的作用和结构。开源已经在许多方面从根本上改变了软件的原有面貌,越来越多的系统开始采用或集成开源代码,因此对每位开发人员来说,学习和理解这些底层技术也变得十分重要。

本书深入浅出地讲解了构建过程(编译、链接)中的细节,从多个角度展示了程序与库文件或代码的集成方法,提出了面向代码重用和系统集成的软件架构设计方法,同时展示了系统开发过程中疑难问题的解决方案。另外,本书也是一本C和C++二进制文件方面的软件工程指南,涵盖中级和专家级程序员所需的各方面内容和信息。
通过阅读本书,你将学到:

*构建过程(编译和链接)与装载过程的内部原理。
*静态库、动态库和可执行文件的内部工作机制。
*面向代码重用和系统集成的软件架构设计方法。
*编译、链接与运行时问题的排查技巧。
*在Linux和Windows平台下利用二进制文件分析工具进行分析的方法。
作者简介
米兰·斯特瓦诺维奇( Milan Stevanovic ) 
资深软件顾问,在多个学科的工程领域有着丰富的经验。他主要从事Linux和Windows平台下的多媒体压缩格式及多媒体框架设计工作。他热衷于开源,是avxsynth开源项目的主要贡献者,对C和C++底层技术有着深入的研究。
前言
由于Linux市场份额增加,而且越来越多的人都将Linux作为其编程环境,这促使开发人员开始关注Linux编程的相关问题。与在一些封装良好的平台上开发软件的开发人员不同,在Windows和Mac平台上利用IDE和SDK将程序员从一些特定的编程细节问题中解放出来,Linux开发人员在日常工作中需要将来自不同项目且编码风格迥异的代码组合起来,这需要开发人员充分理解编译器、链接器的内部工作机制和程序装载机制,以及不同库的设计细节和使用方法。

本书将许多零碎的知识点进行汇总,并讨论其中有价值的内容,再通过一系列精心设计的简单示例进行验证。需要注意的是,我并非计算机科学科班出身。在20世纪90年代末至今的数字革命中,我作为电气工程师供职于硅谷的一家多媒体行业高新技术企业,并因此掌握了相关领域的知识。希望本书的主题和内容能够让更多读者受益。

【读者对象】
作为一名软件设计实践顾问(虽然很忙,但我还是非常自豪的),我经常会与不同专业背景和资历的人沟通。我经常在不同的办公环境中工作,因此接触了许多开发人员(绝大多数来自硅谷),这也让我更加了解了本书的受众群体,其中包括以下几类人群:

第一类受众群体是来自不同工程领域(电气工程、机械、机器人技术和系统控制、航天、物理和化学等领域)的C/C++开发人员,这类人需要在日常工作中通过编程来解决问题。对缺乏正规计算机科学课程和理论教学的人来说,本书所提供的资料弥足
珍贵。

第二类受众群体是具有计算机科学教育背景的初级程序员。本书能够帮助这类人将主修课程中学到的知识具体化,并注重实践。对资深工程师而言,将第12~14章的内容作为手册查阅也很有益。

第三类受众群体是操作系统集成和定制的爱好者。理解二进制文件及其内部工作机制将有助于在解决问题的过程中扫除障碍。


不管怎么说……
就目前就业市场的情况而言,我认为(自2005年左右开始)熟悉C/C++语言的复杂性,甚至是算法、数据结构和设计模式,对于找到一份好工作是远远不够的。

在开源盛行的今天,专业开发人员在日常工作中所编写的代码越来越少,取而代之的是将现有代码集成到项目中。这不仅要求开发人员能够读懂其他人编写的代码(使用不同的代码风格和实践),还需要了解如何才能以最好的方式将现有的包(绝大多数以二进制文件/库和导出头文件的形式提供)集成到代码中。

我希望本书能够兼具教学(对急需这些知识的读者而言)和快速查询的功能(对分析C/C++二进制文件相关工作的工程师而言)。

【为何采用Linux进行演示】
选择Linux并非我个人的偏好。实际上了解我的人都知道,我过去是多么喜欢使用Windows作为开发环境(原本这是我首选的设计平台),原因是Windows平台具有完善的文档、完美的支持和符合规范的认证组件。我设计过许多专业化软件(曾为Palm公司设计开发了Windows Mobile平台的GraphEdit,其中包含许多复杂的功能,随后又开发了多个媒体格式和DSP分析软件),当时我对Windows技术了如指掌,并感叹Windows相关技术所带来的改变。

与此同时, Linux的时代到来了。有关Linux的技术随处可见,而对开发人员来说,也必须顺应这种趋势去学习和使用它。

Linux软件开发环境具有开放、透明和简单明了的特点。在Linux中,我们可以对每个程序设计阶段进行控制。同时,Linux提供了完善的文档,再加上网络上提供的资源,就可以轻松地使用GNU工具链。

实际上,由于Linux C/C++开发经验可以直接适用于Mac OS平台的底层开发,因此我最终决定选用Linux/GNU作为本书所涵盖的主要开发环境。

别急!Linux与GNU完全是两回事
实际上,Linux是内核,而GNU中包含了Linux内核之上的所有软件。除了GNU编译器可以在其他操作系统上使用(比如Windows上的MinGW)以外,在绝大多数情况下,GNU与Linux的关系其实非常紧密。为了简单起见,同时为了符合一般开发人员对开发场景的认识,特别是为了将Linux与Windows进行对比,本书将GNU与Linux作为一个整体,简称为“Linux”。

【章节概览】
第1~5章讲解的内容主要为后续内容做铺垫。拥有计算机科学背景的读者可以快速阅读这些章节(幸运的是,这些章节的内容并不长)。实际上,任何计算机科学方面的教科书都会对这些内容进行类似介绍,而且内容会更为详细。我个人推荐由Bryant和O’Hallaron编写的《深入理解计算机系统》(Computer Systems—A Programmer’s Perspective)一书,原因是该书对很多主题都进行了非常有条理的梳理和总结。

第6~11章是本书的核心章节。为求整体内容简洁明了,我花费了相当大的精力,并尝试使用一些日常生活中常见事物的文字和图片来阐述那些最为重要的核心概念。如果你不是计算机科学科班出身,那么有必要先理解这些内容。其实这些章节是本书主题的要点。

第12~14章主要概括了一些实践方面的内容,便于读者快速查找相关的概念。这些章节针对一些特定平台的二进制文件分
目录
译者序
前言
第1章 多任务操作系统基础 1
1.1 一些有用的抽象概念 1
1.2 存储器层次结构与缓存策略 2
1.3 虚拟内存 3
1.4 虚拟地址 5
1.5 进程的内存划分方案 5
1.6 二进制文件、编译器、链接器与装载器的作用 6
1.7 小结 7

第2章 程序生命周期阶段基础 8
2.1 基本假设 8
2.2 编写代码 9
2.3 编译阶段 11
2.3.1 基本概念 11
2.3.2 相关概念 11
2.3.3 编译的各个阶段 12
2.3.4 目标文件属性 23
2.3.5 编译过程的局限性 24
2.4 链接 26
2.4.1 链接阶段 26
2.4.2 链接器视角 31
2.5 可执行文件属性 33
2.5.1 各种节的类型 34
2.5.2 各种符号类型 36

第3章 加载程序执行阶段 37
3.1 shell的重要性 37
3.2 内核的作用 39
3.3 装载器的作用 39
3.3.1 装载器视角下的二进制文件(节与段) 39
3.3.2 程序加载阶段 40
3.4 程序执行入口点 43
3.4.1 装载器查找入口点 43
3.4.2 _start()函数的作用 43
3.4.3 __libc_start_main()函数的作用 44
3.4.4 栈和调用惯例 44

第4章 重用概念的作用 46
4.1 静态库 46
4.2 动态库 48
4.2.1 动态库和共享库 49
4.2.2 动态链接详解 51
4.2.3 Windows平台中动态链接的特点 54
4.2.4 动态库的特点 56
4.2.5 应用程序二进制接口 56
4.3 静态库和动态库对比 57
4.3.1 导入选择条件的差异 57
4.3.2 部署难题 59
4.4 一些有用的类比 61
4.5 结论:二进制重用概念所产生的影响 63

第5章 使用静态库 64
5.1 创建静态库 64
5.1.1 创建Linux静态库 64
5.1.2 创建Windows静态库 65
5.2 静态库的使用场合 65
5.3 静态库设计技巧 66
5.3.1 丢失符号可见性和唯一性的可能性 66
5.3.2 静态库使用禁忌 67
5.3.3 静态库链接的具体规则 68
5.3.4 将静态库转换成动态库 68
5.3.5 静态库在64位Linux平台上的问题 68

第6章 动态库的设计:基础篇 70
6.1 创建动态库 70
6.1.1 在Linux中创建动态库 70
6.1.2 在Windows中创建动态库 72
6.2 设计动态库 75
6.2.1 设计二进制接口 75
6.2.2 设计应用程序的二进制接口 79
6.2.3 控制动态库符号的可见性 82
6.2.4 完成链接需要满足的条件 94
6.3 动态链接模式 94
6.3.1 加载时动态链接 95
6.3.2 运行时动态链接 95
6.3.3 比较两种动态链接模式 98

第7章 定位库文件 99
7.1 典型用例场景 99
7.1.1 开发用例场景 99
7.1.2 用户运行时用例场景 100
7.2 构建过程中库文件的定位规则 101
7.2.1 Linux构建过程中的库文件定位规则 101
7.2.2 Windows构建过程中的库文件定位规则 105
7.3 运行时动态库文件的定位规则 109
7.3.1 Linux运行时动态库文件的定位规则 110
7.3.2 Windows运行时动态库文件的定位规则 114
7.4 示例:Linux构建时与运行时的库文件定位 115

第8章 动态库的设计:进阶篇 119
8.1 解析内存地址的必要性 119
8.2 引用解析中的常见问题 120
8.3 地址转换引发的问题 122
8.3.1 情景1:客户二进制文件需要知道动态库符号地址 122
8.3.2 情景2:被装载的库不需要知道其自身符号地址 123
8.4 链接器-装载器协作 124
8.4.1 总体策略 125
8.4.2 具体技术 126
8.4.3 链接器重定位提示概述 127
8.5 链接器-装载器协作实现技术 128
8.5.1 装载时重定位 129
8.5.2 位置无关代码 129

第9章 动态链接时的重复符号处理 134
9.1 重复符号的定义 134
9.2 重复符号的默认处理 137
9.3 在动态库链接过程中处理重复符号 140
9.3.1 处理重复符号问题的一般策略 142
9.3.2 链接器解析动态库重复符号的模糊算法准则 143
9.4 特定重复名称案例分析 144
9.4.1 案例1:客户二进制文件符号与动态库ABI函数冲突 144
9.4.2 案例2:不同动态库的ABI符号冲突 147
9.4.3 案例3:动态库ABI符号和另一个动态库局部符号冲突 151
9.4.4 案例4:两个未导出的动态库符号冲突 153
9.5 小提示:链接并不提供任何类型的命名空间继承 161

第10章 动态库的版本控制 162
10.1 主次版本号与向后兼容性 162
10.1.1 主版本号变更 162
10.1.2 次版本号变更 163
10.1.3 修订版本号 163
10.2 Linux动态库版本控制方案 163
10.2.1 基于soname的版本控制方案 163
10.2.2 基于