如何告知链接器不在已链接的共享库中查找指定符号?
符号冲突引发的链接问题及非侵入式解决方案探索
问题背景
我们的程序依赖大量共享库与静态库。新增一个静态库依赖后,编译正常但运行时崩溃。排查发现,新静态库定义的符号foo与某共享库中的同名符号冲突,链接器最终选择了共享库的foo版本,导致运行时调用错误函数触发崩溃。
最小复现示例
我搭建了一个最小示例复现该问题,组件如下:
libstatic_old静态库:包含单个函数print_thing(),输出内容为old static liblibstatic_new静态库:包含单个函数print_thing(),输出内容为new static liblibdynamic共享库:链接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()
- 输出:
不同链接顺序的输出结果
- 先链接
libdynamic再链接libstatic_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
可执行文件调用print_thing()时,错误使用了共享库中的版本。
- 先链接
libstatic_new再链接libdynamic
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
共享库调用print_thing()时,错误使用了新静态库中的版本。
两种方式都无法实现预期:让可执行文件从libstatic_new查找print_thing,同时让共享库从libstatic_old查找该符号。即便libstatic_new的代码已嵌入可执行文件、libstatic_old的代码已嵌入共享库,链接器仍会为整个进程全局选择一个符号版本。
需求与尝试
实际场景中,libdynamic是预编译的二进制文件,无法重新构建。我希望找到以下两种方案之一:
- 编译
executable时,告知链接器不要在libdynamic中查找print_thing符号; - 无需修改共享库本身,移除或隐藏
libdynamic中的print_thing符号。
尝试1:参考同类问题方案
曾发现同类问题的解决方案,但该方案需要修改共享库,不符合我的非侵入式需求。
尝试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符号,会触发未定义符号错误:
about to do things from executable ./executable: symbol lookup error: /home/c/luizromario/local/linker_example/build/libdynamic.so: undefined symbol: print_thong
尝试3:使用--exclude-libs链接器选项
我发现了--exclude-libs链接器选项,通过CMake配置:
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
但该方案需要重新编译libdynamic共享库,不符合我对非侵入式方案的需求。
内容的提问来源于stack exchange,提问作者Romário
相关产品推荐
相关产品推荐

