Linux:库的制作与原理
文章目录
- 一、什么是库
- 二、静态库
- 1、ar 将.o文件归档
- 2、静态库的名称
- 3、gcc -L 找库
- 4、gcc -I 找头文件
- 5、ldd 查看可执行程序对应链接库的信息
- 6、静态库生成
- 三、动态库
- 1、动态库的生成
- 2、file 查看文件详细属性
- 3、动态库的使用
- 四、使⽤外部库
- 五、目标文件
- 六、ELF文件
- 七、ELF从形成到加载轮廓
- 1、ELF形成可执行
- 2、ELF可执行文件加载
- 3、readelf 查看可执⾏程序的section
- 八、静态链接
- 1、objdump 查看编译后的.o⽬标⽂件
- 2、查看.o文件符号表
- 九、ELF加载与进程地址空间
- 1、逻辑地址
- 2、虚拟地址
- 3、重新理解进程虚拟地址空间
- 十、动态库加载
- 1、进程如何看到动态库
- 2、进程间如何共享库的
- 十一、动态链接
- 1、我们的可执⾏程序被编译器动了⼿脚
- 2、动态库中的相对地址
- 3、程序跟库的映射
- 4、程序进行库调用
- 5、全局偏移量表GOT(global offset table)
- 7、库间依赖
- 8、总结
一、什么是库
在计算机中库是由高级程序员写好的现有的,成熟的,可以复⽤的代码,现实中每个程序都要依赖很多基础的底层库,不可能
每个⼈的代码都从零开始,因此库的存在意义⾮同寻常。
在生活中也充满了库,比如说想要个手机,直接买就行,不需要自己制作,已经有手机生成商把手机所需要的显示屏内存等等零件组装好后,可直接使用的手机。
二、静态库
- 静态库在链接时是把静态库编译的代码拷贝到将要生成可执行的程序里面一起生成可执行程序的
1、ar 将.o文件归档
静态库本质,就是.o打了一个包!!
-
ar 是 gnu 归档工具,rc 表示(replace and create)
-
.a静态库,本质是一种归档文件,不需要使用者解包,而用gcc/g++直接进行链接即可
2、静态库的名称
静态库的命名规范,由lib开头,.a结尾,去掉lib 和 .a 剩下就是库的名字
3、gcc -L 找库
4、gcc -I 找头文件
5、ldd 查看可执行程序对应链接库的信息
6、静态库生成
使用Makefile来生成静态库
使用方式:
三、动态库
1、动态库的生成
先形成同名.o,跟静态库的区别就是加一个 -fPIC选项
然后是打包,动态库直接使用gcc -shared选项 来把.o 文件打包成动态库,静态库是使用ar归档
makefile生成动态库:
2、file 查看文件详细属性
动态库也被称为共享文件
3、动态库的使用
在当前路径下已经有需要的动态库文件和头文件了
然后像使用静态库那样去编译链接形成可执行程序
然后运行可执行程序
但是会报错,系统没有找到动态库链接的路径,因为之前形成可执行程序时只告诉了gcc编译器,系统不知道
- 解决方案:
- 1、把动态库拷贝到系统库中
- 2、建立软连接,把软连接放到系统库中(但这两种都会污染系统库)
- 3、把动态库路径导入到环境变量 LD_LIBRARY_PATH
- 4、在系统指定目录建立 .conf 的配置文件,文件内容就是要查找动态库的路径
向我们自己创建的.conf文件中写入路径
最后再执行重新加载配置
- 当一个文件既有动态库又有静态库时默认使用动态库
- 动静态库同时存在非要使用静态库,加选项-static:
四、使⽤外部库
五、目标文件
- .o(Linux) / .obj(Windows) :可重定位目标文件
动静态库,可执行程序,.o文件都是ELF格式的!
以一定的格式放入到二进制文件中的
六、ELF文件
七、ELF从形成到加载轮廓
1、ELF形成可执行
2、ELF可执行文件加载
3、readelf 查看可执⾏程序的section
选项-S:读取的是Section Headers的内容
- bss:未初始化全局变量,更好的节省空间,节省形成的可执行程序占据磁盘的空间
-l 选项:查看section合并的segment
把原本29个数据节合并为9个数据节
选项-h:查看ELF Header信息
- 整个ELF格式相关的管理信息
- 包括每一个区的开始和大小
八、静态链接
1、objdump 查看编译后的.o⽬标⽂件
-d选项:将.o⽬标⽂件的代码段进行反汇编
选项 -S(大写)对整个文件进行反汇编
2、查看.o文件符号表
readelf -s(小写):读取code.o符号表
- puts:就是printf的实现
- UND就是:undefine,表⽰未定义说⽩了就是本.o⽂件找不到
- FUNC:表⽰run符号类型是个函数
- 1(Ndx):就是run函数所在的section被合并最终的那⼀个section中了,1就是下标
- 所以,链接过程中会涉及到对.o中外部符号进⾏地址重定位。
九、ELF加载与进程地址空间
1、逻辑地址
一个可执行程序,如果没有被加载到内存中,该可执行程序,有逻辑地址
对可执行程序,完成在磁盘上的编制。
逻辑地址(起始地址 + 偏移量)
2、虚拟地址
当代计算机⼯作的时候,都采⽤"平坦模式"进⾏⼯作。所以也要求ELF对⾃⼰的代码和数据进⾏统⼀编址,也就是只有一个起始地址就是全0的地址,只记录数据的偏移量,也叫线性地址。
其实虚拟地址在我们的程序还没有加载到内存的时候,就已经把可执⾏程序进⾏统⼀编址了。
3、重新理解进程虚拟地址空间
- ELF 在被编译好之后,会把⾃⼰未来程序的⼊⼝地址记录在ELF header的Entry字段中
十、动态库加载
1、进程如何看到动态库
2、进程间如何共享库的
十一、动态链接
1、我们的可执⾏程序被编译器动了⼿脚
33
2、动态库中的相对地址
3、程序跟库的映射
4、程序进行库调用
5、全局偏移量表GOT(global offset table)
7、库间依赖