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.
>>>>
>>


Reply via email to