Hi, Steve, Thank you so much!!! I will try -instlib option :)
Regards, Steve Clamage wrote: > The std::string<T> class template depends on having only one > __null_string_ref_rep<T> in the entire program. > > The std::string template is pre-instantiated on char and wchar_t, in > which case the only __null_string object is already in libCstd, and > does not get replicated. > > I think the problem comes from creating a std::string on another type, > unsigned int in your case. You need to take steps to ensure only one > copy of __null_string_ref_rep<T> exists, for any T other than char or > wchar_t. > > You can do that by building libraries in hierarchical order, bottom > up, and using the -instlib option to prevent instances of the same > template from being generated in more than one library. Here is how: > > 1. Determine the (partial) ordering of library dependencies. There > must be no cycle in the dependency graph. > > 2. Build the lowest-level library first, the one which depends on no > other project library. Call it libA.so. > > 3. Build the next-higher library, call it libB, which depends on libA. > For each CC command that creates a .o file that will go into libB, add > the option > -instlib=/path/to/libA.so > > 4. Build the next-higher library, libC.so. For each CC command that > creates a .o file that will go into libC, add the options > -instlib=/path/to/libA.so -instlib=/path/to/libB.so > (assuming libC depends on both libA and libB). > > You need an -instlib option only for a library on which the current > library depends (directly or transitively). > > You can read more about the -instlib option in the C++ Users Guide > Appendix on command-line options. The option causes the the compiler > to scan the named library for template instances (and inline functions > generated out of line), and omit generating them in the current .o > file. In my example, libB will contain no template instance that > occurs in libA, and libC will contain no template instance that occurs > in libA or libB. > > We are planning to add the capability to the compiler and Solaris > linker to specify that an object must be a singleton, which will > eliminate the need for this elaborate build process just to fix the > _null_string problem. We do not have a projected date for the new > option. You might still need to use -instlib to eliminate other > circular references, however. > > --- > Steve Clamage, stephen.clamage at sun.com > > On 6/22/2007 8:32 PM, Yong Sun wrote: >> 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. >>>> >>