BookNotes_《CSAPP_3e》_chp07_Linking 链接
作者:互联网
上周末到这周六,花了一周的时间看完了《CSAPP_3e》 chp07 Linking,疫情还在持续也不好出门运动,呆在家里把这周的学习做个梳理和总结。
不得不说,CSAPP这本书真的是非常之经典,不光是他的内容–计算机的底层基础知识,是每个从事计算机软件工作必须修炼的内功,对于身边的人特别是刚毕业的新人我总是不遗余力的推荐;还有就是这本书的行文结构非常符合结构化思维:为什么?是什么?怎么做?
。每章节都是如此的行文结构,真的是授之与鱼和渔。英文的行文和语法也非常工整,至少我读起来没什么困难,里面不少短语和句式我都记录了下来方便自己以后查阅使用,为此我还开了个专栏 English Mood,锻炼自己的英文写作能力。
扯多了,言归正传。
Linking这章,首先介绍了为什么要学习链接,我们能收获到什么并因此避开一些软件开发中的坑?
其次,在简单介绍了编译的大概过程后,开始分析静态链接。介绍了目标文件格式ELF,以及由此生成可执行文件的符号解析、重定位过程。
最后,分析动态链接。静态库和动态库的原理和使用,末尾介绍了个黑科技–打桩技术。
1. 编译的大概过程
我们常说的编译其实是包含了预处理、编译、汇编、链接
这四个过程的总称。拆开来讲,这四个过程都有专门的二进制可执行程序工具来执行(对应cpp、cc、as、ld),而gcc这个二进制可执行程序可以帮我们依次调用它们,我们可以使用特定的参数来让gcc执行其中特定的单个子处理过程,或者子处理过程集(例如-s、-c、-o)。在英文中,对gcc承担这一角色有个称呼–compiler driver
,它一个人有序地指挥和调度着上面四个过程和子工具的调用和执行,driver 这一称呼可以说是非常形象贴切了。
编译的过程
- 预处理
生成内容是ascii码的的文件,后缀是.i - 编译
生成内容是汇编代码语言的文件,后缀是.s - 汇编
生成二进制内容的可重定位目标代码文件,后缀是.o - 链接
生成二进制内容的可执行目标代码文件,没有后缀。
本章后面的内容就是对这些子过程的细节描述了。
2. 静态链接
静态链接是指将输入为可重定位的目标文件
(.o文件)经过符号解析
和重定位
过程生成输出可执行目标文件
。
这里的重点是目标文件格式–ELF。
目标文件分为三类:
- 可重定位目标文件,即.o为后缀的文件;
- 可执行目标文件;
- 共享目标文件。一种可重定位目标文件的特例。
可重定位目标文件
静态链接的材料可重定位目标文件的典型ELF格式图如下:
图1. 可重定位目标文件格式。
EFL文件的格式很重要,重点是深刻了解.text、.rodata、.data、.bss、.symtab
这些sections存储对应源码的那些内容(很多时候面试会问到,嘿嘿),如果了解了.rel.text和.rel.data那更好了。
几个主要section的内容:
Section | Content |
---|---|
.text | 代码段机器码 |
.rodata | 只读数据:格式化字符串(printf),switch语句的跳转表 |
.data | 初始化的全局变量 初始化的static变量 |
.bss | 未初始化的static变量 初始化为0的全局变量和static变量 |
.COMMON | 未初始化的全局变量 |
注:函数内部的局部变量由运行时 stack
维护,他们是不会出现在.data 或 .bss中的。
然后在详细介绍了符号解析和重定位。符号解析这部分比较细,要多看几遍,具体的看书就好了。
重定位的目的就是给所有整合起来的地址为0的section和symbol分配运行时虚拟地址。
重定位操作包含两步:
- 对所有sections和symbol definition进行重定位;
- 对sections中的symbol reference进行重定位。
其中对symbol reference进行重定位有分为pc-relative reference重定位和absolute reference 重定位。
可执行目标文件
紧接着介绍了可执行目标文件ELF格式:
图2. 可执行目标文件格式
学习的时候要对比前面提到的可重定位目标文件ELF格式来看,注意他们的差异就好,其他大部分都是类似的。
对于可执行目标文件一个非常重要的点就是要知道它被load进main memory跑起来时的内存布局:
这里值得关注的是stack和heap,注意看它们的地址增长方向。
说几个我认为重要的点:
- 可重定位目标文件(.0)各个sections的地址都是
0地址
,经过链接之后生成的可执行目标文件的各个sections是虚拟地址
。 - 可执行目标文件的.bss section在磁盘存储时只是起到站位符作用并不占用实际的磁盘空间,当可执行目标文件被load to main memory from disk实际跑起来时才会给.bss section中的内容分配main memory空间并初始化值为0. 这也就是为什么可执行文件在磁盘存放时的size小于运行时size的大小的原因了。
- 可执行目标文件被加载进内存运行时的内存布局,特别是运行时stack和运行时heap,知道他们是干嘛的和彼此的区别(比如增长方向)。
3. 动态链接
动态链接是对于动态库来说的。动态库指的是.so后缀的文件(Linux环境下;Windows环境下是DLL文件)。
我理解,动态库和动态链接技术是软件工程软件行业得以规模化快速发展的基础条件。有了动态库,大家可以彼此分工开发不同的模块,开发完成只需要将自己的成果以so库的形式提供给其他模块调用使用,而不用因为一个小小的改动就引起整个代码工程大动干戈。协同的效率非常高。
涉及动态库有几个常用的开发接口:dlopen,dlsym,dlclose,dlerror
。
本章最后介绍了PIC位置无关码和库打桩技术。这个就不细说了。
说一下我知道的打桩技术在我们公司的一个大型应用。我司对Android代码的测试引入了打桩技术,简单来说就是对Jave、Native和Kernel部分的代码都运用了打桩技术来检查代码可能存在的缺陷,目的是在开发过程中就将大部分隐藏的代码问题暴露出来,避免后续量产代码出现相关问题,影响客户体验。
标签:定位,CSAPP,文件,chp07,BookNotes,可重,目标,执行,链接 来源: https://blog.csdn.net/xiaosaerjt/article/details/105749659