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.
我有一个应用程序,其中一部分使用共享库。这些库在编译时链接。在运行时,加载器期望共享对象位于LD_LIBRARY_PATH中,如果没有找到整个应用程序崩溃,并显示“无法加载共享库”错误。请注意,不能保证客户端将拥有该库,在这种情况下我想要留下合适的错误消息的应用程序也应该独立的部分正常工作。
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.
为此,我使用dlsym()和dlopen()在共享库中使用API。这个问题是如果我在API中有很多函数,我必须使用dlsym()和ptrs单独访问它们,在我看来这会导致内存损坏和代码崩溃。
Are there any alternatives for this?
这有什么替代方案吗?
5 个解决方案
#1
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):
你的问题的常见解决方案是声明一个函数指针表,做一个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
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.
附:使用dlsym和指针单独访问API函数本身并不会导致内存损坏和崩溃。很可能你只是有虫子。
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
.
编辑:您可以使用与第三方库完全相同的技术。创建一个libdrmaa_wrapper.so并将api_table放入其中。将包装器直接链接到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.
在主可执行文件中,dlopen(“libdrmaa_wrapper.so”,RTLD_NOW)。如果(并且仅当)libdrmaa.so在运行时出现并且提供您在api_table中使用的所有API函数,则此dlopen将成功。如果成功,单个dlsym调用将允许您访问整个API。
#2
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.
您可以使用另一个首先检查所有必需库的应用程序来包装您的应用程序,如果缺少某些内容,则会很好地解决错误,但如果一切正常,则执行真正的应用程序。
#3
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()
.....
使用dlopen()在运行时加载此库。并使用dlsym()并调用getDynLibPointer(),它返回DynLib对象。从这个对象你可以访问你的所有函数jst as obj.fun1().....
This is ofcource a C++ style of struct method proposed earlier.
这是前面提出的C ++样式的struct方法。
#4
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.
您可能正在寻找Linux上某种形式的延迟库加载。它不是开箱即用的,但你可以通过创建一个小的静态存根库来轻松模仿它,它会在第一次调用它的任何函数时尝试dlopen所需的库(发出诊断消息并在dlopen失败时终止)然后转发所有来电。
Such stub libraries can be written by hand, generated by project/library-specific script or generated by universal tool Implib.so:
这样的存根库可以手工编写,由项目/库特定的脚本生成或由通用工具Implib.so生成:
$ implib-gen.py libxyz.so
$ gcc myapp.c libxyz.tramp.S libxyz.init.c ...
#5
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.
您的问题是未解决的符号的解决方案很早就完成了 - 在Linux上我相信数据符号在进程启动时被解析,并且函数符号是懒惰地完成的。因此,根据您未解决的符号以及您正在进行的静态初始化,您可能无法获得代码。
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.
或者,您可以让您的包装器脚本运行ldd,然后解析输出,ldd将报告您的特定应用程序找不到的所有库。
#1
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):
你的问题的常见解决方案是声明一个函数指针表,做一个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
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.
附:使用dlsym和指针单独访问API函数本身并不会导致内存损坏和崩溃。很可能你只是有虫子。
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
.
编辑:您可以使用与第三方库完全相同的技术。创建一个libdrmaa_wrapper.so并将api_table放入其中。将包装器直接链接到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.
在主可执行文件中,dlopen(“libdrmaa_wrapper.so”,RTLD_NOW)。如果(并且仅当)libdrmaa.so在运行时出现并且提供您在api_table中使用的所有API函数,则此dlopen将成功。如果成功,单个dlsym调用将允许您访问整个API。
#2
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.
您可以使用另一个首先检查所有必需库的应用程序来包装您的应用程序,如果缺少某些内容,则会很好地解决错误,但如果一切正常,则执行真正的应用程序。
#3
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()
.....
使用dlopen()在运行时加载此库。并使用dlsym()并调用getDynLibPointer(),它返回DynLib对象。从这个对象你可以访问你的所有函数jst as obj.fun1().....
This is ofcource a C++ style of struct method proposed earlier.
这是前面提出的C ++样式的struct方法。
#4
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.
您可能正在寻找Linux上某种形式的延迟库加载。它不是开箱即用的,但你可以通过创建一个小的静态存根库来轻松模仿它,它会在第一次调用它的任何函数时尝试dlopen所需的库(发出诊断消息并在dlopen失败时终止)然后转发所有来电。
Such stub libraries can be written by hand, generated by project/library-specific script or generated by universal tool Implib.so:
这样的存根库可以手工编写,由项目/库特定的脚本生成或由通用工具Implib.so生成:
$ implib-gen.py libxyz.so
$ gcc myapp.c libxyz.tramp.S libxyz.init.c ...
#5
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.
您的问题是未解决的符号的解决方案很早就完成了 - 在Linux上我相信数据符号在进程启动时被解析,并且函数符号是懒惰地完成的。因此,根据您未解决的符号以及您正在进行的静态初始化,您可能无法获得代码。
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.
或者,您可以让您的包装器脚本运行ldd,然后解析输出,ldd将报告您的特定应用程序找不到的所有库。