Shared library initialization order.

Shared library initialization order.

Post by Mott » Wed, 14 Aug 2002 00:34:03



Hiya all.

I've posted this on comp.os.linux.development.apps but got no response
so I thought I might have more luck here (even though I'm not strictly
speaking working on the system).

I have a shared library that depends on another shared library. In
other OSs (Solaris HP-UX) this causes the global variables in the
second library to be initialized first but in Linux I see that the
order of initialization is wholly dependant on the order of the
libraries on the link line (they get initialized in reverse order to
that of the link line). In AIX it's possible to give a shared library
a priority at link time (-qmkshrobj[=priority] ) which is much uglier
but at least you don't have to worry about the order on link line.

Is there any way to get g++ to choose the correct initialization
order?

Here is a sample:
----- used.C
class multiplier {
        int i;
public:
        operator int() const { return i; }
        multiplier(int ii, int jj) : i(ii*jj) { }

Quote:};

multiplier obj(7,6);

int usedFunc()
{
        return obj;

Quote:}

----- user.C
int usedFunc();
int userInt = usedFunc();

int userFunc()
{
        return userInt;

Quote:}

----- main.C
int userFunc();
int main()
{
        return userFunc() -42;
Quote:}

----- Makefile (I was lazy so it only works on Linux and Solaris
ifeq ($(OSTYPE),linux)
LD=g++ --shared
CXX=g++ -g
else
# solaris
LD=CC -G
CXX=CC -g
endif

all: libuser.so libused.so
        ${CXX} main.C -L. -lused -luser -o runme

libuser.so: user.o libused.so

libused.so: used.o

used.o: used.C

user.o: user.C

clean:
        -/bin/rm -rf *.o *.so core runme
------

After I run gmake I checked with ldd to make sure that libuser.so is
dependant on libused.so.

In Solaris this is enough and when I run ./runme the global object in
libused.so get initialized before those of libuser.so and the return
code is the expected 0. But in linux this doesn't happen and runme
fails (returns a nonzero value).

Any ideas?
Also if you think there is another group which may be able to help me
on this please point it out.

P.S. Yes I know I could put the libraries in the correct order but
where's the fun in that? also in real life we're talking about
something slightly more complex than my sample....

--
If at first you don't succeed, post, post, post again.

 
 
 

Shared library initialization order.

Post by John Reise » Wed, 14 Aug 2002 03:02:30


Please specify the versions of the tools and libraries that were used.
With make-3.79.1-8, OSTYPE is not a predefined symbol.

Cut to the chase:
        $ make
        g++ -g  -c user.C -o user.o
        g++ -g  -c used.C -o used.o
        g++ --shared  used.o -o libused.so
        g++ --shared  -L. -lused user.o -o libuser.so
        g++ -g  main.C -L. -lused -luser -o runme
        $ LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ldd ./libuser.so
                libused.so => ./libused.so (0x40002000)
                libstdc++-libc6.2-2.so.3 => /usr/lib/libstdc++-libc6.2-2.so.3 (0x4001b000)
                libm.so.6 => /lib/i686/libm.so.6 (0x4005e000)
                libc.so.6 => /lib/i686/libc.so.6 (0x42000000)
                /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)
        $  LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ldd ./runme
                libused.so => ./libused.so (0x40014000)
                libuser.so => ./libuser.so (0x40017000)
                libstdc++-libc6.2-2.so.3 => /usr/lib/libstdc++-libc6.2-2.so.3 (0x4002f000)
                libm.so.6 => /lib/i686/libm.so.6 (0x40072000)
                libc.so.6 => /lib/i686/libc.so.6 (0x42000000)
                /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
        $ LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./runme
        $ echo $?
        0
        $
which is a correct answer.  That's with glibc-2.2.5-36 that includes
/lib/ld-linux.so.2 and /lib/{i686}/libc.so.6.  The current ELF spec requires
that the dynamic loader ld-linux.so.2 perform .so initializations according
to a runtime topological sort of dependencies.  It has the property you desire.

 
 
 

Shared library initialization order.

Post by Bernd Striede » Wed, 14 Aug 2002 17:02:32



> Hiya all.

> I've posted this on comp.os.linux.development.apps but got no response
> so I thought I might have more luck here (even though I'm not strictly
> speaking working on the system).

> I have a shared library that depends on another shared library. In
> other OSs (Solaris HP-UX) this causes the global variables in the
> second library to be initialized first but in Linux I see that the
> order of initialization is wholly dependant on the order of the
> libraries on the link line (they get initialized in reverse order to
> that of the link line). In AIX it's possible to give a shared library
> a priority at link time (-qmkshrobj[=priority] ) which is much uglier
> but at least you don't have to worry about the order on link line.

