我的情况如下:我们的程序依赖于大量的共享(和静态)库。我想添加一个新的依赖项,这是一个静态库。程序编译时没有问题,但在运行时崩溃。事实证明,新的静态库定义了一个符号foo
,它可以在许多共享库中找到。因此,链接器链接到共享库的foo
,而不是新静态库的foo
--然后在运行时调用了错误的foo
,导致崩溃。
我创建了一个最小的例子来模拟这个:https://gitlab.com/luizromario/linker_example
在那里,我们有:
- 一个名为
libstatic_old
的库,包含一个打印old static lib
的函数print_thing()
- 一个名为
libstatic_new
的库,包含一个打印new static lib
的函数print_thing()
- 一个名为
libdynamic
的共享库链接到libstatic_old
。它包含一个函数do_things()
: - 打印以下消息:
about to print thing from dynamic lib (should print "old static lib"):
- 呼叫
print_thing()
- 一个名为
executable
的可执行文件,它链接到libdynamic和libstatic_new。它: - 打印:
about to do things from executable
- 呼叫
do_things()
- 打印:
about to print thing from executable (should print "new static lib"):
- 电话
print_thing()
如果我先连接dynamic
,然后连接static_new
,输出如下:
about to do things from executable
about to print thing from dynamic lib (should print "old static lib"): old static lib
about to print thing from executable (should print "new static lib"): old static lib
如果我先连接static_new
,然后连接dynamic
,输出如下:
about to do things from executable
about to print thing from dynamic lib (should print "old static lib"): new static lib
about to print thing from executable (should print "new static lib"): new static lib
在这两种情况下,我都无法告诉链接器,对于可执行文件,它应该在static_new
中查找print_thing
,对于共享库,它应该在static_old
中查找print_thing
。即使我们已经将static_new
的代码烘焙到可执行文件中(对吗?)和static_old
的代码烘焙到共享库中,对于整个可执行文件,链接器只能链接到其中一个。
当然,我不能简单地链接到定义相同符号的两个不同库,但不幸的是,在真实的场景中,共享库是一个预构建的二进制文件,我不能再次构建。那么,在编译executable
时,有没有一种方法可以告诉链接器不要在libdynamic
中查找print_thing
?或者某种方法从libdynamic
中删除print_thing
符号?
编辑:有人在这里描述了一个类似的问题:Linux/C++ shared libaries: Can I edit the sybol table, i.e. which symbols are exported?
我可能会尝试,但我真的不喜欢编辑共享库。
编辑2:经过一些尝试和错误,我设法将libdynamic.so
二进制文件中的一个print_thing
编辑为print_thong
,这就成功了:
about to do things from executable
about to print thing from dynamic lib (should print "old static lib"): old static lib
about to print thing from executable (should print "new static lib"): new static lib
但是,这真的不可靠,我不能简单地找到并替换二进制文件中的所有print_thing
,因为二进制文件中还有一个我不能编辑的print_thing
(否则执行失败):
about to do things from executable
./executable: symbol lookup error: /home/c/luizromario/local/linker_example/build/libdynamic.so: undefined symbol: print_thong
我仍然更愿意告诉链接器不要在libdynamic
中查找print_thing
编辑3:我可能会慢慢接近一个解决方案。
我发现了--exclude-libs
链接器选项,并像这样使用它:
target_link_options(dynamic PRIVATE "-Wl,--exclude-libs,libstatic_old.a")
最后的结果正是我想要的:
about to do things from executable
about to print thing from dynamic lib (should print "old static lib"): old static lib
about to print thing from executable (should print "new static lib"): new static lib
不幸的是,我需要一个非侵入性的解决方案,因为正如我提到的,我不能依赖于能够重新编译动态库
1条答案
按热度按时间0lvr5msh1#
查看
ld
的手册,我注意到以下选项:我设法用它来做我想做的事。这是棘手的,但它的工作足够可靠,* 我不需要篡改
libdynamic.so
*。1.将
--exclude-libs
链接选项添加到可执行文件:1.首先链接到
static_new
,然后链接到dynamic
。搞定了!
注意:**连接顺序很重要。**先连接
dynamic
,然后连接static_new
会导致执行失败:这是怎么回事
据我所知,
--exclude-libs ALL
告诉链接器,对于每个链接库,排除链接库导出的每个符号。所以,在我的例子中,ld
正在做的是:executable
链接到static_new
executable
中调用print_thing
将指向static_new
的print_thing
executable
中删除static_new
导出的所有符号executable
二进制文件中不再提供print_thing
executable
链接到dynamic
print_thing
的调用肯定会指向dynamic
的print_thing
,因为我们在前面的步骤中已经排除了static_new
的print_thing
dynamic
导出的所有符号秩序为何重要
链接
dynamic
首先失败,因为ld
将执行以下操作:executable
链接到dynamic
dynamic
同时导出print_thing
(从static_old
)和do_thing
,因此executable
中对这些符号的引用都将指向烘焙到libdynamic.so
中的代码executable
中删除dynamic
导出的所有符号print_thing
已经链接了executable
链接到static_new
print_thing
已经在步骤1中定义。static_new
导出的所有符号不幸的是,由于链接顺序的问题,我仍然没有设法解决我原来的项目中的问题,但我关闭这个项目,因为链接的具体问题已经解决了。