Hi, Steve, Thank you very much!
In my case (the dltest.tar), when the main program call dlopen ("libtest.so"), it resolves the dependencies, then adds libbase.so in the initialization sequence ahead of libtest.so (the order is reversed). And we all knew that the static constructors in a shared library are in the .init routine. While it's trying to initialize the static object "bar" in libbase.so, it finds there is a symbol "xxx::__null_string_ref_rep<xxx>" (introduced by std::basic_string<unsigned int>), then looks up this symbol in loaded libraries. Firstly, it looks up the symbol in main program, then in libc.so, then finds matched one in libtest.so, and stops to move on (actually, libbase.so also has this symbol). Then it tries to initialize libtest.so, and initializes the static object "foo". Unfortunately, the constructor of Foo calls a external function in libbase, and this function accesses the static instance "bar", which is not initialized yet (the "buf" is not allocated). So the main program cores. I am not sure, maybe the ld.so should first lookup the symbol in the current initializing shared library, i.e., libbase.so? Regards, Steve Clamage wrote: > We have a deliberate, although possibly mis-guided, interaction > between libCrun and libCstd initialization. To ensure that C++ > iostreams are initialized soon enough, CCrti (program startup code for > C++) calls a routine in libCun that has a table of initialization > routines that are done first. The only entry in the table currently is > the one to initialize iostreams in libCstd. (It uses a weak symbol > definition for the target, so if libCstd is not linked, nothing happens.) > > If a user program has a proper dependency on libCstd, this bouncing > between libCrun and libCstd, and their respective initializations, > should finish before any user library starts its initialization. At > least, that's how it seems to me. > > Do we have a case where a user program has a dependency on libCstd, > but sill mixes its initialization with that of libCstd? If so, I'd > like to know how that happened, and what we could do to ensure that > doesn't happen. > > We are now looking again at the iostream issue. I think we can arrange > for libCrun to initialize itself without any reference to libCstd, and > for libCstd to ensure that iostreams are initialized first. > > If we make that change, programs that now use libCstd but have no > dependency on it, might stop working. I consider such a situation to > be user error (correct me if I am wrong), in which case the change > doesn't bother me. > > --- > Steve Clamage, stephen.clamage at sun.com > > > On 06/21/07 17:45, Rod Evans wrote: >> Yong Sun wrote: >>> Hi, Rod, >>> >>> I finally isolated the problem to very simple example C/C++ source >>> files, as attached. If you have interests, you could extract the tar >>> file, and run gmake. Then you could see, test would core, while >>> test2 would succeed. >> >> Someone from C++ land is going to have to unravel this. >> >> There are multiple instances of the same symbol in different libraries, >> cyclic dependencies, and .init code that jumps all over the place. >> >> Set LD_DEBUG=.init and we start seeing: >> >> 04973: 1: calling .init (from sorted order): /usr/lib/libCrun.so.1 >> 04973: 1: >> 04973: 1: calling .init (dynamically triggered): /usr/lib/libCstd.so.1 >> 04973: 1: >> 04973: 1: warning: calling /usr/lib/libCrun.so.1 whose init has not >> completed >> 04973: 1: >> 04973: 1: calling .init (dynamically triggered): ./libtest.so >> 04973: 1: >> 04973: 1: calling .init (dynamically triggered): >> /home/rie/dltest/libbase.so >> 04973: 1: >> 04973: 1: warning: calling ./libtest.so whose init has not completed >> 04973: 1: >> 04973: 1: warning: calling ./libtest.so whose init has not completed >> 04973: 1: >> 04973: 1: warning: calling /usr/lib/libCrun.so.1 whose init has not >> completed >> 04973: 1: >> 04973: 1: warning: calling /usr/lib/libCrun.so.1 whose init has not >> completed >> >> Now I can't tell you that these indicate problems or not, as there is no >> way to determine whether a reference to another object requires that >> object >> to have completed its .init for the reference to be valid. Meaning, if >> data is updated by a .init, and that data is referenced before the .init >> has completed, are you in trouble? >> >> If you expand a little with init,bindings: >> >> 04948: 1: calling .init (from sorted order): /usr/lib/libCrun.so.1 >> ...... >> 04948: 1: binding file=/usr/lib/libCrun.so.1 to >> file=/usr/lib/libCstd.so.1: \ >> symbol `__SUNW_force_load_of_inits' >> 04948: 1: >> 04948: 1: calling .init (dynamically triggered): /usr/lib/libCstd.so.1 >> >> Hmmm, __SUNW_force_load_of_inits - that looks scary. >> >> 04948: 1: binding file=/usr/lib/libCstd.so.1 to >> file=/usr/lib/libCrun.so.1: \ >> symbol `__1cG__CrunSregister_exit_code6FpG_v_v_ >> 04948: 1: >> 04948: 1: warning: calling /usr/lib/libCrun.so.1 whose init has not >> completed >> >> So, you have libCruns .init calling libCstd.so.1, and libCstds .init >> calling >> libCrun.so.1 >> >> The scenario continues through your other objects. >> >> The runtime linker is simply jumping from object to object as directed, >> and trying frantically to fire .init's before an object is called. When >> cyclic dependencies exist, you can't programaticaly determine a >> "correct" >> order, so the dynamic firing attempts to compensate - and from >> experience >> we know that without this "compensation" a whole mess of applications >> would already be falling over. >> >> I'll stick by my concluding remarks from >> >> http://blogs.sun.com/rie/entry/init_and_fini_processing_who >> >> and let's see if someone from C++ can enlighten us some more. >>