【问题标题】:Ubuntu C program loadable module and undefined symbolsUbuntu C 程序可加载模块和未定义符号
【发布时间】:2014-02-11 15:45:50
【问题描述】:

一般来说,对 linux 来说非常新,并试图构建一个可加载的模块以在 zabbix 中使用,这很有效,但试图构建一个简单的 shell 程序来测试它。这意味着这个模块需要动态加载。

可共享模块 SNMPmath 是用这个构建的:

gcc -shared   -o SNMPmath.so $(CFLAGS)  -I../../../include -I/usr/include/libxml2 -fPIC SNMPmath.c

这对 zabbix 很有效。

测试程序(TestSO.c)使用

lib_handle = dlopen("./SNMPmath.so", RTLD_NOW);

动态加载这个图像,当它加载时,它缺少包括 init_snmp 在内的符号,这些符号来自 SNMPmath 可加载模块中引用的 net-snmp 包。

我的问题既笼统又具体。什么是正确的方法——由可加载模块调用的这个库是否应该被强制进入可加载模块?它是否应该被强制进入测试程序(尽管没有编译时引用它)?还是应该在可加载模块中动态加载它本身(这似乎与我在其他示例中看到的相矛盾)?

无论哪种情况,如何修改 GCC 命令以包含 net-snmp?我已经尝试了整个存档的变体,不需要,列出我认为是库(/usr/lib/x86_64-linux-gnu/libsnmp.a)的各种编译器选项没有效果(或偶尔出现错误) )。还尝试链接到 .so 版本(无效)。因此,关于包含该库的正确 GCC 命令的提示将非常有帮助。

这是链接主程序的一次尝试:

gcc -rdynamic -o TestSO   -I../../../include -I/usr/include/libxml2 TestSO.c  -ldl -Wl,--no-as-needed /usr/lib/x86_64-linux-gnu/libsnmp.so

我发现了许多加载模块的示例,但它们都加载了一个简单的例程,该例程本身没有需要满足的未定义符号。

回顾:

    TestSO.c
       ==> Loads with dlopen SNMPmath.c
          ==> needs to refer to net-snmp routines like init_snmp

欢迎指点示例或解释,我意识到我遗漏了一些相当明显的东西。

在第一条评论后编辑包括:

我现在可以使用它,但如果这是正确的,我将不胜感激。我把它剪掉了,以便显示整个代码。这是生成 SO 的代码:

   #include <net-snmp/net-snmp-config.h>
   #include <net-snmp/net-snmp-includes.h>
   #include <string.h>
   int     zbx_module_SNMPmath_avg(int i, int j)
   {

    init_snmp("snmpapp");   // initialize SNMP library
    return 1;
   }

这是它的编译方式(注意名称略有变化):

    CFLAGS=-I. `net-snmp-config --cflags`

    SNMPmath_small: SNMPmath_small.c
            gcc -shared  -o SNMPmath.so $(CFLAGS)  -I../../../include -I/usr/include/libxml2 -fPIC SNMPmath_small.c -Wl,--no-as-needed,/usr/lib/x86_64-linux-gnu/libsnmp.so

然后这里是主程序:

    #include <stdio.h>
    #include <dlfcn.h>
    #include <dlfcn.h>
    #include <string.h>

    int main(int argc, char **argv)
    {
       void *lib_handle;
       int(*fn)(int req, int ret);
       int x;
       char *error;

       lib_handle = dlopen("./SNMPmath.so", RTLD_NOW);
       if (!lib_handle)
       {
          fprintf(stderr, "Error on open - %s\n", dlerror());
          exit(1);
       }
       else
           fprintf(stderr,"Successfully loaded module\n");
       fn = dlsym(lib_handle, "zbx_module_SNMPmath_avg");
       if ((error = dlerror()) != NULL)
       {
          fprintf(stderr, "Error on dlsym %s\n", error);
          exit(1);
       }
       else fprintf(stderr,"Successfully called dlsym\n");

    // testing
       int req, ret;
       req=1;
       ret=1;

       x=(*fn)(req, ret);
       printf("Valx=%i\n",x);

       dlclose(lib_handle);
       return 0;
    }

最后这是用:

    TestSO: TestSO.c
            gcc -rdynamic -o TestSO   -I../../../include -I/usr/include/libxml2 TestSO.c  -ldl

这现在将按预期运行。我发现在构建我的 so 时链接 netsnmp 库的 so 文件似乎可行。

但这是正确的顺序吗?和/或首选顺序?

附言。去阅读第一个建议答案中的论文。

【问题讨论】:

  • 显示更多 C 源代码。
  • +1 表示明确的问题,但是我同意@BasileStarynkevitch 的观点,即发布一些额外的代码会增加您获得有用答案的几率。
  • 自最初发布以来,我已经取得了一些进展,但将使用当前设置对其进行编辑。我在尽量避免一堆与zabbix相关的无关代码,让我看看我是否可以在发布之前将其削减。

标签: c linux


【解决方案1】:

解释指针:Drepper's paper: Howto write shared libraries

但我们需要更多源代码(以及用于编译它的命令)和真正的错误消息(例如,dlerror()dlopen 调用后给出的信息)来提供更多帮助。

(另见this answer

您可能想要添加一些库,例如 -lsomething(我不知道是哪个,您可能知道!)到您的命令 gcc -shared,它正在构建 SNMPmath.so ...。您不想将libsnmp.a 之类的静态库链接到它(您应该将共享库链接到您的SNMPmath.so 共享对象)。

【讨论】:

  • 谢谢。我正试图浏览该文件。它似乎确实有效,在我修复它的过程中是否有任何 cmets,特别是如果链接器选项在包含的程序上显示正确(当然我使用的库是正确的库)?
猜你喜欢
  • 2014-02-13
  • 1970-01-01
  • 1970-01-01
  • 2016-10-16
  • 2012-01-02
  • 1970-01-01
  • 2012-07-23
  • 1970-01-01
  • 2012-12-21
相关资源
最近更新 更多