6.动态链接

6.动态链接

Posted by ZhaoLe on March 11, 2021

//TODO:….动态链接学的并不好,PIC外部模块函数调用的细节理解不够好,涉及到GOT,PLT之间如何协作工作没有理解,感觉还有些基础要补下,决定先暂时将动态链接放下,后面再补完

动态链接

静态连接中如果有多个目标文件进行连接,需要将链接好的文件分别都装载,拷贝到内存中。再重复占用一次内存空间,对于如果有多个模块来说,是非常浪费空间的。即便现在计算机的内存空间大,也是要避免掉无意义的浪费,如果可以·对相同的模块重复利用,那就非常节省空间了。这个时候动态链接就出现了。 动态链接目标不是存储在硬盘上的目标文件代码,而是加载在内存中的共享库。Linux中动态链接文件又叫共享对象,就是 .so文件。 要想在程序运行的时候共享代码 要求就是这些机器码必须地址无关。详细的说就是如果共享库中出现地址有关代码的话,在运行时跳转地址就是绝对地址了,无法复用,动态链接中要求无论在哪个内存地址,都能够正常执行。

FAQ

动态链接学起来比静态连接难多了,里面涉及的碎片化概念也挺多的,一开始记录的笔记也比较散,后来决定用问答的形式将这些知识点梳理下。

动态链接与静态连接的区别

静态连接发生在编译期,在编译期间就可以知道各种符号的地址,可以通过重定位表来计算出引用其他模块的虚拟内存地址。 动态链接发生在装载时,由装载器分配一块连续的虚拟地址空间给共享对象,让地址无关的共享模块加载在虚拟内存中,可供多个目标文件可以连接。

什么是PIC

加载无需重定位的代码称为位置无关代码(Position-Independent Code PIC). 因为共享库的要求是无论加载到内存哪个位置 都需要被正确连接到,这就要求动态链接的时候不能固定共享库的绝对地址。要求地址无关。 根据上面的思路,我们吧指令中那些需要修改的部分分离出来,放入数据段中,因为在虚拟内存中,代码段是共享并且只读的,而数据段是各个动态链接它的应用程序里各加载一份。代码段和数据段的相对位置是不变的,在虚拟内存中,内存地址和对应代码段位置的偏移量是始终确定的 ,这样共享库就能做到地址无关。

什么是GOT

GOT叫全局偏移量表(Global Offset Table),存在于数据段,每个被目标模块引用的全局数据变量都有一个8字节数据(类似重定位记录)存在其中。 GOT中记录着该外部函数真正的地址,装载器在做动态链接时,会查找每个外部符号的地址,然后填充到GOT的对应的项中。

什么是PLT

过程连接表(Procedure Linkage Table)延迟绑定技术中一种,存在于代码段。数据格式是数组形式,每一项都是一小段代码,对应于本运行模块要引用的一个全局函数

如何做到位置无关代码

针对于外模块分数据引用和函数调用两种会分别进行说明,在说之前我们还需知道一些概念上的细节: 无论我们在内存中任何加载一个目标模块,数据段与代码段的距离总是保持不变,因此,代码段中任何指令和数据段中任何变量之间的距离都是一个运行时常量,与代码段和数据段的绝对内存位置无关

  • PIC数据引用 在链接器的编译时期可以确定GOT相对于当前指令的偏移量,就是当前寄存器的值加上偏移量。等到了加载的时候链接器会重定位GOT中每个条目,使它包含目标的正确绝对地址。

  • PIC函数调用 调用共享库定义的函数,因为不知道函数的运行时地址,使用了延迟绑定这个技术,将过程地址绑定推迟到第一次调用该过程时候(符号查找,重定位)。因为一个共享模块有很多函数,但是真正使用缺不是很多,也是为了性能考虑,将函数地址解析推迟到它实际使用的时候。它与PIC引用类似 不过多出了过程连接表(PLT)。

调用的基础流程:

1

资料引用