C++ 不同的数学符号绑定与dlopen共享库并直接链接到可执行文件(Linux)

C++ 不同的数学符号绑定与dlopen共享库并直接链接到可执行文件(Linux),c++,binding,linker,shared-libraries,dlopen,C++,Binding,Linker,Shared Libraries,Dlopen,我在Linux上使用了两个共享库libA和libB,它们有两种使用方式: 1.作为共享库直接链接到“脱机”测试可执行文件。 2.在实际应用程序中使用:辅助包装库(libWrapper)与libA和libB链接,应用程序使用系统调用dlopen(“libWrapper.so”,RTLD_NOW | RTLD_LOCAL)仅打开包装库 问题:库运行复杂的图像分析算法,有时数值结果不相等。 我应该找到一种方法来确保测试可执行文件给出与实际应用程序相同的结果,但我不允许更改库或实际应用程序,只能更改测试

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

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

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

我使用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
尽管版本计算机上的数学库没有符号,但我假设libm的方法是相同的:它在库中定义弱符号expf或acosf,用户应该能够在自己的库中用强符号覆盖它们:

[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
我认为,符号绑定的问题是“限制”一节中描述的典型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'  <<<<<<
对于测试可执行文件,但这对符号绑定没有影响:

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,测试可执行文件也不会改变并坚持(libA的)库内实现,但使用dlopen它使用libm符号?!?我如何才能强制测试可执行文件与实际应用程序的行为相同,即使用libm符号

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

欢迎提出任何意见

我不允许更改库或实际应用程序

如果不允许您更改任何内容,则无法解决问题

我使用LD_DEBUG=bindings查找差异,并发现

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$”
也可能会有所启发


一旦你掌握了所有的信息(并且假设你仍然无法理解发生了什么),问一个新问题,并记录更详细的观察结果。

我想我可以自己回答这个问题

实际应用程序中的
dlopen
调用在加载常用库(和libm)并启动应用程序执行之后,确实要晚得多。如果在先前加载的lib中已经找到符号,则首选符号,尽管libA中有弱符号和强符号(稍后在程序执行中通过dlopen加载)。“限制”一节中关于弱符号的讨论描述了动态链接器ld-linux.so对于类Unix system-V系统(在本例中为linux)的这种弱点。 使用LD_DEBUG=您可以看到链接器如何搜索符号


在这种情况下,如果不能更改原始应用程序和共享LIB(链接器标志、导出方式和符号),唯一的解决方案仍然是重写测试可执行文件,使其也使用dlopen(作为实际应用程序)。

谢谢您的评论。明天早上我将测试gdb和readelf。关于LD_DEBUG,它被列在LD.so中,作为“关于动态链接器的输出详细调试信息”,这在我看来似乎就是我要寻找的。我在问题中添加了更多信息,希望现在更清楚。我被允许更改测试可执行文件,但实际应用程序或libs A和B.gdb都不能在目标系统上工作:“B acosf”-->错误:“无法访问地址0x4处的内存…”readelf-Ws…|grep acosf结果:test-executable.shared:(nothing)real application:(nothing)libWrapper.so:(nothing)libB.so:3934:004c12a6 40 FUNC弱默认10_ZSt4acosf 5855:01423b80 506 FUNC全局默认10 acosf.a0422:01423d7c 666 FUNC全局默认10 acosf.J 14338:01422ef0 40 FUNC全局默认10 acosf libA.so:2333:0066c1e8 506 FUNC全局默认10 acosf.A 4179:0066c3e4 666 FUNC全局默认值10 acosf.J 5772:00665088 40 FUNC全局默认值10 acosfreedelf-Ws..grep acosf结果:测试可执行文件:-实际应用程序:-libWrapper.so:--libB.so:3934:004c12a6 40 FUNC弱默认值10_ZSt4acosf 5855:01423b80 506 FUNC全局默认值10 acosf.A10422:01423d7c 666函数全局默认值10 acosf.J 14338:01422ef0 40函数全局默认值10 acosf libA.so:2333:0066c1e8 506函数全局默认值10 acosf.A 41
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'  <<<<<<
linker option -Wl,--no-whole-archive 
define LD_BIND_NOW 
define LD_PRELOAD=libm.so 
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'