【问题标题】:Calling function in shared library (Linux) get Segmentation Fault共享库(Linux)中的调用函数得到分段错误
【发布时间】:2014-12-25 14:59:40
【问题描述】:

我试图编写一个共享库打开和函数调用的基本示例以进行练习,但事实证明,当可执行文件实际运行时,我总是遇到“分段错误”。以下是源代码:


main.cpp:

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

using namespace std;

typedef void (*API)(unsigned int);

int main(int argc,char** argv){

    void* dl;
    API api;
    unsigned int tmp;

    //...

    dl=dlopen("pluginA.so",RTLD_LAZY);
    api=(API)dlsym(dl,"API");

    cin>>tmp;
    (*api)(tmp);

    dlclose(dl);

    //...

    return 0;

    }

插件A.cpp:

#include<iostream>
using namespace std;
extern "C" void API(unsigned int N){switch(N){
    case 0:cout<<"1\n"<<flush;break;
    case 1:cout<<"2\n"<<flush;break;
    case 2:cout<<"4\n"<<flush;break;
    case 4:cout<<"16\n"<<flush;break;}}

我用以下命令编译了这两部分:

g++ -shared -o pluginA.so -fPIC plugin.cpp
g++ main.cpp -ldl

这是输出

Segmentation fault (core dumped)

顺便说一句,我也尝试直接调用 api(tmp) 而不是 (*api)(tmp),这也不起作用。既然api是​​指针,(*api)就更有意义了?


我不确定我应该怎么做。网上有很多关于共享库中调用函数的教程,但大部分都没有完全编码,或者实际上不起作用。

而且我也不确定我应该如何处理“attribute((visibility("default")))”。我应该把它写下来吗?


EDT1 谢谢你给我这么多建议。终于发现其实一切都是编译命令的错别字……我把pluginA.so误打成了pluginA.o,这就是它不起作用的原因……

无论如何,这是我修改后的程序,添加了错误处理,并添加了更“完整”的系统:

main.cpp:

#include<dirent.h>
#include<dlfcn.h>
#include<iostream>
#include<cstring>
using namespace std;

typedef bool (*DLAPI)(unsigned int);

int main(){

    DIR* dldir=opendir("dl");
    struct dirent* dldirf;
    void* dl[255];
    DLAPI dlapi[255];
    unsigned char i,dlc=0;
    char dldirfname[255]="./dl/";
    unsigned int n;

    while((dldirf=readdir(dldir))!=NULL){
        if(dldirf->d_name[0]=='.')continue;
        strcat(dldirfname,dldirf->d_name);
        dl[dlc]=dlopen(dldirfname,RTLD_LAZY);
        if(!dl[dlc])cout<<dlerror()<<endl;else{
            dlapi[dlc]=(DLAPI)dlsym(dl[dlc],"API");
            if(!dlapi[dlc])cout<<dlerror()<<endl;else dlc++;}
        dldirfname[5]='\0';}

    if(dlc==0){
        cerr<<"ERROR:NO DL LOADED"<<endl;
        return -1;}

    while(true){
        cin>>n;
        for(i=0;i<dlc;i++)if((*dlapi[i])(n))break;
        if(i==dlc)cout<<"NOT FOUND"<<endl;}

    for(i=0;i<dlc;i++)dlclose(dl[i]);

    return 0;}

【问题讨论】:

    标签: c++ linux


    【解决方案1】:

    您应该阅读dlopen(3)dlsym 的文档,并且您应该始终处理故障。所以代码

    dl=dlopen("./pluginA.so",RTLD_LAZY);
    if (!dl) { fprintf(stderr, "dlopen failure: %s\n", dlerror()); 
               exit (EXIT_FAILURE); };
    api=(API)dlsym(dl,"API");
    if (!api)  { fprintf(stderr, "dlsym failure: %s\n", dlerror()); 
               exit (EXIT_FAILURE); };
    

    dlopen 的文档解释了为什么要使用 ./ 前缀传递 ./pluginA.so

    最后,您应该始终使用所有警告和调试信息进行编译,所以:

    g++ -Wall -Wextra -g -shared -o pluginA.so -fPIC plugin.cpp
    g++ -Wall -Wextra -g -rdynamic main.cpp -ldl
    

    (将主程序链接到-rdynamic 以便插件可以访问其符号很有用)

    你可能想在main 结束之前dlclose(dl) ...(如果你过早地dlclose 调用或从dlsym-ed 函数返回会使你的程序崩溃)。你甚至可以避免dlclose(即接受一些资源泄漏)。根据经验,您通常可以dlopen 数十万个共享对象(请参阅我的manydl.c

    只有在您的程序被调试后,您才能添加一些优化标志,如 -O-O2(也可能删除调试标志 -g,但我不建议初学者这样做)。

    您或许应该阅读Drepper's paper: How To Write Shared Libraries

    【讨论】:

      【解决方案2】:

      我稍微更正了您的代码并使用了错误检查。尝试一下并了解发生了什么:

      #include<iostream>
      #include<dlfcn.h>
      
      using namespace std;
      
      typedef void (*API)(unsigned int);
      
      int main(int argc,char** argv)
      {
      
        API api;
        unsigned int tmp;
      
        //...
      
        void* handle = dlopen("pluginA.so", RTLD_LAZY);
        if (!handle)
        {
          std::cerr << dlerror() << std::endl;
          return 1;
        }
      
        dlerror();
      
        api = reinterpret_cast<API>(dlsym(handle, "API"));
        if (!api)
        {
          std::cerr << dlerror() << std::endl;
          return 2;
        }
      
        cin>>tmp;
        (*api)(tmp);
      
        dlclose(handle);
      
          //...
      
        return 0;
      
      }
      

      最后:为什么失败了?使用正确的路径:“./pluginA.so”,而不是“pluginA.so”,或者输入插件的完整路径。

      【讨论】:

        猜你喜欢
        • 2021-04-13
        • 2023-03-12
        • 1970-01-01
        • 2010-11-13
        • 2018-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多