C++ 中 dlsym() 和 dlopen() 的替代品

发布于 2024-07-26 01:21:54 字数 334 浏览 9 评论 0原文

我有一个应用程序,其中一部分使用共享库。 这些库在编译时链接。
在运行时,加载程序期望共享对象位于 LD_LIBRARY_PATH 中,如果没有找到,整个应用程序将崩溃并出现错误“无法加载共享库”。请注意,不能保证客户端将拥有库,在这种情况下,我希望应用程序留下合适的错误消息,独立部分也应该正常工作。

为此,我使用 dlsym()dlopen() 来使用共享库中的 API。 问题是,如果 API 中有很多函数,我必须使用 dlsym() 和 ptr 单独访问它们,在我的例子中,这会导致内存损坏和代码崩溃。

有其他选择吗?

I have an application a part of which uses shared libraries. These libraries are linked at compile time.

At Runtime the loader expects the shared object to be in the LD_LIBRARY_PATH , if not found the entire application crashes with error "unable to load shared libraries".Note that there is no guarantee that client would be having the library, in that case I want the application to leave a suitable error message also the independent part should work correctly.

For this purpose I am using dlsym() and dlopen() to use the API in the shared library. The problem with this is if I have a lot of functions in the API, i have to access them Individually using dlsym() and ptrs which in my case are leading to memory corruption and code crashes.

Are there any alternatives for this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

数理化全能战士 2024-08-02 01:21:54

解决问题的常见方法是声明一个函数指针表,执行单个 dlsym() 来查找它,然后通过指向该表的指针调用所有其他函数。 示例(未经测试):

// libfoo.h
struct APIs {
   void  (*api1)(void);
   void *(*api2)(int);
   long  (*api3)(int, void *);
};

// libfoo.cc
void fn1(void) { ... }
void *fn2(int) { ... }
long fn3(int, void *) { ... }

APIs api_table = { fn1, fn2, fn3 };


// client.cc
#include "libfoo.h"
...
  void *foo_handle = dlopen("libfoo.so", RTLD_LAZY);
  if (!foo_handle) {
     return false;            // library not present
  }
  APIs *table = dlsym(foo_handle, "api_table");
  table->api1();              // calls fn1
  void *p = table->api2(42);  // calls fn2
  long x = table->api3(1, p); // calls fn3

PS 使用 dlsym 和指针单独访问 API 函数本身不会导致内存损坏和崩溃。 很可能你只是遇到了错误。

编辑:
您可以对第三方库使用完全相同的技术。 创建一个libdrmaa_wrapper.so并将api_table放入其中。 将包装器直接链接到 libdrmaa.so

在主可执行文件中,dlopen("libdrmaa_wrapper.so", RTLD_NOW)。 当(且仅当)libdrmaa.so 在运行时存在并提供您在 api_table 中使用的所有 API 函数时,此 dlopen 才会成功。 如果成功,只需一次 dlsym 调用即可让您访问整个 API。

The common solution to your problem is to declare a table of function pointers, to do a single dlsym() to find it, and then call all the other functions through a pointer to that table. Example (untested):

// libfoo.h
struct APIs {
   void  (*api1)(void);
   void *(*api2)(int);
   long  (*api3)(int, void *);
};

// libfoo.cc
void fn1(void) { ... }
void *fn2(int) { ... }
long fn3(int, void *) { ... }

APIs api_table = { fn1, fn2, fn3 };


// client.cc
#include "libfoo.h"
...
  void *foo_handle = dlopen("libfoo.so", RTLD_LAZY);
  if (!foo_handle) {
     return false;            // library not present
  }
  APIs *table = dlsym(foo_handle, "api_table");
  table->api1();              // calls fn1
  void *p = table->api2(42);  // calls fn2
  long x = table->api3(1, p); // calls fn3

P.S. Accessing your API functions individually using dlsym and pointers does not in itself lead to memory corruption and crashes. Most likely you just have bugs.

EDIT:
You can use this exact same technique with a 3rd-party library. Create a libdrmaa_wrapper.so and put the api_table into it. Link the wrapper directly against libdrmaa.so.