> Is there any way to get g++ to choose the correct initialization
> order?

AFAIK there is no requirement on this in C++. This is why global objects are
usually avoided to make it easier to port between different compilers.
There are techniques to move those globals into function static variables,
or put it on the heap, i.e. only using global pointers. Essentially the
singleton pattern is applied. Those initializations are moved to some time
after main() was called, and they are triggered by user code, in some lazy
way:

     if !initialized
           initialize
     return for use

You might find more on it in the archives comp.lang.c++{.moderated}
comp.std.c++.

Quote:

> Any ideas?
> Also if you think there is another group which may be able to help me
> on this please point it out.

> P.S. Yes I know I could put the libraries in the correct order but
> where's the fun in that? also in real life we're talking about
> something slightly more complex than my sample....

When it gets slightly more complex, then it is no more fun. It is easier to
write code independent from the tools than getting it right each time new
tool releases might have something changed.

Bernd Strieder

 
 
 

Shared library initialization order.

Post by t?' » Wed, 14 Aug 2002 17:15:46


John Reiser bravely attempted to attach 32 electrodes of knowledge to
the *s of comp.os.linux.development.system by saying:

Quote:>    $ LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./runme
>    $ echo $?
>    0
>    $
>which is a correct answer.  That's with glibc-2.2.5-36 that includes
>/lib/ld-linux.so.2 and /lib/{i686}/libc.so.6.  The current ELF spec requires
>that the dynamic loader ld-linux.so.2 perform .so initializations according
>to a runtime topological sort of dependencies.  It has the property you desire.

Yes, it does.
Thanks a lot,  I'll be looking into it.
 
 
 

Shared library initialization order.

Post by Mott » Wed, 14 Aug 2002 17:25:10


Bernd Strieder bravely attempted to attach 51 electrodes of knowledge
to the *s of comp.os.linux.development.system by saying:


>> Hiya all.

>> I've posted this on comp.os.linux.development.apps but got no response
>> so I thought I might have more luck here (even though I'm not strictly
>> speaking working on the system).

>> I have a shared library that depends on another shared library. In
>> other OSs (Solaris HP-UX) this causes the global variables in the
>> second library to be initialized first but in Linux I see that the
>> order of initialization is wholly dependant on the order of the
>> libraries on the link line (they get initialized in reverse order to
>> that of the link line). In AIX it's possible to give a shared library
>> a priority at link time (-qmkshrobj[=priority] ) which is much uglier
>> but at least you don't have to worry about the order on link line.

>> Is there any way to get g++ to choose the correct initialization
>> order?

>AFAIK there is no requirement on this in C++. This is why global objects are
>usually avoided to make it easier to port between different compilers.
>There are techniques to move those globals into function static variables,
>or put it on the heap, i.e. only using global pointers. Essentially the
>singleton pattern is applied. Those initializations are moved to some time
>after main() was called, and they are triggered by user code, in some lazy
>way:

>     if !initialized
>           initialize
>     return for use

It's even simpler than that, you can use a static object, as it's in a
function the object is only created when (and if) the function is
first called and the destructor gets called when the program unloads
(I don't remember if the order of destructors is defined).

MyClass& MySingleton()
{
        static MyClass singleton;
        return singleton;

Quote:}

This way C++ takes care of all the if !initialized stuff for you.

But this is no good for us because we have to deal with lots of
existing code plus clients' code.

P.S. My persona seems to be slipping, Motti == Teh sorry about posting
in the wrong persona before.

 
 
 

Shared library initialization order.

Post by Martin v. L?w » Wed, 14 Aug 2002 17:33:30



> I have a shared library that depends on another shared library. In
> other OSs (Solaris HP-UX) this causes the global variables in the
> second library to be initialized first but in Linux I see that the
> order of initialization is wholly dependant on the order of the
> libraries on the link line (they get initialized in reverse order to
> that of the link line).

That is not the case. Linux will honor dependencies between shared
libraries as well.

Quote:> Is there any way to get g++ to choose the correct initialization
> order?

Define "correct" - the C++ standard is silent on this issue.

In any case, there is a portable way to achieve the behaviour you
desire. Instead of

Quote:> multiplier obj(7,6);

> int usedFunc()
> {
>    return obj;
> }

write

multiplier obj(7,6);

int usedFunc()
{
        static multiplier obj(7,6);
        return obj;

Quote:}

or, if you need access to obj from other places:

multiplier& obj()
{
   static multiplier _obj(7,6);
   return _obj;

Quote:}

int usedFunc(){
  return obj();

Quote:}
> Also if you think there is another group which may be able to help me
> on this please point it out.

On writing portable code, please use a C++ group, such as
comp.lang.c++.moderated. On Linux-specific questions, this group is

Regards,
Martin

 
 
 

Shared library initialization order.

Post by Stephen Hemminge » Fri, 16 Aug 2002 14:46:08


Check out any of the standard C++ FAQ's and they all say don't depend on
static initializer order.
==================================================
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.11

10.11] What's the "static initialization order fiasco"?

