dlsym()/dlopen() 的用法

Posted

技术标签:

【中文标题】dlsym()/dlopen() 的用法【英文标题】:Usage of dlsym()/dlopen() 【发布时间】:2014-05-14 11:59:10 【问题描述】:

我写了下一个程序:

#include <iostream>
#include <dlfcn.h>

int main(int argc, char** argv)

    typedef void* (*fptr)();
    fptr func;
    void *handle = dlopen(0, RTLD_NOW);
    std::cout << dlerror() << std::endl;    
    *(void **)(&func) = dlsym(handle, "__libc_start_main");
    std::cout << dlerror() << std::endl;

    std::cout << handle << " " << func << "\n";

    dlclose(handle);
return 0;

并尝试用下一种方式编译:

g++ -rdynamic main.cpp -ldl -o test

当我运行这个程序时,我没有看到任何消息。为什么?

感谢您的关注。

【问题讨论】:

【参考方案1】:

您的进程出错了,因为 dlerror() 仅在 error 条件下调用才有效,而您在调用之前从未验证过该情况实际发生过。

来自Linux docs:

函数dlerror() 返回一个人类可读的字符串,描述 从dlopen()dlsym()dlclose() 发生的最新错误 自上次致电dlerror() 以来。 如果没有错误则返回 NULL 自初始化或自上次调用以来发生。

换句话说,你的dlopen 成功了,所以从dlerror() 返回NULL。然后将该 NULL 作为char * 发送到std::cout 和kerboom。

底线:在调用 dlerror() 之前检查您的错误情况。试试这个:

#include <iostream>
#include <dlfcn.h>

int main(int argc, char** argv)

    typedef void* (*fptr)();
    fptr func;

    void *handle = dlopen(0, RTLD_NOW);
    if (handle == nullptr)
    
        std::cout << dlerror() << std::endl;
        exit(EXIT_FAILURE);
    

    func = (fptr)dlsym(handle, "__libc_start_main");
    if (!func)
    
        std::cout << dlerror() << std::endl;
        exit(EXIT_FAILURE);
    

    std::cout << handle << " " << func << "\n";

    dlclose(handle);
    return 0;

【讨论】:

【参考方案2】:

这是(可能)未定义的行为:

std::cout << dlerror() << std::endl; 

...除非dlerror 实际上是非空的(它可能不是)。应该是:

char* error = dlerror();
if (error != 0)
    std::cout << error << std::endl;

...或:

void *handle = dlopen(0, RTLD_NOW); 
if (handle == 0)
    std::cout << dlerror() << std::endl;

此外,如果dlerror 不为空(或handle 为空),您可能应该中止,因为在空handle 上调用dlsym 也是未定义的行为。

见Why does std::cout output disappear completely after NULL is sent to it。

【讨论】:

谢谢你。这是如何处理成员函数的最后一个问题。 typedef void (A::*fptr)();而不是尝试类似 func = (fptr)dlsym(handle, "test");比这是编译错误,因为他不知道如何将 void 转换为 fptr。你能帮我解决这个问题吗?

以上是关于dlsym()/dlopen() 的用法的主要内容,如果未能解决你的问题,请参考以下文章

用dlopen和dlsym得到的符号 在dlclose后还能继续使用么

C:尽管添加了 `-ldl` 标志,但未定义对 `dlopen`/`dlsym` 的引用

插件之dlopen/dlsym/dlclose 加载动态链接库

加载动态链接库——dlopen dlsym dlclose

dlopen / dlsym函数(动态链接库)

dlopen / dlsym函数(动态链接库)