使用一些相同的符号链接两个共享库
我链接了两个不同的共享库。这两个库都定义了一些共享名称但具有不同实现的符号。我不能让每个库都使用自己的实现而不是另一个库。
例如,两个库都定义了各自在内部调用的全局函数 bar()
。库一从 foo1()
调用它,库二从 foo2()
调用它。
Lib1.so:
T bar
T foo1() // calls bar()
Lib2.so:
T bar
T foo2() // calls bar()
如果我将应用程序链接到 Lib1.so,然后链接到 Lib2.so,即使在调用 foo2() 时也会调用 Lib1.so 的 bar 实现。另一方面,如果我将应用程序链接到 Lib2.so,然后链接到 Lib1.so,则始终从 Lib2.so 调用 bar。
有没有办法让一个库总是比任何其他库更喜欢自己的实现?
I link with two different shared libraries. Both libraries define some symbols that share a name but have different implementations. I can't make each library use its own implementation over the other.
For example, both libraries define a global function bar()
that each calls internally. Library one calls it from foo1()
and library two calls it from foo2()
.
Lib1.so:
T bar
T foo1() // calls bar()
Lib2.so:
T bar
T foo2() // calls bar()
If I link my application against Lib1.so and then Lib2.so the bar implementation from Lib1.so is called even when calling foo2()
. If on the other hand, I link my application against Lib2.so and then Lib1.so, then bar is always called from Lib2.so.
Is there a way to make a library always prefer its own implementation above any other library?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
有多种方法可以解决此问题:
将
-Bsymbolic
或-Bsymbolic-functions
传递给链接器。这具有全局效果:对可以解析为库中符号的全局符号(具有-Bsymbolic-functions
的函数类型)的每个引用都会解析为该符号。这样,您就失去了使用 LD_PRELOAD 对这些符号进行内部库调用的能力。 符号仍会导出,因此可以从库外部引用它们。使用版本脚本将符号标记为库的本地,例如使用类似:
{local: bar;};
和将--version-script=versionfile
传递给链接器。 符号未导出。用适当的可见性标记符号(GCC 可见性信息页面),可以是隐藏、内部或受保护。 受保护可见性符号导出为
.protected
,隐藏符号为 导出,并且您妥协不从库外部调用它们,即使是通过函数指针间接调用它们。您可以使用 objdump -T 来检查导出了哪些符号。
There are several ways to solve this:
Pass
-Bsymbolic
or-Bsymbolic-functions
to the linker. This has a global effect: every reference to a global symbol (of function type for-Bsymbolic-functions
) that can be resolved to a symbol in the library is resolved to that symbol. With this you lose the ability to interpose internal library calls to those symbols using LD_PRELOAD. The symbols are still exported, so they can be referenced from outside the library.Use a version script to mark symbols as local to the library, e.g. use something like:
{local: bar;};
and pass--version-script=versionfile
to the linker. The symbols are not exported.Mark symbols with an approppiate visibility (GCC info page for visibility), which will be either hidden, internal, or protected. protected visibility symbols are exported as
.protected
, hidden symbols are not exported, and internal symbols are not exported and you compromise not to call them from outside the library, even indirectly through function pointers.You can check which symbols are exported with
objdump -T
.您必须创建两个“包装器”共享库,每个现有库一个。每个都应该使用 --dynamic-list 构建,该列表仅列出定义 API 的一些不冲突的符号。您还需要 -Bsymbolic 以避免任何全局组合。
通过 dlopen 使用合适的选项访问生成的库可能会压力更小。
You will have to create two 'wrapper' shared libs, one for each of your existing libs. Each one should be built with a --dynamic-list that lists only a few non-conflicting symbols that define an API. You will also need -Bsymbolic to avoid any global combination.
It might be less stressful to access the resulting libs via dlopen with suitable options, as well.
解决这个问题的另一种方法是使用宏来更改命名空间。
先决条件
解决方案
-DLibNS=LibNSv1
,对另一种情况使用-DLibNS=LibNSv2
。代码中使用库时,根据自己的实际情况定义宏;
<前><代码>#define LibNS LibNSv1
#include“my_lib.h”
#undef LibNS
使用此解决方案而不是其他解决方案的原因
潜在问题
#include "my_lib.h"
可能使用宏来防止多重包含并取消定义它们以避免这可能会导致许多不同的问题(库作者将来可能会更改宏名称,标头定义了一些其他宏等)。LibNSv1
或LibNSv2
。这可能会导致其他问题,具体取决于库及其使用方式。注释
Another way to solve this problem is using macro to change namespace.
Prerequisites
Solution
-DLibNS=LibNSv1
for one case and-DLibNS=LibNSv2
for the other.When using libraries in the code, define macro according your current situation;
Reasons why use this instead of other solutions
Potential problems
#include "my_lib.h"
probably uses macro to protect against multiple-inclusion and undefining them to avoid this might cause lots of different problems (library author might change the macro name in the future, header defines some other macros, etc.).LibNS
might be used for something else in the library (variable, function, etc.); in that case, this name will be also changed toLibNSv1
orLibNSv2
. This might lead to other problems depending on the library and how it's used.Notes