linux 平台加载动态库通常使用dlopen,dlsym,dlclose三个函数实现

最近写了一个小程序,遇到dlsym总是调用失败返回空值,查找了很多相关的资料,确定动态库的创建有问题、下面是最初版的 有问题的动态库代码:

dlldemo_global.h

#ifndef DLLDEMO_GLOBAL_H
#define DLLDEMO_GLOBAL_H#include <QtCore/qglobal.h>#if defined(DLLDEMO_LIBRARY)
#  define DLLDEMOSHARED_EXPORT Q_DECL_EXPORT
#else
#  define DLLDEMOSHARED_EXPORT Q_DECL_IMPORT
#endif#endif // DLLDEMO_GLOBAL_H

dlldemo.h

#ifndef DLLDEMO_H
#define DLLDEMO_H#include "dlldemo_global.h"//导出函数
DLLDEMOSHARED_EXPORT  int   Add(int a,int b);
DLLDEMOSHARED_EXPORT  int   Sub(int a,int b);class DLLDEMOSHARED_EXPORT DLLDemo
{public:DLLDemo();};#endif // DLLDEMO_H

dlldemo.cpp

#include "dlldemo.h"DLLDemo::DLLDemo()
{
}int Add(int a,int b)
{return a+b;
}int Sub(int a,int b)
{return a-b;
}

这样导出来的库中的函数已经发生了变化,可以通过nm libDLLDemo.so来查看

root@scada:/home/work/DLLDemo/lib# nm libDLLDemo.so
0000000000200b30 B __bss_start
0000000000200b30 b completed.6903w __cxa_finalize@@GLIBC_2.2.5
0000000000000660 t deregister_tm_clones
00000000000006f0 t __do_global_dtors_aux
0000000000200890 t __do_global_dtors_aux_fini_array_entry
0000000000200b28 d __dso_handle
00000000002008a0 d _DYNAMIC
0000000000200b30 D _edata
0000000000200b38 B _end
0000000000000794 T _fini
0000000000000730 t frame_dummy
0000000000200888 t __frame_dummy_init_array_entry
0000000000000880 r __FRAME_END__
0000000000200b00 d _GLOBAL_OFFSET_TABLE_w __gmon_start__
0000000000000610 T _initw _ITM_deregisterTMCloneTablew _ITM_registerTMCloneTable
0000000000200898 d __JCR_END__
0000000000200898 d __JCR_LIST__w _Jv_RegisterClassesU qt_version_tag@@Qt_5.7
00000000000006a0 t register_tm_clones
0000000000200b30 d __TMC_END__
000000000000076b T _Z3Addii
000000000000077f T _Z3Subii
0000000000000760 T _ZN7DLLDemoC1Ev
0000000000000760 T _ZN7DLLDemoC2Ev
000000000000079d r _ZStL19piecewise_construct

发现Add函数已经变成了_ZNAddii,Sub函数变成了_ZNSubii,这样在动态引用时dlsym时总是返回null。下面是修饰规则:

DLL(动态库)导出函数名乱码含义
C++编译时函数名修饰约定规则:    __stdcall调用约定:    1、以"?"标识函数名的开始,后跟函数名;   2、函数名后面以"@@YG"标识参数表的开始,后跟参数表;  3、参数表以代号表示:    X--void D--char E--unsigned char F--short H--int I--unsigned int J--long K--unsigned long M--float N--double _N--bool ....    PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以"0"代替,一个"0"代表一次重复;4、参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;    5、参数表后以"@Z"标识整个名字的结束,如果该函数无参数,则以"Z"标识结束。    其格式为"[email protected]@YG*****@Z"或"[email protected]@YG*XZ",例如    int Test1(char *var1, unsigned long)[email protected]@[email protected]void Test2()-----"[email protected]@YGXXZ" __cdecl调用约定:    规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YA"。    __fastcall调用约定:    规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YI"。  如果要用DEF文件输出一个"C++"类,则把要输出的数据和成员的修饰名都写入.def模块定义文件    所以...   通过def文件来导出C++类是很麻烦的,并且这个修饰名是不可避免的

