调用共享库(Linux)中的函数会出现Segmentation Fault
Calling function in shared library (Linux) get Segmentation Fault
我试图写一个共享库打开和函数调用的基本示例来练习,但事实证明,当executable实际运行时,我总是会遇到"分段错误"。以下是源代码:
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<<"1n"<<flush;break;
case 1:cout<<"2n"<<flush;break;
case 2:cout<<"4n"<<flush;break;
case 4:cout<<"16n"<<flush;break;}}
我用以下命令编译了两部分:
g++ -shared -o pluginA.so -fPIC plugin.cpp
g++ main.cpp -ldl
这是输出
Segmentation fault (core dumped)
顺便说一句,我还试着直接调用api(tmp),而不是(*api)(tmp),这也不起作用。既然api是一个指针,(*api)更有意义吗?
我不知道该怎么办。网上有很多关于在共享库中调用函数的文章,但大多数都没有完全编码,或者实际上不起作用。
此外,我也不确定该如何处理"属性((可见性("默认"))"。我应该把它写下来吗?
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]=' ';}
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;}
您应该阅读dlopen(3)和dlsym
的文档,并且您应该始终处理故障。所以编码
dl=dlopen("./pluginA.so",RTLD_LAZY);
if (!dl) { fprintf(stderr, "dlopen failure: %sn", dlerror());
exit (EXIT_FAILURE); };
api=(API)dlsym(dl,"API");
if (!api) { fprintf(stderr, "dlsym failure: %sn", 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的论文:如何编写共享库。
我修改了您的代码并使用了错误检查。尝试一下,了解发生了什么:
#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",或者将完整的路径放在你的插件上。
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- Seg Fault Issue C++ (file IO / getline)
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 创建一个简单的类及其变量和函数不断返回" segmentation fault (core dumped)"、C++
- "Segmentation fault"使用 Cmake 在C++代码中运行 python 函数时
- 调用构造函数定义中的函数后收到Segmentation Fault 11错误
- 调用共享库(Linux)中的函数会出现Segmentation Fault
- 甚至调用Segmentation Fault Before函数