A subtle way to kill your project.

The static initialization order fiasco is a very subtle and commonly
misunderstood aspect of C++. Unfortunately it's very hard to detect
the errors occur before main() begins.

In short, suppose you have two static objects x and y which exist in
separate source files, say x.cpp and y.cpp. Suppose further that the
initialization for the y object (typically the y object's constructor)
calls some method on the x object.

That's it. It's that simple.

The tragedy is that you have a 50%-50% chance of dying. If the
compilation unit for x.cpp happens to get initialized first, all is
well. But if the compilation unit for y.cpp get initialized first, then
y's initialization will get run before x's initialization, and you're
toast. E.g., y's constructor could call a method on the x object, yet
the x object hasn't yet been constructed.

I hear they're hiring down at McDonalds. Enjoy your new job flipping
burgers.

If you think it's "exciting" to play Russian Roulette with live rounds
in half the chambers, you can stop reading here. On the other hand if
you like to improve your chances of survival by preventing disasters in
a systematic way, you probably want to read the next FAQ.

Note: The static initialization order fiasco can also, in some cases,
apply to built-in/intrinsic types.



> > I have a shared library that depends on another shared library. In
> > other OSs (Solaris HP-UX) this causes the global variables in the
> > second library to be initialized first but in Linux I see that the
> > order of initialization is wholly dependant on the order of the
> > libraries on the link line (they get initialized in reverse order to
> > that of the link line).

> That is not the case. Linux will honor dependencies between shared
> libraries as well.

> > Is there any way to get g++ to choose the correct initialization
> > order?

> Define "correct" - the C++ standard is silent on this issue.

> In any case, there is a portable way to achieve the behaviour you
> desire. Instead of

> > multiplier obj(7,6);

> > int usedFunc()
> > {
> >       return obj;
> > }

> write

> multiplier obj(7,6);

> int usedFunc()
> {
>         static multiplier obj(7,6);
>         return obj;
> }

> or, if you need access to obj from other places:

> multiplier& obj()
> {
>    static multiplier _obj(7,6);
>    return _obj;
> }

> int usedFunc(){
>   return obj();
> }

> > Also if you think there is another group which may be able to help me
> > on this please point it out.

> On writing portable code, please use a C++ group, such as
> comp.lang.c++.moderated. On Linux-specific questions, this group is

> Regards,
> Martin

 
 
 

Shared library initialization order.

Post by Martin v. L?w » Fri, 16 Aug 2002 17:53:47



> Check out any of the standard C++ FAQ's and they all say don't
> depend on static initializer order.

That might be true if you can't assume a specific compiler. If you
know the compiler is g++ on Linux, you can rely on deterministic and
predictable behaviour.

Regards,
Martin

 
 
 

1. Initialization/Load order of shared libraries

Hello All,

We are working on porting a C++ windows application over to Solaris.
In our app we have a large number of shared libraries. We have gotten
most of our stuff to compile and link, and even sort of work. The
troubling thing is that our libraries are not loaded and/or
initialized in the order we would like them to be, i.e. in dependency
order. For instance, if libB.so depends on libA.so, then it seems
natural that the C++ initializers for libA.so should be called first,
and then those for libB.so. This doesn't seem to be the case, i.e.
libraries seem to get initialized in a pretty haphazard order. This
causes some problems when libB.so depends on global objects exported
from libA.so, and libA.so has not yet been initialized and hence C++
constructors have not been called, often resulting in SEGV when
libB.so is being initialized.

The environment is Solaris 2.8 with SunPro 5.2 (Forte 6 Update 1).

Thanks,
Samar Lotia

2. Curious about bt946c

3. Shared Library Initialization Solaris 2.5

4. Linux help manual

5. C++ shared library initialization

6. Shell script question

7. shared library initialization

8. rdist changes symlink owner to root

9. Shared Library Initialization Function?

10. order of init shared libraries

11. Q: shared libraries, modified search order

12. Order in which shared libraries are loaded at runtime

13. Search order for shared libraries (ld-linux.so and ldconfig)