Linwood
Linwood

Reputation: 262

Ubuntu C program loadable module and undefined symbols

Very new to linux in general and trying to build a loadable module for use in zabbix, which works, but trying to build a simple shell program for testing it. That means this module needs to be loaded dynamically.

Sharable module SNMPmath is built with this:

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

That works fine for zabbix.

The test program (TestSO.c) uses

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

to load this image dynamically, and when it does, it is missing symbols including init_snmp which come from the net-snmp package which is referenced in the SNMPmath loadable module.

My question is both general and specific. What's the right approach -- is this library called by the loadable module supposed to be forced into the loadable module? Is it supposed to be forced into the test program (despite having no compile-time reference to it)? Or is it supposed to be dynamically loaded, itself, in the loadable module (which seems to contradict what I'm seeing in other examples)?

And in either case, how is the GCC command modified to include net-snmp? I've tried variations of whole-archive, no-as-needed, listing what I think is the library (/usr/lib/x86_64-linux-gnu/libsnmp.a) with various compiler options with no effect (or occasionally errors). Also tried linking to the .so version of that (no effect). So a hint as to the proper GCC command to include the library would be very helpful.

Here's one iteration of attempts at linking the main program:

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

I've found numerous examples of loading modules, but they all load a simple routine that does not itself have undefined symbols that need satisfying.

Recap:

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

Pointers to examples or explanation welcome, I realize I'm missing something fairly obvious.

EDIT AFTER FIRST COMMENTS TO INCLUDE:

I have it sort of working now, but would appreciate a sanity check if this is correct. I pruned it down so as to show the whole code. Here is the code to produce the 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;
   }

Here is how it is compiled (note slight name change):

    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

Then here is the main program:

    #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;
    }

And finally this is built with:

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

This now will run as expected. I found that linking against the netsnmp library's so file when building my so seemed to work.

But is this the correct sequence? And/or the preferred sequence?

Ps. Off to read the paper in the first proposed answer.

Upvotes: 2

Views: 584

Answers (1)

Pointer to explanation: Drepper's paper: Howto write shared libraries

But we need more source code (and the commands used to compile it), and the real error messages (e.g. as given by dlerror() after dlopen call) to help more.

(See also this answer)

You might want to add some libraries like -lsomething (I don't know which, you probably do know!) to your command gcc -shared which is building SNMPmath.so .... You don't want to link a static library like libsnmp.a to it (you should link shared libraries to your SNMPmath.so shared object).

Upvotes: 2

Related Questions