我试图从这里[1]了解Linux中的动态库加载,并希望澄清这个概念。具体地说,当在Linux环境中的进程中加载动态库时,它会在地址空间中的任何位置加载。现在,库有一个代码段和一个数据段。代码段的地址未定义为预链接,因此它是0x0000000,而对于数据段,某些数字被定义为地址。
但这是诀窍,这个数据段的地址实际上并不是真正的地址。实际上,无论在何处加载代码段,都会将数据段的预定义地址添加到其中。
我在这里纠正吗?
引用文章还有一件事。这句话是什么意思?
但是,我们有一个约束,即共享库在每个进程中仍必须具有unqiue数据实例。虽然可以在运行时将库数据放在我们想要的任何地方,但这需要留下重定位来修补代码并告知它在哪里实际查找数据 - 破坏代码的始终只读属性,从而破坏性。
[1] http://www.technovelty.org/linux/plt-and-got-the-key-to-code-sharing-and-dynamic-libraries.html
答案 0 :(得分:1)
实际上,无论加载什么位置代码段,都会将数据段的预定义地址添加到其中。
是。数据段的“VirtAddr”将添加到基址。
这句话是什么意思?
这意味着当库访问自己的静态数据时,我们不应该在库代码中使用重定位。否则链接器可能需要修补二进制代码,这导致在进程之间取消共享库代码的某些部分(如果process1将库lib1加载到0x40000000,而process2加载lib1为0x50000000,则它们的数据重定位将不同)。
因此,在现实生活中使用不同的解决方案。库代码和数据都加载在一起,代码和数据之间的偏移量对于所有情况都是固定的。在您引用的文字后面有“解决方案”:http://www.technovelty.org/linux/plt-and-got-the-key-to-code-sharing-and-dynamic-libraries.html
从上面的标题中可以看出,解决方案是读写数据部分始终放在库的代码部分的已知偏移处。这样,通过虚拟内存的魔力,每个进程都可以看到自己的数据部分,但可以共享未修改的代码。访问数据所需的只是一些简单的数学;我想要的东西的地址=我当前的地址+已知的固定偏移量。