gpt4 book ai didi

c++ - 带有带有dlopen的共享库的不同数学符号绑定(bind),并直接链接到可执行文件(Linux)

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:38:10 28 4
gpt4 key购买 nike

我有两个在Linux上使用的共享库libA和libB,它们以两种方式使用:
1.作为共享库直接链接到“脱机”测试可执行文件。
2.在实际应用程序中使用:辅助包装器库(libWrapper)与libA和libB链接,该应用程序使用系统调用dlopen("libWrapper.so", RTLD_NOW | RTLD_LOCAL)仅打开包装器lib。

问题:库运行复杂的图像分析算法,有时数值结果不相等。
我应该找到一种方法来确保测试可执行文件给出的结果与真实应用程序相同,但是我不允许更改库或真实应用程序,而只能更改测试可执行文件。

我使用LD_DEBUG = bindings来查找输出的差异(到stderr):

$ grep acosf log-bindings.test-executable  # *"offline" test executable*
binding file libB.so to libA.so: normal symbol `acosf.J'
binding file libB.so to libA.so: normal symbol `acosf.A'
binding file libA.so to libA.so: normal symbol `acosf.J'
binding file libA.so to libA.so: normal symbol `acosf.A'
binding file libB.so to libA.so: normal symbol `acosf' <<<<<<<
binding file libA.so to libA.so: normal symbol `acosf' <<<<<<<


$ grep acosf log-bindings.process # logging from *real process*
binding file libB.so to libA.so: normal symbol `acosf.J'
binding file libB.so to libA.so: normal symbol `acosf.A'
binding file libB.so to libB.so: normal symbol `_ZSt4acosf' # std::acosf
binding file libB.so to **libm**.so.6: normal symbol `acosf' <<<<<<
binding file libA.so to libA.so: normal symbol `acosf.J'
binding file libA.so to libA.so: normal symbol `acosf.A'
binding file libA.so to **libm**.so.6: normal symbol `acosf' <<<<<<

(为了清楚起见,删除了路径)

这表明,在实际的应用程序 中,使用了许多数学函数符号(cos,cosf,exp,expf,sin,sinf,acos...。) 从系统数学库libm 中使用,同时进行了测试可执行文件的绑定(bind)从libB到库libA,从libA到libA本身。这可能是造成差异的原因。

我可以以acosf()函数为例:
使用链接器选项-y acosf时,我们通过将-Wl,yacosf传递给编译器来获得输出:
release/libBdl/lib/libA.so: definition of acosf
release/libBdl/lib/libB.so: reference to acosf

我使用nm工具在库中显示符号:
$ nm  libA/libA.so | grep acosf
00665200 T acosf # impl. of acosf (text symbol)
0066c360 T acosf.A
0066c55c T acosf.J
00271fae t _Z13acosf_checkedf # acosf_checked(float)
00708244 r _Z13acosf_checkedf$$LSDA

$ nm libB/libB.so | grep acosf
01423780 T acosf # impl. of acosf (text symbol)
01424410 T acosf.A
0142460c T acosf.J
004c1b3a W _ZSt4acosf
01547eec r _ZSt4acosf$$LSDA

尽管发行计算机上的math lib没有符号,但我假设libm的方法是相同的:它在lib中定义了弱符号expf或acosf,用户应该可以在自己的lib中使用强符号覆盖它们:
[newer CentOS7 system]$ nm /usr/lib/libm.so|grep acosf
0001b9c0 W acosf # weak symbol 'acosf'
0001b9c0 t __acosf # strong symbol / implementation
000176b0 T __acosf_finite
000176b0 t __ieee754_acosf # called by __acosf in libm

[newer CentOS7 system]$ nm /usr/lib/libm.so|grep expf
0001bc60 W expf # weak symbol 'expf'
0001bc60 t __expf # strong symbol / implementation
00017990 i __expf_finite
0002d370 t __expf_finite_ia32
0002d1b0 t __expf_finite_sse2
00017960 i __ieee754_expf # called by __expf in libm
0002d330 t __ieee754_expf_ia32
0002d1b0 t __ieee754_expf_sse2

readelf -Ws .. | grep acosf结果:
test-executable:
--

real-application:
--

libWrapper.so:
--

libB.so:
3934: 004c12a6 40 FUNC WEAK DEFAULT 10 _ZSt4acosf
5855: 01423b80 506 FUNC GLOBAL DEFAULT 10 acosf.A
10422: 01423d7c 666 FUNC GLOBAL DEFAULT 10 acosf.J
14338: 01422ef0 40 FUNC GLOBAL DEFAULT 10 acosf

libA.so:
2333: 0066c1e8 506 FUNC GLOBAL DEFAULT 10 acosf.A
4179: 0066c3e4 666 FUNC GLOBAL DEFAULT 10 acosf.J
5772: 00665088 40 FUNC GLOBAL DEFAULT 10 acosf

我认为,符号绑定(bind)的问题是 https://en.wikipedia.org/wiki/Weak_symbol在“限制”部分中描述的典型Unix system-V问题。使用dlopen(),动态链接程序更喜欢libm及其弱符号,因为它已被加载,尽管libA“稍后”中提供了强符号。


LD_DEBUG = all:
test-executable:

symbol=expf; lookup in file=./test-executable.shared
symbol=expf; lookup in file=/lib/libdl.so.2
symbol=expf; lookup in file=/home/test/test/bin_NDEBUG/libA/libA.so
binding file libB.so to libA.so: normal symbol `expf' <<<<

