【问题标题】:Purpose of using dynamic linking loader <dlfcn.h> instead of direct function call?使用动态链接加载器 <dlfcn.h> 而不是直接函数调用的目的?
【发布时间】:2020-04-30 18:46:39
【问题描述】:

我今天遇到了类似这段代码的东西。

A.h:

class A { blah blah blah }

#define CREATE_A_FUNC_NAME   ("CreateA")
extern "C" A* CreateA(void);
typedef A* (*funcCreateA)(void);

main.cpp:

void* handle = dlopen("libA.so", RTLD_LAZY);
funcCreateA func = (funcCreateA)dlsym(handle, CREATE_A_FUNC_NAME);
A* a = func();

现在显然 A.h 只是声明的标头,它的所有实现都存储在 libA.so 中。

我已经测试过,如果我正确设置了我的项目,这意味着正确链接了 lib,我可以简单地执行 A* a = CreateA() 来获取指向新创建的 A 实例的指针。因此,问题来了。为什么要经历这么多麻烦来实现一个简单的函数调用?这种技术或技术叫什么?优缺点都有什么?我什么时候应该使用这种技术?谢谢!

【问题讨论】:

  • 如果您将此 libA.so 链接到您的应用程序中,则不应使用dlopenld.so 将与您的可执行文件一起加载 libA.so。其他应用程序(Apache httpd 就是一个例子)有很多库,并不是在每个程序运行中都使用,或者一些库是由其他方创建的(例如 libphp.so),因此它们是动态加载的(通过 dlopen)取决于程序选项/配置文件/用户输入。

标签: c++ linux shared-libraries dynamic-linking


【解决方案1】:

使用 dlsym 而不是直接链接到 DSO 的主要原因:

  • 您想为您的应用提供插件机制,因此您需要能够动态加载 DSO(当您构建 exe 时,链接器不知道这些插件) .最简单的方法是添加一些虚拟基类(我假设'A'有一些虚拟方法?),然后导出一个带有“C”链接的创建者方法(其中禁用 C++ 名称修饰)。看来这就是这里的意图?
  • 您可能针对特定 CPU 指令集优化了代码(即在游戏引擎启动时,检查 CPU 支持的最新指令集,在运行时加载相关的 SSE 或 AVX 库,然后调用针对特定 CPU 优化的方法)
  • 在极少数情况下,您可能希望“卸载”一些繁重的代码以释放设备上的更多内存。这在 Android/iOS 和控制台上经常发生(例如,在所有着色器编译完成后释放着色器编译器)

值得注意的是,如果您直接链接到 DSO,在后台,链接器将简单地在应用启动时插入 dlsym/dlopen 代码,这将自动加载 DSO 并解析符号。

【讨论】:

  • 精彩的答案。从本质上讲,这种技术是否称为动态加载?我想用谷歌搜索更多关于它的信息,并且需要一个名字来搜索。
  • '动态链接库'如果你在 Windows 上,或者'动态共享对象'如果你在 linux 上。我猜总括性术语是:动态链接。 Windows 和 Posix API 之间没有太大区别。 Linux:dlopen、dlclose 和 dlsym。在 Windows 上:LoadLibrary、FreeModule 和 GetProcAddress。它们很容易封装在#ifdef WIN32 后面
  • 最后一段是一个简化:加载器链接器 (ld.so) 和 dlopen 做的事情非常相似,但它们仍然不一样。
  • dlopen 的另一个原因:加载特定于供应商的 OpenGL 实现(这就是 Glew 所做的)。
猜你喜欢
  • 1970-01-01
  • 2021-12-09
  • 1970-01-01
  • 1970-01-01
  • 2012-08-30
  • 2011-08-21
  • 1970-01-01
  • 2019-12-02
  • 1970-01-01
相关资源
最近更新 更多