ld.so
运行时链接器 ( ) 和程序有什么区别prelink
?我知道运行时链接器(ld.so
)加载程序所需的所有动态库,但是有什么好处prelink
?两者都在做同样的工作,不是吗?
答案1
这很大程度上涵盖了联机prelink
帮助页:
prelink
是一个修改 ELF 共享库和 ELF 动态链接二进制文件的程序,其方式是动态链接器在启动时执行重定位所需的时间显着减少。由于重定位较少,运行时内存消耗也会减少(尤其是不可共享页面的数量)。如果自预链接以来没有任何依赖库发生更改,则仅在启动时使用预链接信息;否则程序会正常重定位。
prelink
首先收集要预链接的 ELF 二进制文件以及它们依赖的所有 ELF 共享库。然后,它为每个库分配一个唯一的虚拟地址空间槽,并将共享库重新链接到该基地址。当动态链接器尝试加载这样的库时,除非该虚拟地址空间槽已被占用,否则它将将该库映射到给定的槽中。完成此操作后prelink
,在动态链接器的帮助下,根据其依赖库解析二进制文件或库中的所有重定位,并将重定位存储到 ELF 对象中。它还将所有依赖库的列表及其校验和存储到二进制文件或库中。对于二进制文件,它还计算一个列表冲突 (在二进制文件的符号搜索范围中的解析方式与在解析依赖库的较小搜索范围中的解析方式不同)并将其存储到特殊的 ELF 部分中。在运行时,动态链接器首先检查所有依赖库是否已成功映射到其指定的地址空间槽中,以及自预链接完成以来它们是否未发生更改。如果所有检查均成功,则动态链接器仅重播冲突列表(通常明显短于重定位总数),而不是重定位每个库。
ld.so
和之间的主要区别prelink
在于,前者在每次加载动态链接的二进制文件时运行。通过预先计算动态链接二进制文件所涉及的库重定位,prelink
尝试减少程序启动时占用的时间和内存;ld.so
它在二进制文件中存储这些重定位以及确定它们是否仍然有效所需的信息,并且ld.so
可以使用该信息来跳过自己的重定位(只要预链接的重定位有效)。
使用prelink
确实会产生许多不利后果,特别是:
- 它修改了二进制文件,这意味着它们不能再与它们的“来源”(包等)进行比较来确定它们是否被篡改;
- 它会导致固定的重定位,这大大减少了地址空间布局随机化的范围,从而降低了系统的安全性(对于任何给定的预链接二进制文件,只要链接库不改变重定位就会保持不变,这对于试图利用其中一个库中的小工具的攻击者来说非常有用)。