symbol=acosf; lookup in file=./test-executable.shared
symbol=acosf; lookup in file=/lib/libdl.so.2
symbol=acosf; lookup in file=/home/test/test/bin_NDEBUG/libA/libA.so
binding file libA.so to libA.so: normal symbol `acosf' <<<<



real-application:

symbol=expf; lookup in file=real-application
symbol=expf; lookup in file=/home/test/lib/libX1.so
symbol=expf; lookup in file=/home/test/lib/libX2.so
symbol=expf; lookup in file=/home/test/lib/libX3.so
symbol=expf; lookup in file=/home/test/lib/libX4.so
symbol=expf; lookup in file=/lib/libdl.so.2
symbol=expf; lookup in file=/usr/lib/libstdc++.so.5
symbol=expf; lookup in file=/home/test/lib/libX5.so
symbol=expf; lookup in file=/lib/i686/libm.so.6
binding file libA.so to libm.so.6: normal symbol `expf' <<<<<<<


symbol=acosf; lookup in file=real-application
symbol=acosf; lookup in file=/home/test/lib/libX1.so
symbol=acosf; lookup in file=/home/test/lib/libX2.so
symbol=acosf; lookup in file=/home/test/lib/libX3.so
symbol=acosf; lookup in file=/home/test/lib/libX4.so
symbol=acosf; lookup in file=/lib/libdl.so.2
symbol=acosf; lookup in file=/usr/lib/libstdc++.so.5
symbol=acosf; lookup in file=/home/test/lib/libX5.so
symbol=acosf; lookup in file=/lib/i686/libm.so.6
binding file libA.so to libm.so.6: normal symbol `acosf' <<<<<<

辅助库“libWrapper”链接到libA和libB,但没有符号acosf。

该平台是使用内核2.4和glibc 2.2.5的旧32位Linux(是的,2001年!)。

库A和库B是使用带有选项-O3,NDEBUG的Intel Icc编译器构建的。使用DEBUG似乎没有问题。与共享链接相比,静态/归档版本的结果略有不同。

使用g++(或icc,没有区别)将测试可执行文件直接链接到共享库libA和libB。
我试图通过使用LD_PRELOAD或各种链接程序标志来使测试可执行文件还将数学符号也绑定(bind)到libm,但这并没有改变。

我的假设:真正的应用程序中的dlopen调用确实要晚得多,这是在加载了常规库(和libm)并启动了应用程序之后。如果在先前加载的库中已经找到符号,则首选符号,尽管该符号在libA中存在一个弱符号,而一个强符号可用。可能这只是旧Linux的行为,但是“限制”部分中的 Wikipedia article on weak symbols描述了Unix system-V之类的系统的链接器的这种弱点。

我试过了
linker option -Wl,--no-whole-archive 
define LD_BIND_NOW
define LD_PRELOAD=libm.so

对于test-executable,但这对符号绑定(bind)没有影响:
symbol=acosf;  lookup in file=./test-executable.shared
symbol=acosf; lookup in file=/lib/i686/libm.so.6
symbol=acosf; lookup in file=/lib/libdl.so.2
symbol=acosf; lookup in file=libA.so
binding file libA.so to libA.so: normal symbol `acosf'

我的问题:为什么,即使使用LD_PRELOAD,test-executable也不会更改,并坚持使用(libA)的库内实现,但是使用dlopen它会使用libm符号吗?以及如何强制test-executable的行为与真实应用程序相同,即使用libm符号?

遗憾的是,dlopen的几个现代标志不可用,并且链接器未命中例如。 --exclude-symbols。
此外,LD_DYNAMIC_WEAK环境变量在旧Linux上不可用。
可能唯一的解决方案是也重写测试可执行文件以使用dlopen。

任何想法表示赞赏。

最佳答案

I am not permitted to change the libraries or the real application.



如果不允许您进行任何更改,则无法解决问题。

I used LD_DEBUG=bindings to find differences, and found that ...


LD_DEBUG是调试此工具的错误工具。请改用GDB。

在上设置断点 cos,运行两个二进制文件,并确认它们实际上正在执行不同的代码。一旦您知道其中一种情况下的 cos位于 libA中(我无法完全解析您的描述,但是我认为这就是您声称已经观察到的内容),请弄清楚它如何进入 libA中(使用链接器标记 -Wl,-y,cos来确定)。

符号可见性可能是其中一个原因,这就是符号分辨率表现不同的原因。用于链接prod-exe,test-exe,libA.so和libB.so的确切命令行可能很重要。运行 readelf -Ws prot-exe test-exe libA.so libB.so | grep ' cos$'可能也很有启发。

掌握所有信息后(并假设您仍然无法理解正在发生的事情),请提出一个新问题,并提供更详细的观测记录。

关于c++ - 带有带有dlopen的共享库的不同数学符号绑定(bind),并直接链接到可执行文件(Linux),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57632394/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com