怎么办呐?为什么呐?

这是因为在导出函数时使用的g++编译器,导出时自动加上约定的符号,为了使用原生的函数名,因此将导出函数名时加上extern “C”,表明使用gcc编译器,这样导出的函数名就不会改变了。以下是改过的头文件dlldemo.h代码:

#ifndef DLLDEMO_H
#define DLLDEMO_H#include "dlldemo_global.h"//导出函数
extern "C" DLLDEMOSHARED_EXPORT  int   Add(int a,int b);
extern "C" DLLDEMOSHARED_EXPORT  int   Sub(int a,int b);class DLLDEMOSHARED_EXPORT DLLDemo
{public:DLLDemo();};#endif // DLLDEMO_H

我们再来看看导出函数名吧:

root@scada:/home/work/DLLDemo/lib# nm libDLLDemo.so
000000000000076b T Add
0000000000200b30 B __bss_start
0000000000200b30 b completed.6903w __cxa_finalize@@GLIBC_2.2.5
0000000000000660 t deregister_tm_clones
00000000000006f0 t __do_global_dtors_aux
0000000000200890 t __do_global_dtors_aux_fini_array_entry
0000000000200b28 d __dso_handle
00000000002008a0 d _DYNAMIC
0000000000200b30 D _edata
0000000000200b38 B _end
0000000000000794 T _fini
0000000000000730 t frame_dummy
0000000000200888 t __frame_dummy_init_array_entry
0000000000000880 r __FRAME_END__
0000000000200b00 d _GLOBAL_OFFSET_TABLE_w __gmon_start__
0000000000000608 T _initw _ITM_deregisterTMCloneTablew _ITM_registerTMCloneTable
0000000000200898 d __JCR_END__
0000000000200898 d __JCR_LIST__w _Jv_RegisterClassesU qt_version_tag@@Qt_5.7
00000000000006a0 t register_tm_clones
000000000000077f T Sub
0000000000200b30 d __TMC_END__
0000000000000760 T _ZN7DLLDemoC1Ev
0000000000000760 T _ZN7DLLDemoC2Ev
000000000000079d r _ZStL19piecewise_construct

以上命令输出结果查看到Add 和Sub两个函数名。再此调用函数dlsym,此时不为空,调用成功了。

以下是调用该动态库的代码:

#include <QCoreApplication>
#include <dlfcn.h>
//#include "dlldemo.h"typedef int(* FuncAddTest)(int, int); // 定义函数指针类型的别名int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);const char *dylib_path = "/home/work/DLLDemo/lib/libDLLDemo.so";void *handle = NULL;char *error = NULL;if((handle = dlopen(dylib_path, RTLD_GLOBAL | RTLD_NOW)) == NULL){printf("dlopen - %sn", dlerror());exit(-1);}else{//获取add地址FuncAddTest addfunc =  (FuncAddTest)dlsym(handle, "Add");if(addfunc){printf("1 + 2 = %d\n",addfunc(1,2));       }else{if ((error = dlerror()) != NULL)  {fprintf (stderr, "%s ", error);exit(1);}printf("未找到\n");}dlclose(handle);}return a.exec();
}

