dlopen配置RTLD_DEEPBIND

对联调时看到的问题做简单记录,以免日后踩坑;

首先是一些相关概念和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则输出:
dlopen配置RTLD_DEEPBIND
否则:
dlopen配置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 相同功能的业务代码,如果使用了不同模块,应当用编译宏彻底隔离开,而非以解决编译问题为目标进行修改。

上一篇:13. 罗马数字转整数 - LeetCode


下一篇:R语言之S3系统(详细介绍)*程序输出改进