-
Change Request
-
Resolution: Unresolved
-
Major
-
None
-
3.2.0alpha2
Let's start with a small demonstration. Let's build a small application (test) linked against two libraries (liba.so and libe.so) depending on one and the same symbol (foo) from two different libraries (libb.so and libd.so).
a.c:
#include "a.h" #include "b.h" void a_foo(void) { foo(); }
a.h:
void a_foo(void);
b.c:
#include <stdio.h>
void foo(void)
{
printf("bar\n");
}
b.h:
void foo(void);
d.c:
#include <stdio.h>
void foo(void)
{
printf("baz\n");
}
d.h:
void foo(void);
e.c:
#include "d.h" #include "e.h" void e_foo(void) { foo(); }
e.h:
void e_foo(void);
Let's build libraries:
$ gcc -o libb.so b.c -fPIC -shared $ gcc -o libd.so d.c -fPIC -shared $ gcc -o liba.so a.c -lb -L. -fPIC -shared $ gcc -o libe.so e.c -ld -L. -fPIC -shared
Let's first test them separately.
test_a:
#include "a.h" int main(void) { a_foo(); return 0; }
test_e.c:
#include "e.h" int main(void) { e_foo(); return 0; }
$ export LD_LIBRARY_PATH=. $ gcc -o test_a test_a.c -la -L. $ gcc -o test_e test_e.c -le -L. $ ./test_a bar $ ./test_e baz
So far everything is as expected. Now let's link both libraries to the same program.
test_both.c:
#include "a.h" #include "e.h" int main(void) { a_foo(); e_foo(); return 0; }
Both a_foo() and e_foo() print "bar" or "baz" depending on -l flag order:
$ gcc -o test_both test_both.c -la -le -L. $ ./test_both bar bar $ gcc -o test_both test_both.c -le -la -L. $ ./test_both baz baz
If program has it's own symbol foo it gets even better.
test_own.c:
#include "a.h" #include "e.h" #include <stdio.h> void foo(void) { printf("foo\n"); } int main(void) { a_foo(); e_foo(); return 0; }
Symbol foo from liba.so and libe.so gets resolved to the foo exported by the program itself:
$ gcc -o test_own test_own.c -la -le -L. $ ./test_own foo foo
But with a different approach it is possible to sort it out.
test_rtld.c:
#include <stdio.h> #include <dlfcn.h> void foo(void) { printf("foo\n"); } int main(void) { void *liba, *libe; void (*a_foo)(void); void (*e_foo)(void); liba = dlopen("liba.so", RTLD_NOW | RTLD_LOCAL); libe = dlopen("libe.so", RTLD_NOW | RTLD_LOCAL); a_foo = dlsym(liba, "foo"); e_foo = dlsym(libe, "foo"); foo(); a_foo(); e_foo(); dlclose(liba); dlclose(libe); return 0; }
$ gcc -o test_rtld test_rtld.c -ldl $ ./test_rtld foo bar baz
Most important question: How is it related to Zabbix?
Zabbix depends on a number of libraries (cURL, Net-SNMP, OpenIPMI, DB client libraries, ...) which all require encryption libraries as a secondary dependency. Zabbix uses DB client libraries to access its database and links against UnixODBC which loads ODBC drivers which require DB client libraries too. Sometimes they all need different versions of the same library and inability to resolve symbols correctly (slight difference between "bar" and "baz" in the example above) often leads to crashes.