linux平台 加载动态库dlsym返回null相关推荐

  1. linux 无法加载动态库,51CTO博客-专业IT技术博客创作平台-技术成就梦想

    比较懒,而且时间也不早了,就贴上英文,以后有机会在翻译吧. DLOPEN(3)     Linux Programmer's Manual  DLOPEN(3) NAME dladdr, dlclos ...

  2. Linux系统程序运行时加载动态库路径顺序

    程序运行时加载动态库路径顺序(Linux) 在linux系统中,如果程序需要加载动态库,它会按照一定的顺序(优先级)去查找: 链接时路径(Link-time path)和运行时路径(Run-time ...

  3. linux直接运行程序加载动态库失败,扣丁学堂Linux培训详解程序运行时加载动态库失败解决方法...

    今天扣丁学堂Linux培训老师给大家介绍一下关于Linux程序运行时加载动态库失败的解决方法,希望对同学们学习有所帮助,下面我们一起来看一下吧. Linux下不能加载动态库问题 当出现下边异常情况 . ...

  4. 加载动态库失败(loadLibrary返回为空)的几种解决办法

    如果遇到了以下几种问题,也许可以在本文找到解决方法: 一.版本更新后,原本正常的功能突然无法使用了: 二.VS编译的时候,弹出"xxx(win32):已加载"xx.dll" ...

  5. linux加载动态库问题

    当我们在linux系统引用动态库时,经常会遇到一个问题,加入我们需要的动态库没有在系统的默认目录下,我们编译时使用-L指定了动态库的路径,编译时没有问题,但是执行调用该动态库的可执行文件时,却提示找不 ...

  6. sunPKCS11加载动态库(转)

    sunPKCS11加载动态库(转) http://www.cnblogs.com/sunfb/archive/2013/03/01/2938491.html 这篇文章不介绍具体的编程方法,而是针对PK ...

  7. java.library.path hadoop_java - Hadoop“无法为您的平台加载native-hadoop库”警告

    java - Hadoop"无法为您的平台加载native-hadoop库"警告 我目前正在运行CentOs的服务器上配置hadoop. 当我运行hadoop-env.sh或sto ...

  8. tableview动态修改和删除_Ubuntu加载动态库失败的解决方案

    在ubuntu下代码编译通过的情况下,经常出现运行时加载动态库出错的情况.这些问题很琐碎,不具备任何技术含量,纯属耽误时间,这也是linux系统的通病,花里胡哨,故弄玄虚. 为了减少初学者在这种无意义 ...

  9. php7.2 加载pgsql驱动,PHP启动:无法加载动态库PGSQL - php

    我正在尝试使用运行Symfony 3.x: Ubuntu 16.04 PHP 7.0 NGinx 我想与我创建的PGSQL数据库进行交互,但出现此错误: PHP警告:PHP启动:无法加载动态库 '/u ...

最新文章

  1. 再回首数据结构—链表
  2. maven 使用 问题记录
  3. arch模型的思路_ARCH模型
  4. 大牛书单 | 腾讯技术大咖推荐你五一看这些书
  5. 简单易用的baidutemplate模板的使用
  6. 真实不装| 阿里巴巴新人上路指北
  7. Kafka的rebalance机制
  8. kubernetes API服务器的安全防护
  9. linux打包工具tar及一些压缩工具
  10. 使用Nmon监控Linux的系统性能
  11. 别以为真懂Openstack: 虚拟机创建的50个步骤和100个知识点(1)
  12. opencv 创建调色板
  13. 设计模式-头脑风暴-速记
  14. 什么是智能门锁,智能门锁主要有哪些优点?
  15. GIS | 坐标系统与地图投影
  16. mac java 配置环境变量配置_Mac 配置环境变量的方法
  17. 搭建kettle 源码工程报[ui/spoon.xul]找不到错误的解决方案
  18. 360众测考核简单记录
  19. 【C语言练习——打印空心上三角及其变形】
  20. win7系统如何添加计算机,教你win7系统电脑添加邮箱怎么添加

热门文章

  1. oracle ip策略,ip rule -- 路由策略数据库管理命令
  2. [BugFix] The font Arial cannot be found
  3. 数组模拟二叉搜索树(二叉排序树)
  4. 几千元的宝妈创业好项目,可年入15万以上,真的假的?
  5. java小公司社招面试3则(稍微进阶)
  6. Quartz 基本使用
  7. 抽检工作自动化,软件机器人提升样品信息采集和录入效率
  8. 超级安卓模拟器genymotion
  9. 自己做的简单网页如何放到服务器上运行
  10. 论文阅读《Pedestrian Dead Reckoning-Assisted Visual Inertial Odometry Integrity Monitoring》