共享库(.so)如何调用其加载器代码中实现的函数?

2024-11-08 09:04:00
admin
原创
30
摘要:问题描述:我有一个自己实现的共享库,并希望 .so 调用在主程序中实现的加载该库的函数。假设我有一个 main.c (可执行文件),其中包含:void inmain_function(void*); dlopen("libmy.so"); 在 my.c (libmy.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 中的符号,而不是反之亦然,这是常见的用法。


解决方案 1:

您有两个选项可供选择:

选项 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!
");
}

void unexported_callback() /*< Function we don't want to export */
{
    printf("Hello from unexported callback!
");
}

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
", dlerror());
       return -1;
   }
   func = dlsym(handle, "library_function");

   if (func == NULL) {
       fprintf(stderr, "Unable to get symbol
");
      return -1;
   }

   func();
   return 0;
}

int main(int argc, const char *argv[])
{
    printf("Hello from main!
");
    call_library();
    return 0;
}

库代码(lib.c):

#include <stdio.h>
int exported_callback();

int library_function()
{
    printf("Hello from library!
");
    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

解决方案 2:

您需要在 .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();
}

解决方案 3:

  1. 将您的主函数的原型放在.h 文件中,并将其包含在主库和动态库代码中。

  2. 使用 GCC,只需使用标志编译您的主程序-rdynamic

  3. 一旦加载,您的库将能够从主程序调用该函数。

进一步解释一下,一旦编译完成,您的动态库中就会有一个未定义的符号,该符号对应于主代码中的函数。当您的主应用程序加载该库时,该符号将由主程序的符号表解析。我已经多次使用上述模式,效果非常好。

解决方案 4:

以下内容可用于加载动态库并从加载调用中调用它(以防有人在寻找如何加载和调用 .so 库中的函数后来到此处)

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,它会给您一些描述问题的有意义的消息。

然而,其他海报已经为您的问题提供了更合适的答案。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用