dlopen的身份

  • dlopen用于加载动态分享库:happy:,其函数声明如下

    1
    2
    3
    4
    #include <dlfcn.h>
    void *dlopen(const char *filename, int flags);

    int dlclose(void *handle);

    参数filename指定了需要加载的分享库,flags指定了加载的模式。

  • 执行成功时,函数返回一个共享库文件的handle;若执行出错,则返回NULL。

flags一二说

  • flags参数用来指定加载模式,主要有如下的几种区分。如果想使用不同层面的模式组合,使用按位或即可。:sunglasses:

  • RTLD_LAZY VS. RTLD_NOW

    RTLD_LAZY指定共享库在其中的符号被引用时,才会真正地加载共享库。而RTLD_NOW是立刻加载。

    需要注意RTLD_LAZY的效果会被LD_BIND_NOW的效果掩盖。

  • RTLD_LOCAL VS. RTLD_LOCAL

    RTLD_LOCAL规定此次加载的共享库的动态符号,在后面加载的其他共享库中可以使用。例如顺序加载函数func1func2,那么func2中使用了func1是被允许的。

    RTLD_LOCAL与RTLD_LOCAL刚好相反,它不允许。

  • RTLD_NODELETE

    如果指定RTLD_NODELETE,那么即使handle被dlclose(),加载的共享库实际也不会被删掉。

  • RTLD_NOLOAD

    意味着此次是加载,实际上没有加载。

    问:为什么设置这个功能,有什么用?

    答:可根据返回值类型判断是否存在共享库!

dlopen的使用:grinning:

  • 首先,需要说明的一点是,使用dlopen的源代码在编译时需要加上-ldl选项

  • 一套连招使用方法是:

    • 使用mkstemp family系统调用创建一个新的文件,然后将某段主角代码写进去。
    • 在程序中通过exec family系统调用来调用gcc,添加正确的编译选项,将第一招里创建的文件编译成共享库。
    • :laughing:使用dlopen加载共享库!并且根据使用目的选择合适的flags。
    • 得到handle之后,即可使用dlsym系统调用得到symbol的地址,也就是函数指针!得到函数指针之后可以尽情地调用函数。
    • 根据目的选择是否要dlclose。
  • RTFM标准样例代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    int main(void) {
    void *handle;
    double (*cosine)(double);
    char *error;

    handle = dlopen(LIBM_SO, RTLD_LAZY);
    if (!handle) {
    fprintf(stderr, "%s\n", dlerror());
    exit(EXIT_FAILURE);
    }

    dlerror(); /* Clear any existing error */

    cosine = (double (*)(double)) dlsym(handle, "cos");

    error = dlerror();
    if (error != NULL) {
    fprintf(stderr, "%s\n", error);
    exit(EXIT_FAILURE);
    }

    printf("%f\n", (*cosine)(2.0));
    dlclose(handle);
    exit(EXIT_SUCCESS);
    }