共享库(.so)如何调用在其加载程序中实现的函数?

我有一个共享库,我实现了,我想要.so调用加载该库的主程序中的函数。

假设我有main.c(可执行文件),其中包含:

void inmain_function(void*); dlopen("libmy.so"); 

在my.c(libmy.so的代码)中,我想调用inmain_function

 inmain_function(NULL); 

无论inmain_function是否定义,共享库如何调用inmain_function

注意:我想从my.c中调用main.c中的一个符号,反之亦然,这是常见的用法。

您需要在.so中创建一个注册函数,以便可执行文件可以为您的.so函数指针提供以后使用。

喜欢这个:

 void in_main_func () { // this is the function that need to be called from a .so } void (*register_function)(void(*)()); void *handle = dlopen("libmylib.so"); register_function = dlsym(handle, "register_function"); register_function(in_main_func); 

register_function需要将函数指针存储在.so中.so中的其他函数可以找到它的变量中。

你的mylib.c需要看起来像这样:

 void (*callback)() = NULL; void register_function( void (*in_main_func)()) { callback = in_main_func(); } void function_needing_callback() { callback(); } 

你有两个选择,你可以从中选择:

选项1:从您的可执行文件中导出所有符号。 这是简单的选项,只是在构建可执行文件时,添加一个标志-Wl,--export-dynamic 。 这将使所有的函数可用于库调用。

选项2:创建一个带有函数列表的导出符号文件,并使用-Wl,--dynamic-list=exported.txt 。 这需要一些维护,但更准确。

演示:简单的可执行文件和动态加载的库。

 #include <stdio.h> #include <dlfcn.h> void exported_callback() /*< Function we want to export */ { printf("Hello from callback!\n"); } viud unexported_callback() /*< Function we don't want to export */ { printf("Hello from unexported callback!\n"); } typedef void (*lib_func)(); int call_library() { void *handle = NULL; lib_func func = NULL; handle = dlopen("./libprog.so", RTLD_NOW | RTLD_GLOBAL); if (handle == NULL) { fprintf(stderr, "Unable to open lib: %s\n", dlerror()); return -1; } func = dlsym(handle, "library_function"); if (func == NULL) { fprintf(stderr, "Unable to get symbol\n"); return -1; } func(); return 0; } int main(int argc, const char *argv[]) { printf("Hello from main!\n"); call_library(); return 0; } 

库代码(lib.c):

 #include <stdio.h> int exported_callback(); int library_function() { printf("Hello from library!\n"); exported_callback(); /* unexported_callback(); */ /*< This one will not be exported in the second case */ return 0; } 

所以,首先建立库(这一步没有什么不同):

  gcc -shared -fPIC lib.c -o libprog.so 

现在用所有导出的符号构建可执行文

  gcc -Wl,--export-dynamic main.c -o prog.exe -ldl 

运行示例:

  $ ./prog.exe Hello from main! Hello from library! Hello from callback! 

符号导出:

  $ objdump -e prog.exe -T | grep callback 00000000004009f4 g DF .text 0000000000000015 Base exported_callback 0000000000400a09 g DF .text 0000000000000015 Base unexported_callback 

现在用导出的列表( exported.txt ):

 { extern "C" { exported_callback; }; }; 

构建和检查可见符号:

 $ gcc -Wl,--dynamic-list=./exported.txt main.c -o prog.exe -ldl $ objdump -e prog.exe -T | grep callback 0000000000400774 g DF .text 0000000000000015 Base exported_callback 
  1. 将主函数的原型放在.h文件中,并将其包含在主库函数和动态库代码中。

  2. 使用GCC,只需使用-rdynamic标志编译主程序即可。

  3. 一旦加载,你的库就可以从主程序中调用这个函数。

进一步的解释是,一旦编译完成,你的动态库将会在主代码中有一个未定义的符号。 当您的主应用程序加载库时,符号将由主程序的符号表来解析。 我已经多次使用上述模式,它的作品就像一个魅力。

下面的代码可以用来在你的代码中加载一个动态库(如果有人来看看如何做到这一点):

 void* func_handle = dlopen ("my.so", RTLD_LAZY); /* open a handle to your library */ void (*ptr)() = dlsym (func_handle, "my_function"); /* get the address of the function you want to call */ ptr(); /* call it */ dlclose (func_handle); /* close the handle */ 

不要忘记把#include <dlfcn.h>和链接到–ldl选项。

您可能还想添加一些检查是否返回NULL逻辑。 如果是这种情况,你可以调用dlerror ,它应该给你一些有意义的消息来描述这个问题。

其他海报却为您的问题提供了更合适的答案。