提问人:Romário 提问时间:9/29/2023 最后编辑:Romário 更新时间:10/3/2023 访问量:82
如何告诉链接者不要在链接的共享库中查找某些符号?
How to tell linker not to look for certain symbols in a linked shared library?
问:
我的情况如下:我们的程序依赖于大量共享(和静态)库。我想添加一个新的依赖项,这是一个静态库。程序编译没有问题,但在运行时崩溃。事实证明,新的静态库定义了一个符号,该符号在许多共享库之一中可用。因此,链接器链接到共享库而不是新的静态库 - 然后在运行时调用错误,导致崩溃。foo
foo
foo
foo
我创建了一个最小的示例来模拟这一点:https://gitlab.com/luizromario/linker_example
在那里,我们有:
- 一个名为 的库,包含一个打印
libstatic_old
print_thing()
old static lib
- 一个名为 的库,包含一个打印
libstatic_new
print_thing()
new static lib
- 一个名为 的共享库,它链接到 。它包含一个函数,该函数:
libdynamic
libstatic_old
do_things()
- 打印以下消息:
about to print thing from dynamic lib (should print "old static lib"):
- 调用
print_thing()
- 打印以下消息:
- 链接到 libdynamic 和 libstatic_new 的可执行文件。它:
executable
- 指纹:
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
在这两种情况下,我都无法告诉链接器,对于可执行文件,它应该查找 in,对于共享库,它应该查找 .即使我们有 baked 到 executable 中的代码(对吧?)和 baked 到 shared lib 中的代码,链接器也只能链接到整个可执行文件中的任何一个。print_thing
static_new
print_thing
static_old
static_new
static_old
当然,我根本无法链接到定义相同符号的两个不同库,但不幸的是,在实际场景中,共享库是一个预构建的二进制文件,我无法再次构建。那么,在编译的时候,有没有办法告诉链接器不要在里面找呢?或者以某种方式从中删除符号?executable
print_thing
libdynamic
print_thing
libdynamic
编辑:其他人在这里描述了类似的问题:Linux/C++ 共享库:我可以编辑 sybol 表,即导出哪些符号吗?
我可能会尝试这样做,但我真的不想编辑共享库。
编辑 2:经过一些反复试验,我设法将二进制文件中的一个 s 编辑成,这成功了:print_thing
libdynamic.so
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
不过,这真的很不可靠,我不能简单地找到并替换二进制文件中的所有 s,因为二进制文件中还有另一个我无法编辑(否则执行失败):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
我仍然更愿意告诉链接器不要在里面寻找print_thing
libdynamic
编辑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
不幸的是,我需要一个非侵入性的解决方案,因为正如我所提到的,我不能依赖能够重新编译动态库
答:
查看手册,我注意到以下选项:ld
--exclude-libs lib,lib,...
Specifies a list of archive libraries from which symbols should not
be automatically exported. The library names may be delimited by
commas or colons. Specifying "--exclude-libs ALL" excludes symbols
in all archive libraries from automatic export.
我设法用它来做我想做的事。这很棘手,但它工作足够可靠,我不需要篡改 libdynamic.so
。
- 将链接选项添加到可执行文件:
--exclude-libs
target_link_options(executable PRIVATE "-Wl,--exclude-libs,ALL")
- 首先链接到,然后链接到 。
static_new
dynamic
target_link_libraries(executable static_new dynamic)
做!
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
注意:链接顺序很重要。先链接后会使执行失败: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
这是怎么回事
据我了解,告诉链接器对于每个链接库,排除链接库导出的每个符号。所以,在我的例子中,正在做的是:--exclude-libs ALL
ld
- 链接到
executable
static_new
- 对 in 的调用将指向 的
print_thing
executable
static_new
print_thing
- 对 in 的调用将指向 的
- 从结果中排除导出的所有符号
static_new
executable
print_thing
在二进制文件中不再可用executable
- 链接到
executable
dynamic
- 调用 肯定会指向 的 ,因为我们在上一步中已经排除了 的
print_thing
dynamic
print_thing
static_new
print_thing
- 调用 肯定会指向 的 ,因为我们在上一步中已经排除了 的
- 排除导出的所有符号
dynamic
为什么订单很重要
首先链接失败,因为随后将执行以下操作:dynamic
ld
- 链接到
executable
dynamic
- 由于 export (from ) 和 ,因此对这些符号的引用都将指向烘焙到
dynamic
print_thing
static_old
do_thing
executable
libdynamic.so
- 由于 export (from ) 和 ,因此对这些符号的引用都将指向烘焙到
- 从结果中排除导出的所有符号
dynamic
executable
- 没关系,已经链接了
print_thing
- 没关系,已经链接了
- 链接到
executable
static_new
- 什么也没发生,在步骤 1 中已经定义了。
print_thing
- 什么也没发生,在步骤 1 中已经定义了。
- 排除导出的所有符号
static_new
不幸的是,由于链接排序问题,我仍然无法解决我原始项目中的问题,但我正在关闭它,因为链接的具体问题已经解决。
评论