问题
不同的程序中,有可能存在调用相同的基础库,内存加载程序的时候是否把这些共享库都加载一次?
动态链接
上次说到的各种内存处理技术:虚拟内存、内存交换、内存分页等等都是为了解决内存不足的情况。
多个程序通过装载器装载到内存里面,链接好的同样功能的代码,不会去多次加载,通过动态链接来解决这种问题。
静态链接(Static Link):之前提到的合并代码段的方法。
动态链接(Dynamic Link):加载到内存中的共享库(Shared Libraries),会被很多个程序的指令调用到。
在 Windows 下,这些共享库文件就是.dll 文件,也就是 Dynamic-Link Libary(DLL,动态链接库)。在 Linux 下,这些共享库文件就是.so 文件,也就是 Shared Object(一般我们也称之为动态链接库)。
编译出来的共享库文件的指令代码,是地址无关码(Position-Independent Code)。
这段代码,无论加载在哪个内存地址,都能够正常执行。
对于所有动态链接共享库的程序来讲,虽然我们的共享库用的都是同一段物理内存地址,但是在不同的应用程序里,它所在的虚拟内存地址是不同的。
PLT 和 GOT,动态链接的解决方案
要实现动态链接共享库,和前面的静态链接里的符号表和重定向表类似。
PLT:程序链接表(Procedure Link Table)
GOT:全局偏移表(Global Offset Table)
共享库的代码部分的物理内存是共享的,但是数据部分是各个动态链接它的应用程序里面各加载一份的。
我们的 GOT 表位于共享库自己的数据段里。GOT 表在内存里和对应的代码段位置之间的偏移量,始终是确定的。这样,我们的共享库就是地址无关的代码,对应的各个程序只需要在物理内存里面加载同一份代码。而我们又要通过各个可执行程序在加载时,生成的各不相同的 GOT 表,来找到它需要调用到的外部变量和函数的地址。
领取专属 10元无门槛券
私享最新 技术干货