我试图写一个共享库打开和函数调用练习的基本示例,但事实证明,当exectuable实际运行时,我总是得到“分段错误”。以下是源代码:
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;
}
pluginA.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)
我不知道该怎么办。有很多关于在线共享库中调用函数的总数,但是大多数都没有完全编码,或者它们实际上不起作用。
而且我也不确定我应该用“属性((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;}
答案 0 :(得分:3)
您应该阅读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
链接起来非常有用,以便插件可以访问其符号)
您可能希望在dlclose(dl)
结束前main
...(如果您dlsym
,则dlclose
- ed函数调用或返回会导致您的程序崩溃太早了)。您甚至可以避免dlclose
(即接受一些资源泄漏)。根据经验,您通常可以dlopen
数十万个共享对象(请参阅我的manydl.c)
只有在调试程序后,您才可以添加一些优化标记,如-O
或-O2
(也许可以删除调试标记-g
,但我不建议初学者使用)
答案 1 :(得分:1)
我纠正了你的代码并使用错误检查。试试这个并了解发生了什么:
#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;
}
最后:为什么失败了?使用正确的路径:&#34; ./ pluginA.so&#34;,而不是&#34; pluginA.so&#34;或者将完整路径放到插件中。