31

至少在 Linux 和 Solaris 上,静态库实际上只是一堆已编译的 .o 文件,它们被扔进一个大文件中。编译静态库时,通常会省略 -fpic 标志,因此生成的代码是位置相关的。

现在说我的静态库是 B。我已经构建了它并得到了生成的 .a 文件,它实际上只是所有与位置相关的 .o 文件的全局。现在我有一个我想构建的共享库A,我希望它静态链接B。当我构建A时,我自然会使用-fpic标志来使生成的代码位置独立。但是如果我链接到 B,我不是混合了位置相关和位置无关的目标文件吗?

除非我还指定 -mimpure-text,否则我会收到很多文本重定位错误,我认为这可能是原因。看来我编译一个库的时候,真的需要编译3次,一个共享版本,一个静态版本,一个static-that-c​​an-be-used-by-shared-libs版本。我对吗?我可以继续使用 -mimpure-text 但 g++ 手册页说,如果你这样做,对象实际上并没有最终被共享(不清楚它是全部未共享还是只是静态链接的部分,有人知道吗?) .

4

3 回答 3

29

您不必在共享对象中使用 PIC 代码(正如您发现的那样,您可以使用 -mimpure-text 选项来允许这样做)。

也就是说,共享对象中的非 PIC 代码更重量级。使用 PIC 代码,内存中的文本页面只是磁盘上文本页面的直接内存映射。这意味着如果多个进程正在使用共享对象,它们可以共享内存页面。

但如果您没有 PIC 代码,当运行时链接器加载共享对象时,它必须对文本页面应用修正。这意味着每个使用共享对象的进程都将拥有它自己的任何文本页面的唯一版本,该文本页面上有一个修复(即使共享对象加载到与写时复制相同的地址,也只会注意到该页面是修改,而不是以相同的方式修改)。

对我来说,重要的问题是您是否会同时运行多个进程,每个进程都加载共享对象。如果你这样做了,那么确保 SO 中的所有代码都是 PIC 绝对值得。

但如果不是这种情况并且只有一个进程加载了共享对象,那么它就没有那么重要了。

于 2009-10-19T17:35:56.277 回答
3

我在静态库的共享对象库版本的链接阶段执行以下操作:g++ -shared -o libshared.so -Wl,--whole-archive -fPIC -lstatic -Wl,--no-whole-archive。由于--whole-archive 链接静态库(形式为libstatic.a)(列表)中的每个对象,我相信在(列表)之前使用-fPIC 是OP 需要做的所有事情。

于 2012-06-09T19:04:20.213 回答
1

作为一种替代方法,提供两个库:您的共享库和您正在链接的静态库。它们应该正确链接到最终的可执行文件。

于 2009-10-19T18:40:12.607 回答