Created attachment 27214 [details]
generated linker script
Not sure which heading collect2 goes under; placed in c++ heading by default.
We use a linker script to control static initialization order. We manually maintain files that give intra- and inter-project dependencies from which a tool produces a partial ordering file that is added to each project library. Before linking, another tool collects the partial order files of all libraries referenced on the link command line to produce a global partial order for the program being linked. It then takes the default linker script that gcc uses and textually modifies it with linker commands that reflect the partial order. We then pass the modified script to gcc on the gcc linker command line, which invokes collect2 and the system linker in the normal way.
For this to work we depend on the collect2 priority sort defaulting to the file order that the system gives it on the first link pass. That is, we depend on the sort being stable in the absence of program-specified priorities, which we do not use (priority is impractical for large developments that incorporate third-party binaries; our system uses local relative dependency rather than trying to maintain global absolute priority).
This has worked for a decade, but breaks in 4.7. Because we are using the same linker I conclude that there have been changes in collect2, most likely the introduction of an unstable sort.
I will attach a representative script generated by our system.
I don't think this is collect2 changing the order but rather .init_array which changes the order.
See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46770#c76 for more info. Really any dependance on link order is invalid for C++ code.
Wow - this will break a lot of big users - we are far from the only ones who find priorities unusable.
BTAIM, it appears that our choice is to use an option (there is one? what?) to force 4.7 to continue to use ctors, or to use some other option (there is one? what?) to force 4.7 to process init_array in reverse order from what it does by default.
Of these two, which do you recommend as a workaround? Are there any other choices?
Looking a little further at this, I don't think we can use init_array at all, even if it ran in reverse order.
Consider TUs in a .a library, where some of the TUs have an order dependency with other TUs in the same library. If I understand the way init_array works (doubtful), the init_array will be populated with TUs in command line order; the assumption is that libraries at the end of the list are more primitive, and so will need to be initialized first. Or maybe the order is reversed; either way, it is determined by the command line.
However, if several TUs are picked up from a single library then they will be ordered w/r/t files from a different library, but will be in random order w/r/t files from the same library. This breaks the asserted intra-library dependency.
As far as I can tell from the discussion there is no way to control the init_array populating process other than priority, which as previously mentioned is unusable in a large environment with third-party binaries.
Hence we need some way to force gcc to continue to use ctors instead of init_array. I find no documented option to do that - have I overlooked it, or does it not exist?
Or have I misunderstood init_array (all to likely)?
Really you should not be dependent on the order since that has even been defined. Yes you would think it would be defined but it was never a guarantee.
Yes, but. Order is not defined, but order dependencies are inescapable in C++ which has a tendency to invoke constructors where you least expect them - when you #include a file for example. The naive sometimes advocate lazy init, doing dynamic initialization in each accessor; they have never had to deal with thread convoying behind the lock in the accessor. Others advocate having an init phase where explicit calls spread out from main() and allocate (and initialize) whatever each module needs; they have never dealt with objects that must be static because new() is unavailable for hardware reasons.
I'm not asking for the behavior to be defined; you are right that the language does not demand that. But we mere users need to control the undefined behavior, and so we need hooks to use for that control. Apparently a usable set of hooks just gratuitously went away.
(In reply to comment #3)
> Wow - this will break a lot of big users - we are far from the only ones who
> find priorities unusable.
> BTAIM, it appears that our choice is to use an option (there is one? what?) to
> force 4.7 to continue to use ctors, or to use some other option (there is one?
> what?) to force 4.7 to process init_array in reverse order from what it does by
> Of these two, which do you recommend as a workaround? Are there any other
you can use gold linker. it have nice options:
$ ld.gold --help|grep ctors
--ctors-in-init-array Use DT_INIT_ARRAY for all constructors (default)
--no-ctors-in-init-array Handle constructors as directed by compiler
(In reply to comment #7)
> you can use gold linker. it have nice options:
> $ ld.gold --help|grep ctors
> --ctors-in-init-array Use DT_INIT_ARRAY for all constructors (default)
> --no-ctors-in-init-array Handle constructors as directed by compiler
Just for the record:
Until we are able to remove inter-CU order dependencies in our code, we are sticking with:
# prevent GCC from generating init_array:
gcc-4.7/configure --disable-initfini-array ...
# make gold use .ctors (we configure gcc to use gold)
gcc-4.7 main.o ... -Wl,--no-ctors-in-init-array
I believe this fully restores the "legacy" (gcc-4.6) ordering.
There is nothing to be fixed here, .init_array should be used no matter what.
You can do the same thing you do with ctors as you can with init_array but init_array is actually nicer in general :).