[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

dlfcn question




Hi.

I'm writing an article (in french) about libdl.so and faced a behavior I
wasn't expected while trying to chain functions w/ same name in
different libraries using dlsym/RTLD_NEXT :

Here is a compile time link of the chain components :
for i in 1 2 3 4
do
cat > lib$i.c <<EOF
#include <stdio.h>
#include <dlfcn.h>
void foo() {
     void (*next_foo)(void);
     printf("lib$i.foo()\n");
     if (next_foo = (void (*)(void)) dlsym(RTLD_NEXT, "foo")) next_foo();
}

EOF
gcc -shared -fPIC lib$i.c -o lib$i.so -D_GNU_SOURCE
done
cat > chain.c <<EOF
#include <dlfcn.h>
extern void foo();
int main() {
     foo();
     return 0;
}

EOF
gcc chain.c -o chain -L. -l1 -l2 -l3 -l4 -ldl
LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./chain

And the result :

lib1.foo()
lib2.foo()
lib3.foo()
lib4.foo()

And now a runtime linking version:

cat > chain2.c <<EOF
#include <dlfcn.h>
int main() {
         void *l1, *l2, *l3, *l4;
         void (*bar)();
         l1 = dlopen("lib1.so", RTLD_NOW | RTLD_GLOBAL);
         l2 = dlopen("lib2.so", RTLD_NOW | RTLD_GLOBAL);
         l3 = dlopen("lib3.so", RTLD_NOW | RTLD_GLOBAL);
         l4 = dlopen("lib4.so", RTLD_NOW | RTLD_GLOBAL);
         bar = (void (*)()) dlsym(RTLD_DEFAULT, "foo");
         bar();
         dlclose(l4);
         dlclose(l3);
         dlclose(l2);
         dlclose(l1);
         return 0;
}

EOF
gcc chain2.c -o chain2 -ldl -D_GNU_SOURCE

LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./chain2

And the result :

lib1.foo()

Period. Other functions in other libs are ignored.

With the following test :

cat > chain5.c <<EOF
#include <dlfcn.h>
int main() {
         void *l1, *l2, *l3, *l4;
         void (*bar)();

         l1 = dlopen("lib1.so", RTLD_NOW | RTLD_GLOBAL);
         bar = (void (*)()) dlsym(l1, "foo");
                printf("l1 is %x l1.foo is %x\n", l1, bar);

         l2 = dlopen("lib2.so", RTLD_NOW | RTLD_GLOBAL);
         bar = (void (*)()) dlsym(l2, "foo");
                printf("l2 is %x l2.foo is %x\n", l2, bar);

         l3 = dlopen("lib3.so", RTLD_NOW | RTLD_GLOBAL);
         bar = (void (*)()) dlsym(l3, "foo");
                printf("l3 is %x l3.foo is %x\n", l3, bar);

         l4 = dlopen("lib4.so", RTLD_NOW | RTLD_GLOBAL);
         bar = (void (*)()) dlsym(l4, "foo");
                printf("l4 is %x l4.foo is %x\n", l4, bar);

         bar = (void (*)()) dlsym(l1, "foo");
                printf("l1.foo is %x \n", bar);
         bar = (void (*)()) dlsym(l2, "foo");
                printf("l2.foo is %x \n", bar);
         bar = (void (*)()) dlsym(l3, "foo");
                printf("l3.foo is %x \n", bar);
         bar = (void (*)()) dlsym(l4, "foo");
                printf("l4.foo is %x \n", bar);

         bar = (void (*)()) dlsym(RTLD_DEFAULT, "foo");
                printf("default foo is %x \n", bar);

         bar();
         dlclose(l4);
         dlclose(l3);
         dlclose(l2);
         dlclose(l1);
         return 0;
}

EOF
gcc chain5.c -o chain5 -ldl -D_GNU_SOURCE

chain5
l1 is 804a018 l1.foo is 5556d584
l2 is 804a3b0 l2.foo is 55570584
l3 is 804a710 l3.foo is 55572584
l4 is 804aa70 l4.foo is 55574584
l1.foo is 5556d584
l2.foo is 55570584
l3.foo is 55572584
l4.foo is 55574584
default foo is 5556d584
lib1.foo()

So dlsym cannot fetch next symbol when libs are linked runtime w/ dlopen even when
RTLD_GLOBAL|RTLD_NOW are set.

Is this behavior normal under glibc (which on linux implements dlfcn
functions) ?


Thanks for your help !


regards,

Yann LANGLAIS
http://ilay.org
langlais@ilay.org
--
    I r i s
L i l a
é   A n g e l a
o   Y a n n
    . o r g



Reply to: