对联调时看到的问题做简单记录,以免日后踩坑;
首先是一些相关概念和demo相关代码:
RTLD_DEEPBIND (since glibc 2.3.4)
Place the lookup scope of the symbols in this shared object ahead of the global scope. This means that a self-con‐
tained object will use its own symbols in preference to global symbols with the same name contained in objects that
have already been loaded.
testbind.c:
#include <stdio.h>
#include "testbind.h"
int CheckA()
{
return CheckDlib();
}
testbind2.c:
#include <stdio.h>
int CheckDlib()
{
printf("testfunc.\n");
return 0;
}
testlocal.c:
#include "stdio.h"
#include "testlocal.h"
int CheckDlib()
{
printf("local func\n");
return 0;
}
主函数:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include "testlocal.h"
#define TEST_LIB_PATH "libtestbind.so"
typedef int (*testFunc) ();
int RunCheck()
{
void *handle;
testFunc func;
char *error;
handle = dlopen(TEST_LIB_PATH, RTLD_LAZY | RTLD_DEEPBIND);
//handle = dlopen(TEST_LIB_PATH, RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(1);
}
dlerror(); /* Clear any existing error */
func = (testFunc) dlsym(handle, "CheckA");
/* According to the ISO C standard, casting between function
pointers and 'void *', as done above, produces undefined results.
POSIX.1-2003 and POSIX.1-2008 accepted this state of affairs and
proposed the following workaround:
*(void **) (&cosine) = dlsym(handle, "cos");
This (clumsy) cast conforms with the ISO C standard and will
avoid any compiler warnings.
The 2013 Technical Corrigendum to POSIX.1-2008 (a.k.a.
POSIX.1-2013) improved matters by requiring that conforming
implementations support casting 'void *' to a function pointer.
Nevertheless, some compilers (e.g., gcc with the '-pedantic'
option) may complain about the cast used in this program. */
error = dlerror();
if (error != NULL) {
fprintf(stderr, "%s\n", error);
exit(1);
}
CheckDlib();
printf("check a \n");
(*func)();
dlclose(handle);
exit(0);
}
int main()
{
RunCheck();
return 0;
}
背景:testbind.c和testbind2.c可看作两个不同的模块,以动态库的形式供外部使用;libtestbind.so又依赖于libtestbind2.so,显然对于libtestbind.so期望的是使用libtestbind2.so中的CheckDlib,然而实际应用中由于项目侧代码自己定义了一个同名的函数,导致libtestbind.so调用到了项目侧的这个函数,而与预期的运行结果不符:
gcc testbind2.c -o libtestbind2.so -fPIC -shared
gcc testbind.c -o libtestbind.so -fPIC -shared -L./ -ltestbind2
gcc -L/xxxx testmain.c -ltestbind -ldl
使用RTLD_DEEPBIND则输出:
否则:
再看一遍
This means that a self-contained object will use its own symbols in preference to global symbols with the same name contained in objects that have already been loaded.
即加入该选项后,动态库在使用符号的时候,优先选择内部符号,而非全局符号;
个人认为在一个项目中其实该问题完全可以避免:
1 各个模块在函数命名时要根据模块名称添加前缀;
2 相同功能的业务代码,如果使用了不同模块,应当用编译宏彻底隔离开,而非以解决编译问题为目标进行修改。