Re: strange behavior of glibc/libdl function chaining on linux.

From: Peter T. Breuer (ptb_at_oboe.it.uc3m.es)
Date: 08/18/05


Date: Thu, 18 Aug 2005 21:21:43 +0200

In comp.os.linux.development.system Yann LANGLAIS <langlais@ilay.org> wrote:
> different libraries using dlsym/RTLD_NEXT :

RTLD_NEXT is not documented in my man page (for dlsym), but
/usr/include/dlfcn.h has this:

 /* If the first argument of `dlsym' or `dlvsym' is set to RTLD_NEXT
    the run-time address of the symbol called NAME in the next shared
    object is returned. The "next" relation is defined by the order
    the shared objects were loaded. */
 #define RTLD_NEXT ((void *) -1l)

So I guess the order is not defined as you think it is defined! It
appears in particular not to be defined at all between dynamically
linked libraries opened with dlopen, or perhaps the notion of "current"
library is different to what you think when several are open.

Mind you, the man page is clearly "wrong" in places too .. it says that
_init() in the shared dynamically loaded object will be executed
autmatically. All it does for me is provoke an error about a name clash
in crt0.o or something like.

> 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

Hmmm.

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

> LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./chain2

> And the result :

> lib1.foo()

What? No other output at all? So the lookups yield NULL?

I would guess that the libraries are chained in reverse order. Try
testing for that.

> Period. Other functions in other libs are ignored.

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

> On other platforms, such as Solaris 8 using native "forte" compiler and
> native libdl.so, the result of chain2 is the same as the one of chain.

Peter



Relevant Pages

  • Re: strange behavior of glibc/libdl function chaining on linux.
    ... > EOF ... > extern void foo(); ... > int main{ ... I would guess that the libraries are chained in reverse order. ...
    (comp.unix.questions)
  • Re: Im a stupid blond :( Please help me!!!
    ... > int main ... The point is whether or not that can be detected at compile time. ... The code of the foo() function won't be linked because it cannot possibly ... libraries you linked, only those that may be called either by the startup ...
    (comp.lang.cpp)
  • libdl/glibc question
    ... Here is a compile time link of the chain components: ... cat> lib$i.c <<EOF ... extern void foo(); ... int main{ ...
    (comp.unix.programmer)
  • Re: [opensuse] quasselcore doesnt run
    ... Symbols in libraries are functions, ... void foo::foo; ... int foo::foo; ... so that all "foo" functions are different ...
    (SuSE)
  • Re: porting from Ikarus to PLT
    ... Will PLT and Ikarus behave the same here? ... (provide foo bar) ... An identifier can be imported with the same local name from two or more libraries or for two levels from the same library only if the binding exported by each library is the same (i.e., the binding is defined in one library, and it arrives through the imports only by exporting and re-exporting). ...
    (comp.lang.scheme)