引言
想要了解链接的过程就不得不了解什么是静态链接库与动态链接库 它们都在其自身角度解决了一些困难的问题 接下来我们就来看看究竟什么是静态链接库与动态链接库以及其作用
静态链接库
我们知道在链接的过程中并不是只有我们的代码而已 在绝大多数情况下要用到安全稳定的标准库(大多数情况),那我们就要把库的代码拿到我们的的代码中来 我们知道在链接阶段已经得到了一张符号表 所以我们要做的就是把引用与定义相连接 但一个标准库中文件显然是很多的 如果每次引用都会把库中的代码都拷贝了显然是有些笨重的
所以我们的静态库采用了把库中每一个函数都变成一个独立的可重定位文件(点击开头浅析链接),这样我们在链接阶段就可以把我们需要的部分拷贝,其他的则不同理会 这样极大的节省了我们的宝贵的内存
如何定义自己的静态库
静态库以存档这种特殊的文件格式存在,后缀为 .a,经过前面的解释 我们也不难理解存档其实就是可重定位文件的集合 我们可以通过AR工具来构建自己的静态库
gcc -c test.c
ar rcs stalib_name.a test.o
首先创建.o文件(经过汇编),然后使用AR工具生产存档
gcc -c main.c
gcc -static main.o ./stalib_name.a
./a.out
这样我们即可运行我们使用了创建的静态库的文件
动态链接库(DLL)
动态链接库又叫共享库,两个名字突出了其两个特点
- 内存共享
- 动态链接
内存共享
静态库虽然已经很好的节省了内存 但在很多情况下还是不够优秀 比如常用的标准IO库 我们几乎每个程序都需要 难到要给每一个进程都拷贝一份吗 答案是否定的,共享库的策略是每一个文件系统系统只有一份库的数据,每一个库的代码部分可被不同进程共享 也就是说每一个进程的虚拟地址经过翻译后得到的物理地址相同 共用一份库,这样就优化了我们的内存占用
创建自己的动态库
与静态库一样 动态库同样有一个特殊后缀 .so
gcc -shared -fpic -o test_dy.so 动态链接库.c
gcc main.c ./test_dy.so
./a.out
- fpic 生成位置无关代码
- shared 创建一个共享的库
具体实现取决于两个特殊的数据结构(均为数组)
GOT存在于数据段开头 PLT存在于代码段
- GOT(Global Offset Table) 全局偏移量表
- PLT(Procedure Linkage Table) 过程链接表
GOT
因为链接阶段可能不知道一些符号的的具体位置 所以我们需要一个数据结构来存储经过动态加载后找到的符号的真实地址 这就是GOT 需要注意的是GOT的前三项不存储符号地址 GOT[0]和GOT[1]存储动态链接器解析函数地址时需要的信息(那么多库 我们当然要标记我们需要的) ,GOT[2] 则是存储动态链接器程序的入口点
PLT
将函数调用转移到GOT中 GOT存储绝对地址
加载时链接就是在加载时重定位GOT中的条目
运行时链接就是对于每一条GOT条目在库中进行匹配
动态链接过程
这里有一篇前辈的文章 非常详细