【问题标题】:Why must shared libraries be position independent while static libraries don't?为什么共享库必须是位置独立的,而静态库不是?
【发布时间】:2019-08-25 20:24:01
【问题描述】:

我了解位置无关代码使用当前位置的偏移量,而位置相关代码使用绝对地址。

但是,我不明白为什么共享库必须被视为与位置无关,而静态库则不然?

【问题讨论】:

  • 假设您有两个动态库,内存地址重叠。现在一个程序尝试使用(并因此加载)它们。
  • @EOF 内存地址重叠是什么意思?
  • 库使用的内存地址集不是(成对)不相交的。 IOW,集合之间存在(非空)成对交集。
  • 如果libA 使用地址0x20000 的内存来存储代码或数据,而libB 使用地址0x20000 的内存来存储其他代码或数据,那是行不通的。
  • 请记住,当前的计算实践大多来自 32 位甚至 16 位计算时代。想象一下,为了简单起见,您将 32 位地址空间划分为 1 MiB 块,每个库将获得其中一个。不是你有 4096 个不同的“库块”。加上生日悖论和10-100的千库可供选择,你会发现修复动态库的地址是行不通的。对于 64 位地址空间,您甚至可以侥幸成功,但同时 64 位处理器架构往往包含使 PIC 不那么痛苦的功能。

标签: c shared-libraries static-libraries


【解决方案1】:

通常,现在的程序只有一个线性地址空间来存储所有内容,并由虚拟内存(硬件和操作系统子系统)支持。并且所有使用的东西都必须以某种方式安装在其中。

为此,我们必须区分 PIC 代码(任何位置都可以)、可重定位代码(首选一个位置)和固定代码(只有一个位置有效)。

由于可执行文件本身具有特权,因为它是第一个加载的用户代码(除了某些系统中的加载器,尽管它通常可以无缝地重新定位自身),它可以放在任何你想要的地方。但是使用它会限制 ASLR。

可执行文件的静态库中的代码可以利用,但会限制包含的代码。

另一方面,共享库的加载顺序没有明确规定,因此,尽管加载器可以尝试将其放在首选位置,但通常必须能够将其放在其他位置。
因此,共享库和它们包含的代码必须是 PIC 或至少是可重定位的。

PIC 代码通常稍微慢一些,但需要较少的修复,这意味着大多数可以根据需要从源二进制文件重新加载,而不必重新定位(在 Windows 95 和后代中发生)或交换到磁盘当需要空间时。

【讨论】:

  • 由于我们不知道共享库将被加载到内存中的哪个位置,我们必须确保它是位置无关代码,这样说是否正确?
  • 是的。尽管我们有时可以摆脱猜测。你今天运气好吗?
  • 但是为什么不使用重定位而不是图片呢?顺便说一句,这是一个肮脏的哈利参考
  • @duper21 正如我所说,与可重定位代码相比,PIC 需要的修复(以及集中在几页中的修复)要少得多(而且这些修复非常均匀地分布在各处)。因此,几乎所有可重定位代码都本地化到它所使用的每个单个进程,而 PIC 代码几乎共享所有未被触及的内容,除了一两页。
  • @Deduplicator 相关用户名?
【解决方案2】:

实际上,“静态库”也有与位置无关的代码。不同之处在于链接器在构建静态可执行文件时将这些相对地址解析为绝对地址。静态库一旦链接,就不能在其他任何地址执行。

对于能够共享的共享库,这意味着代码大部分不会被更改。因此,代码准备好在运行时的任何位置工作。

上面使用的所有“地址”都指的是“虚拟地址”。静态库仍然可以在不同的物理地址加载和执行,而虚拟地址保持不变...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-28
    • 1970-01-01
    • 2014-05-27
    • 2023-04-04
    • 2021-06-04
    • 1970-01-01
    相关资源
    最近更新 更多