In the main executable, dlopen("libdrmaa_wrapper.so", RTLD_NOW). This dlopen will succeed if (and only if) libdrmaa.so is present at runtime and provides all API functions you used in the api_table. If it does succeed, a single dlsym call will give you access to the entire API.

吃→可爱长大的 2024-08-02 01:21:54

您可以用另一个应用程序包装您的应用程序,该应用程序首先检查所有必需的库,如果缺少某些内容,它会很好地出错,但如果一切正常,它会执行真正的应用程序。

You can wrap your application with another one which first checks for all the required libraries, and if something is missing it errors out nicely, but if everything is allright it execs the real application.

各自安好 2024-08-02 01:21:54

使用以下类型的代码

Class DynLib
{
    /* All your functions */
    void fun1() {};
    void fun2() {};
    .
    .
    .
}

DynLib* getDynLibPointer()
{
    DynLib* x = new Dynlib;
    return x;
}

使用 dlopen() 在运行时加载此库。
并使用 dlsym() 并调用 getDynLibPointer() 来返回 DynLib 对象。
从这个对象中,您可以访问所有函数 jst 作为 obj.fun1().....

这是早期提出的 C++ 风格的结构方法。

Use below type of code

Class DynLib
{
    /* All your functions */
    void fun1() {};
    void fun2() {};
    .
    .
    .
}

DynLib* getDynLibPointer()
{
    DynLib* x = new Dynlib;
    return x;
}

use dlopen() for loading this library at runtime.
and use dlsym() and call getDynLibPointer() which returns DynLib object.
from this object you can access all your functions jst as obj.fun1().....

This is ofcource a C++ style of struct method proposed earlier.

緦唸λ蓇 2024-08-02 01:21:54

您可能正在 Linux 上寻找某种形式的延迟库加载。 它不是开箱即用的,但您可以通过创建一个小型静态存根库来轻松模仿它,该存根库将在第一次调用它的任何函数时尝试dlopen所需的库(发出诊断消息和如果 dlopen 失败则终止),然后将所有调用转发给它。

此类存根库可以手动编写、由项目/库特定的脚本生成或由通用工具 Implib 生成。所以

$ implib-gen.py libxyz.so
$ gcc myapp.c libxyz.tramp.S libxyz.init.c ...

You are probably looking for some form of delay library load on Linux. It's not available out-of-the-box but you can easily mimic it by creating a small static stub library that would try to dlopen needed library on first call to any of it's functions (emitting diagnostic message and terminating if dlopen failed) and then forwarding all calls to it.

Such stub libraries can be written by hand, generated by project/library-specific script or generated by universal tool Implib.so:

$ implib-gen.py libxyz.so
$ gcc myapp.c libxyz.tramp.S libxyz.init.c ...
你的往事 2024-08-02 01:21:54

你的问题是,未解析符号的解析是很早就完成的 - 在Linux上,我相信数据符号在进程启动时解析,而函数符号是延迟完成的。 因此,根据您未解析的符号以及您正在进行的静态初始化类型,您可能没有机会进入您的代码。

我的建议是有一个包装应用程序来捕获返回代码/错误字符串“无法加载共享库”,然后将其转换为更有意义的内容。 如果这是通用的,则不需要在每次添加新的共享库时都进行更新。

或者,您可以让包装器脚本运行ldd,然后解析输出,ldd 将报告未找到特定应用程序的所有库。

Your problem is that the resolution of unresolved symbols is done very early on - on Linux I believe the data symbols are resolved at process startup, and the function symbols are done lazily. Therefore depending on what symbols you have unresolved, and on what sort of static initialization you have going on - you may not get a chance to get in with your code.

My suggestion would be to have a wrapper application that traps the return code/error string "unable to load shared libraries", and then converts this into something more meaningful. If this is generic, it will not need to be updated every time you add a new shared library.

Alternatively you could have your wrapper script run ldd and then parse the output, ldd will report all libraries that are not found for your particular application.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文