Considering .init_array/.fini_array has been supported by glibc for 11 years ( http://sourceware.org/git/?p=glibc.git;a=commitdiff;h=fcf70d4114db9ff7923f5dfeb3fea6e2d623e5c2;hp=3f3822198993be18d4d9ccb1593eea274dbd2ba0 ), it would make sense to use these instead of .ctors/.dtors, on systems supporting them.
Using .init_array/.fini_array instead of .ctors/.dtors removes the need for the associated (relative) relocations, and avoids the backwards disk seeks on startup (since while .ctors are processed backwards, .init_array is processed forward)
Hmm, is it possible to do the change without breaking ABI (i.e. preserving the proper relative order for binary built with init_arra/fini_array linked with ctors/dtors library and vice versa? Honza
(In reply to comment #2) > Hmm, is it possible to do the change without breaking ABI (i.e. preserving the > proper relative order for binary built with init_arra/fini_array linked with > ctors/dtors library and vice versa? Yes.
Created attachment 22671 [details] A patch I am testing this patch.
(In reply to comment #2) > Hmm, is it possible to do the change without breaking ABI (i.e. preserving the > proper relative order for binary built with init_arra/fini_array linked with > ctors/dtors library and vice versa? > Honza [hjl@gnu-6 46770]$ cat foo.c #include <stdio.h> static void init () { printf ("init_array\n"); } static void (*const init_array []) () __attribute__ ((section (".init_array"), aligned (sizeof (void *)))) = { init }; static void fini () { printf ("fini_array\n"); } static void (*const fini_array []) () __attribute__ ((section (".fini_array"), aligned (sizeof (void *)))) = { fini }; static void ctor () { printf ("ctor\n"); } static void (*const ctors []) () __attribute__ ((section (".ctors"), aligned (sizeof (void *)))) = { ctor }; static void dtor () { printf ("dtor\n"); } static void (*const dtors []) () __attribute__ ((section (".dtors"), aligned (sizeof (void *)))) = { dtor }; int main () { printf ("main\n"); } [hjl@gnu-6 46770]$ gcc foo.c [hjl@gnu-6 46770]$ ./a.out ctor init_array main fini_array dtor [hjl@gnu-6 46770]$
Another test: [hjl@gnu-6 pr46770]$ cat foo.c #include <stdio.h> int main () { printf ("main\n"); return 0; } [hjl@gnu-6 pr46770]$ cat foo1.c #include <stdio.h> static void init () { printf ("init_array\n"); } static void (*const init_array []) () __attribute__ ((used, section (".init_array"), aligned (sizeof (void *)))) = { init }; static void fini () { printf ("fini_array\n"); } static void (*const fini_array []) () __attribute__ ((used, section (".fini_array"), aligned (sizeof (void *)))) = { fini }; [hjl@gnu-6 pr46770]$ cat foo2.c #include <stdio.h> static void ctor () { printf ("ctor\n"); } static void (*const ctors []) () __attribute__ ((used, section (".ctors"), aligned (sizeof (void *)))) = { ctor }; static void dtor () { printf ("dtor\n"); } static void (*const dtors []) () __attribute__ ((used, section (".dtors"), aligned (sizeof (void *)))) = { dtor }; [hjl@gnu-6 pr46770]$ make gcc -O -fPIC -c -o foo.o foo.c gcc -O -fPIC -c -o foo1.o foo1.c gcc -O -fPIC -c -o foo2.o foo2.c gcc -shared -o libfoo2.so foo2.o gcc -o foo1 foo.o foo1.o libfoo2.so -Wl,-R,. gcc -shared -o libfoo1.so foo1.o gcc -o foo2 foo.o libfoo1.so foo2.o -Wl,-R,. gcc -o foo3 foo.o foo1.o foo2.o ./foo1 ctor init_array main fini_array dtor ./foo2 init_array ctor main dtor fini_array ./foo3 ctor init_array main fini_array dtor [hjl@gnu-6 pr46770]$
Hi, thanks for testcase. What I was concerned about is the static linking case. When you have static library with constructors and main program with constructors, my understanding was that the reverse execution order of .ctor section was designed in a way so library even in this case is initialized first. Now because ctors are handled before init_array, this no longer happen. I.e. when I turn foo1.c into library (and add function used from foo.o) and compile as gcc -o foo4 foo2.o foo.o -l foo -L. I still get init_array main fini_array dtor i.e. the library is initialized later. I am not sure that this is actual requirement, or QOI issue or just something I was told to explain why ctor section is executed backwards while dtors forward (it would make more sense performance wise to reverse this). But in order to approve the patch I need to unerstand this better... Honza
(In reply to comment #7) > Hi, > thanks for testcase. What I was concerned about is the static linking case. > When you have static library with constructors and main program with > constructors, my understanding was that the reverse execution order of .ctor > section was designed in a way so library even in this case is initialized > first. > > Now because ctors are handled before init_array, this no longer happen. I.e. > when I turn foo1.c into library (and add function used from foo.o) and compile > as > gcc -o foo4 foo2.o foo.o -l foo -L. > I still get > init_array > main > fini_array > dtor > i.e. the library is initialized later. > > I am not sure that this is actual requirement, or QOI issue or just something I > was told to explain why ctor section is executed backwards while dtors forward > (it would make more sense performance wise to reverse this). But in order to > approve the patch I need to unerstand this better... > For static linking, there is no difference between gcc -o foo foo2.o foo.o vs gcc -o foo foo2.o -lfoo -L. We guarantee the relative order of constructors vs. destructors. The test in comment 5 shows it works fine with mixed .init_array and .ctors.
(In reply to comment #7) > Hi, > thanks for testcase. What I was concerned about is the static linking case. > When you have static library with constructors and main program with > constructors, my understanding was that the reverse execution order of .ctor > section was designed in a way so library even in this case is initialized > first. This explanation doesn't stand: for instance, ARM EABI exclusively uses .init_array, and the execution order for those is forward. And when linking static libraries, the order of the function pointers in the section is strictly growing, which means libraries are being initialized last.
> This explanation doesn't stand: for instance, ARM EABI exclusively uses > .init_array, and the execution order for those is forward. And when linking > static libraries, the order of the function pointers in the section is strictly > growing, which means libraries are being initialized last. I noticed that EABI is reversed versus .ctor/.dtor ABIs. So I guess we need to decide 1) is there any kind of any documented requirement on initialization of static libraries? (i.e. is EABI fully standard conforming?) 2) I believe that the backwarding order of .ctor section was concious QOI issue. I wonder how much legacy code this might break when static libraries start initializing after main modules. i686-linux execute a lot more code than EABI. Note that we make the situation bit worse than EABI has as the scheme is not strictly backwards or strictly forwards, but combination of both depending what compiler built the code. This probably does not make much of practical difference. Said that, I am personally happy with the patch and see how it should noticeably improve C++ startup times even with the recent ctor/dtor grouping code. Even if we basically eliminate the backward reading in text section, we still will have tendency to initialize data segment in backwarding order. I would like to hear opinion of someone who knows how these things was introduced (Iant, hopefully?) and if the patch is going to 4.6.0, I think we should get approval from one of our release managers. It is bit late for this patch now, though I think it qualify being a patch affecting one target only. Honza
(In reply to comment #10) > > This explanation doesn't stand: for instance, ARM EABI exclusively uses > > .init_array, and the execution order for those is forward. And when linking > > static libraries, the order of the function pointers in the section is strictly > > growing, which means libraries are being initialized last. > > I noticed that EABI is reversed versus .ctor/.dtor ABIs. So I guess we need to > decide > > 1) is there any kind of any documented requirement on initialization of > static libraries? (i.e. is EABI fully standard conforming?) There is no difference in initialization between linking against libfoo.a vs foo.o. > 2) I believe that the backwarding order of .ctor section was concious > QOI issue. I wonder how much legacy code this might break when static > libraries start initializing after main modules. Static libraries are LINKED INTO main module. I don't understand this question. > i686-linux execute a lot more code than EABI. > > Note that we make the situation bit worse than EABI has as the scheme is not > strictly backwards or strictly forwards, but combination of both depending what > compiler built the code. This probably does not make much of practical > difference. My patch guarantee the relative order of constructors vs. destructors, as we do now. GCC never guarantees the order of constructors. Please note' that even within single source file, there is no guarantee that foo will be initialized before bar in --- Foo foo; Bar bar; --- > Said that, I am personally happy with the patch and see how it should > noticeably > improve C++ startup times even with the recent ctor/dtor grouping code. Even if > we > basically eliminate the backward reading in text section, we still will have > tendency > to initialize data segment in backwarding order. > > I would like to hear opinion of someone who knows how these things was > introduced (Iant, hopefully?) and if the patch is going to 4.6.0, I think we > should get approval from one of our release managers. It is bit late for this > patch now, though I think it qualify being a patch affecting one target only. > I worked with Cary on the .init_array gABI spec and implemented it in gas/ld/glibc. I am the person who knows how these things was introduced and how they work.
> > 2) I believe that the backwarding order of .ctor section was concious > > QOI issue. I wonder how much legacy code this might break when static > > libraries start initializing after main modules. > > Static libraries are LINKED INTO main module. I don't understand > this question. I meant the object files that are not in the library. By the way linker works, first placing the object files it is given and then resolving dependencies by getting more from the libraries, the reverse initialization order ensure that the object files from libraries are initialized before object files needing them. > > My patch guarantee the relative order of constructors vs. destructors, > as we do now. GCC never guarantees the order of constructors. Please note' > that even within single source file, there is no guarantee that foo will > be initialized before bar in Yes, I know that within single file the order is undefined. All I am concerned about are the libraries. > > I worked with Cary on the .init_array gABI spec and implemented > it in gas/ld/glibc. I am the person who knows how these things was > introduced and how they work. OK, do you know why the order of execution of .ctor was chosen to be reversed even if it would make more sense to reverse .dtors? Honza > > -- > Configure bugmail: http://gcc.gnu.org/bugzilla/userprefs.cgi?tab=email > ------- You are receiving this mail because: ------- > You are on the CC list for the bug.
(In reply to comment #12) > > > 2) I believe that the backwarding order of .ctor section was concious > > > QOI issue. I wonder how much legacy code this might break when static > > > libraries start initializing after main modules. > > > > Static libraries are LINKED INTO main module. I don't understand > > this question. > > I meant the object files that are not in the library. By the way linker works, > first placing the object files it is given and then resolving dependencies by > getting more from the libraries, the reverse initialization order ensure that > the object files from libraries are initialized before object files needing > them. Not necessarily. You can have ... y.o -lbar x.o -lfoo z.o -lbar -lfoo ... ... y.o --start-group -lbar x.o -lfoo --end-group ... As a linker developer, I will say what you described depends on command line options. We never guarantee that constructors in libbar.a will be called in any particular order relative to constructors in any other object files. > > My patch guarantee the relative order of constructors vs. destructors, > > as we do now. GCC never guarantees the order of constructors. Please note' > > that even within single source file, there is no guarantee that foo will > > be initialized before bar in > > Yes, I know that within single file the order is undefined. All I am concerned > about are the libraries. > > > > I worked with Cary on the .init_array gABI spec and implemented > > it in gas/ld/glibc. I am the person who knows how these things was > > introduced and how they work. > > OK, do you know why the order of execution of .ctor was chosen to be reversed > even if it would make more sense to reverse .dtors? > I agree that the order looks odd. That was chosen when the g++ compiler was first implemented almost 20 years ago. Without .init_array, we had to do all those crazy stuff in crt*.o. We never bothered to change it. However, the order shouldn't make a difference. That is # gcc foo.o bar.o # gcc bar.o foo.o should work the same way. We introduced .init_array into gABI 10 years ago so that we can avoid those crazy things in crt*.o. It is the time now to switch for Linux/x86/
H.J. -- Some of the statements that you're making in Comment #11 are inaccurate or unclear: Given: Foo foo(...); Bar bar(...); within a single module, the C++ standard guarantees that foo is initialized before bar. See \S 3.6.2 "Initialization of non-local objects": "Other objects defined in namespace scope have ordered initialization. Objects defined within a single translation unit and with ordered initialization shall be initialized in the order of their definitions in the translation unit." Now, it is true that if foo or bar is zero-initialized or constant-initialized (these are terms of art in the C++ standard) that initialization happens before dynamic initialization, so given: Foo foo(...); int i = 3; It is guaranteed that "i" is initialized before "foo". But, even in that case, the order is well-defined; it's just not necessarily the order in which the objects are declared. Although the C++ standard does not impose requirements on initialization order across translation units (i.e., source files), there is no doubt that programs accidentally or intentionally depend upon it. I'm sure that making changes in this regard will break something. But, such breakage is akin to the breakage that occurs whenever we optimize more aggressively; people depend on current undocumented behaviors, and programs break when we make a change. So, I don't think we should resist making the change to .init_array simply on this ground. On the other hand, we do have an issue around constructor priorities. If I recall correctly, the linker sorts all of the .ctors.NNNNN sections into a single array which is then executed in order. So, if the program has some object files built using .ctors.NNNNN and others using .init_array, I don't see how we can get the interleaving that is specified in the source code.
(In reply to comment #14) > H.J. -- > > Some of the statements that you're making in Comment #11 are inaccurate or > unclear: > > Given: > > Foo foo(...); > Bar bar(...); > > within a single module, the C++ standard guarantees that foo is initialized > before bar. See \S 3.6.2 "Initialization of non-local objects": > > "Other objects defined in namespace scope have ordered initialization. Objects > defined within a single translation unit and with ordered initialization shall > be initialized in the order of their definitions in the translation unit." > > Now, it is true that if foo or bar is zero-initialized or constant-initialized > (these are terms of art in the C++ standard) that initialization happens before > dynamic initialization, so given: > > Foo foo(...); > int i = 3; > > It is guaranteed that "i" is initialized before "foo". But, even in that case, > the order is well-defined; it's just not necessarily the order in which the > objects are declared. Thanks for correction/clarification. > Although the C++ standard does not impose requirements on initialization order > across translation units (i.e., source files), there is no doubt that programs > accidentally or intentionally depend upon it. I'm sure that making changes in > this regard will break something. But, such breakage is akin to the breakage > that occurs whenever we optimize more aggressively; people depend on current > undocumented behaviors, and programs break when we make a change. So, I don't > think we should resist making the change to .init_array simply on this ground. That is very true, specially for LTO. > On the other hand, we do have an issue around constructor priorities. If I > recall correctly, the linker sorts all of the .ctors.NNNNN sections into a > single array which is then executed in order. So, if the program has some > object files built using .ctors.NNNNN and others using .init_array, I don't see > how we can get the interleaving that is specified in the source code. Linker supports sorting .ctors.NNNNN and .init_array.NNNN. Within .ctors.NNNNN and .init_array.NNNN, the order is defined. And ctors.NNNNN will be called before .init_array.NNNN. If you have constructor priorities in .o files and .c files, you may get different behaviors if .o files are compiled with a different compiler, different versions of GCC or not GCC at all.
On 12/11/2010 10:47 AM, hjl.tools at gmail dot com wrote: > Linker supports sorting .ctors.NNNNN and .init_array.NNNN. > Within .ctors.NNNNN and .init_array.NNNN, the order is defined. > And ctors.NNNNN will be called before .init_array.NNNN. Really? I thought all of ctors.NNNN got sorted into a single big block. If the GNU linker (and GOLD) know how to interleave .ctors.NNNNN with .init_array.NNNNN so that constructor priority is honored even when mixing .ctors and .init_array, then I think we're OK.
(In reply to comment #16) > On 12/11/2010 10:47 AM, hjl.tools at gmail dot com wrote: > > > Linker supports sorting .ctors.NNNNN and .init_array.NNNN. > > Within .ctors.NNNNN and .init_array.NNNN, the order is defined. > > And ctors.NNNNN will be called before .init_array.NNNN. > > Really? I thought all of ctors.NNNN got sorted into a single big block. Linker script has .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); } .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .); } .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(SORT(.fini_array.*))) KEEP (*(.fini_array)) PROVIDE_HIDDEN (__fini_array_end = .); } .ctors : { /* gcc uses crtbegin.o to find the start of the constructors, so we make sure it is first. Because this is a wildcard, it doesn't matter if the user does not actually link against crtbegin.o; the linker won't look for a file to match a wildcard. The wildcard also means that it doesn't matter which directory crtbegin.o is in. */ KEEP (*crtbegin.o(.ctors)) KEEP (*crtbegin?.o(.ctors)) /* We don't want to include the .ctor section from the crtend.o file until after the sorted ctors. The .ctor section from the crtend file contains the end of ctors marker and it must be last */ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } .dtors : { KEEP (*crtbegin.o(.dtors)) KEEP (*crtbegin?.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } > If the GNU linker (and GOLD) know how to interleave .ctors.NNNNN with > .init_array.NNNNN so that constructor priority is honored even when > mixing .ctors and .init_array, then I think we're OK. I am not sure about GOLD. But it usually follows GNU linker. For GNU linker, the constructor priority is honored within .ctors.NNNNN and .init_array.NNNNN. ctors.NNNNN will be called before .init_array.NNNN.
On 12/11/2010 11:03 AM, hjl.tools at gmail dot com wrote: > I am not sure about GOLD. But it usually follows GNU linker. > For GNU linker, the constructor priority is honored within > .ctors.NNNNN and .init_array.NNNNN. ctors.NNNNN will be called > before .init_array.NNNN. From the linker script fragment you're showing we're not going to get the right behavior. In particular, all .ctors.* are going to get called before any .init_array.*, or vice versa; we won't interleave the two appropriately. So, if I understand correctly, we have a critical problem with switching to .init_array; we'll fail to conform to the specification for GNU constructor priorities.
Created attachment 22717 [details] A demo of mixing .init_array and .ctors Here is a demo of mixing .init_array and .ctors with priority. initp1.o uses .ctors and initp2.o uses .init_array.
(In reply to comment #12) > OK, do you know why the order of execution of .ctor was chosen to be reversed > even if it would make more sense to reverse .dtors? > Now I remembered. The reverse order of execution of .ctor is to support constructor priorities. We can't change it without breaking existing objects.
H.J. -- Let's just answer the yes-or-no question: is the interleaving going to work or isn't it? I can't see how it possibly can, given the linker script fragment you posted. And if it can't, we have a correctness problem. -- Mark
(In reply to comment #21) > H.J. -- > > Let's just answer the yes-or-no question: is the interleaving going to work or > isn't it? > You have to be more specific about what you meant by "interleaving". Please show me a C++ example.
(In reply to comment #22) > (In reply to comment #21) > > H.J. -- > > > > Let's just answer the yes-or-no question: is the interleaving going to work or > > isn't it? > > > > You have to be more specific about what you meant by "interleaving". > Please show me a C++ example. I have said "If you have constructor priorities in .o files and .c files, you may get different behaviors if .o files are compiled with a different compiler, different versions of GCC or not GCC at all."
On 12/11/2010 11:53 AM, hjl.tools at gmail dot com wrote: >> You have to be more specific about what you meant by "interleaving". Constructor priorities are a GNU C extension: __attribute__((constructor(<priority>))) > I have said "If you have constructor priorities in .o files and .c > files, you may get different behaviors if .o files are compiled with > a different compiler, different versions of GCC or not GCC at all." Well, it sounds to me, then, that we would be introducing a binary compatibility problem to make this change. If we're going to do it, I think that means adding linker smarts that detect that there are both .ctor.* and .init_array.* sections and issuing an error -- not a warning -- together with a hint as to how to recompile so as to get either the new or old behavior. (Some people will have binary libraries they can't recompile, so we need to explain how to compile new code so that it still uses .ctor.*.)
(In reply to comment #24) > > I have said "If you have constructor priorities in .o files and .c > > files, you may get different behaviors if .o files are compiled with > > a different compiler, different versions of GCC or not GCC at all." > > Well, it sounds to me, then, that we would be introducing a binary > compatibility problem to make this change. If we're going to do it, I Shared libraries are OK. Only static ones may have this issue. > think that means adding linker smarts that detect that there are both > .ctor.* and .init_array.* sections and issuing an error -- not a warning I will work on a linker patch. > -- together with a hint as to how to recompile so as to get either the > new or old behavior. (Some people will have binary libraries they can't > recompile, so we need to explain how to compile new code so that it > still uses .ctor.*.) We need a gcc option to select .ctor or .init_array.
(In reply to comment #24) > Well, it sounds to me, then, that we would be introducing a binary > compatibility problem to make this change. If we're going to do it, I > think that means adding linker smarts that detect that there are both > .ctor.* and .init_array.* sections and issuing an error -- not a warning > -- together with a hint as to how to recompile so as to get either the > new or old behavior. (Some people will have binary libraries they can't > recompile, so we need to explain how to compile new code so that it > still uses .ctor.*.) Another thing, you have a binary archive with constructor priorities and you want to "interleave" your constructor priority with it: 1. It may not be possible due to priority integer. 2. You have to look at section name. 3. If a library uses .init_array, the priority digit in section name is different from the source. I don't think GCC really supports interleaving constructor priority at binary level. Unless GCC can guarantees one can interleave constructor priority in object files, I don't think we should worry about it with .init_array.
On 12/11/2010 12:17 PM, hjl.tools at gmail dot com wrote: > I don't think GCC really supports interleaving constructor priority > at binary level. Unless GCC can guarantees one can interleave constructor > priority in object files I don't understand this comment at all. GCC honors constructor priorities across object files and has for ages.
So I take that, the ctor order is to support priotities, since the .ctor.priority sections get merged into single and ordered in increasing rather than decreasing order, while init_array gets around the problem. > Shared libraries are OK. Only static ones may have this issue. > > > think that means adding linker smarts that detect that there are both > > .ctor.* and .init_array.* sections and issuing an error -- not a warning > > I will work on a linker patch. Can't linker be told to translate .ctor section into init_array upon seeing the fact that both are used? (or just do it by default) > > We need a gcc option to select .ctor or .init_array. We can have that, but I can imiagine this to be hard to handle for users when dealing with environment having multiple compiler - i.e. user can use icc or PathScale (or old GCC) that uses .ctors and it will be refused to link with system library because that one was built with new GCC... Also with LTO we probably want to swap the construction and destruction order. I immitated the ctor/dtor mechanizm. Given that things can be freely reversed, I would go for that. Also it would be nice to decide if LTO is right WRT mixing LTO and non-LTO objects together. Thanks for explanation! Honza
On 12/11/2010 1:01 PM, hubicka at ucw dot cz wrote: > So I take that, the ctor order is to support priotities, since the > .ctor.priority sections get merged into single and ordered in increasing rather > than decreasing order, while init_array gets around the problem. I don't think "gets around the problem" is true. In both cases, you need to honor the order of constructor priorities. That's a GNU C extension, so not part of most standard ABIs, but it's one people use. Whether you use .ctor.* or .init_array, you have a bunch of stuff that has to run in a particular order and the linker has to make sure that happens. > Can't linker be told to translate .ctor section into init_array upon > seeing the fact that both are used? (or just do it by default) Maybe... Certainly, linker magic seems like the obvious way to solve a binary compatibility problem.
(In reply to comment #27) > On 12/11/2010 12:17 PM, hjl.tools at gmail dot com wrote: > > > I don't think GCC really supports interleaving constructor priority > > at binary level. Unless GCC can guarantees one can interleave constructor > > priority in object files > > I don't understand this comment at all. GCC honors constructor > priorities across object files and has for ages. Say I gave you an object with header --- class Two { private: int i, j, k; public: static int count; Two( int ii, int jj ) { i = ii; j = jj; k = count++; }; Two( void ) { i = 0; j = 0; k = count++; }; int eye( void ) { return i; }; int jay( void ) { return j; }; int kay( void ) { return k; }; }; extern Two foo; -- 1. How do you find out what priority "foo" constructor has? 2. How do you run your constructor before "foo"?
Just to make it clear. We support --- `init_priority (PRIORITY)' In Standard C++, objects defined at namespace scope are guaranteed to be initialized in an order in strict accordance with that of their definitions _in a given translation unit_. No guarantee is made for initializations across translation units. However, GNU C++ allows users to control the order of initialization of objects defined at namespace scope with the `init_priority' attribute by specifying a relative PRIORITY, a constant integral expression currently bounded between 101 and 65535 inclusive. Lower numbers indicate a higher priority. In the following example, `A' would normally be created before `B', but the `init_priority' attribute has reversed that order: Some_Class A __attribute__ ((init_priority (2000))); Some_Class B __attribute__ ((init_priority (543))); Note that the particular values of PRIORITY do not matter; only their relative ordering. --- It works at source code level. I don't believe we ever support "interleaving constructor priorities" between object files, with .ctors or .init_array.
On 12/11/2010 2:56 PM, hjl.tools at gmail dot com wrote: > It works at source code level. I don't believe we ever support > "interleaving constructor priorities" between object files, with > .ctors or .init_array. You can definitely use different priorities in different object files and be guaranteed that the constructors will be run in numerical priority order across object files. That's the whole point of the feature.
(In reply to comment #32) > On 12/11/2010 2:56 PM, hjl.tools at gmail dot com wrote: > > > It works at source code level. I don't believe we ever support > > "interleaving constructor priorities" between object files, with > > .ctors or .init_array. > > You can definitely use different priorities in different object files > and be guaranteed that the constructors will be run in numerical > priority order across object files. That's the whole point of the feature. You still didn't answer my questions: 1. How do you find out what priority "foo" constructor has? 2. How do you run your constructor before "foo"?
On 12/11/2010 3:28 PM, hjl.tools at gmail dot com wrote: > 1. How do you find out what priority "foo" constructor has? If you're looking at source code, read the source. If you're looking at object code, look at what section the constructor is in; the numerical value of .ctor.NNNNN indicates the priority. > 2. How do you run your constructor before "foo"? Given it a higher priority.
(In reply to comment #34) > On 12/11/2010 3:28 PM, hjl.tools at gmail dot com wrote: > > > 1. How do you find out what priority "foo" constructor has? > > If you're looking at source code, read the source. This is not the problem. > If you're looking at > object code, look at what section the constructor is in; the numerical > value of .ctor.NNNNN indicates the priority. You have 2 problems: 1. __attribute__((init_priority(1005))) doesn't map to .ctors.1005 section. 2. You need to check .init_array.NNNN sections on some platforms. > > 2. How do you run your constructor before "foo"? > > Given it a higher priority. The highest priority is 65535. What if foo's constructor already has 65535 priority? My point is GCC supports: -- In the following example, `A' would normally be created before `B', but the `init_priority' attribute has reversed that order: Some_Class A __attribute__ ((init_priority (2000))); Some_Class B __attribute__ ((init_priority (543))); Note that the particular values of PRIORITY do not matter; only their relative ordering. -- That is the constructor order between A and B. We don't support "interleaving constructor priorities" between object files.
On 12/11/2010 3:48 PM, hjl.tools at gmail dot com wrote: > 1. __attribute__((init_priority(1005))) doesn't map to > .ctors.1005 section. It probably maps to .ctors.(65535-1005). There is most definitely a direct relationship. > 2. You need to check .init_array.NNNN sections on some > platforms. Not now -- because on most platforms those sections aren't used. The whole point of this PR is to consider switching to .init_array. If we do that, then, yes, you need to use those sections *and* interleave correctly with .ctors sections. >>> 2. How do you run your constructor before "foo"? >> >> Given it a higher priority. > > The highest priority is 65535. What if foo's > constructor already has 65535 priority? There is a maximum priority; you can't have a higher priority than that. But, so what? Your question is like asking "how do you make a unsigned int bigger than UINT_MAX?" In any case, this is totally irrelevant to the issue of mixing .ctors and .init_array. > That is the constructor order between A and B. We don't support > "interleaving constructor priorities" between object files. Yes, we do. We have for a very long time. This is why the linker sorts the .ctors sections.
(In reply to comment #36) > > That is the constructor order between A and B. We don't support > > "interleaving constructor priorities" between object files. > > Yes, we do. We have for a very long time. This is why the linker sorts > the .ctors sections. Really? Here is a testcase. Do you think goo's constructor will be called before another constructor in another file with priority 1005? [hjl@gnu-6 pr46770-2]$ cat foo.C class Two { private: int i, j, k; public: static int count; Two( int ii, int jj ) { i = ii; j = jj; k = count++; }; Two( void ) { i = 0; j = 0; k = count++; }; int eye( void ) { return i; }; int jay( void ) { return j; }; int kay( void ) { return k; }; }; extern Two foo; extern Two goo; Two foo __attribute__((init_priority(65530))) ( 5, 6 ); Two goo __attribute__((init_priority(65535))) = Two( 7, 8 ); [hjl@gnu-6 pr46770-2]$ gcc -c foo.C -m32 [hjl@gnu-6 pr46770-2]$ readelf -S foo.o | grep ctor [ 8] .ctors.00005 PROGBITS 00000000 0000f8 000004 00 WA 0 0 4 [ 9] .rel.ctors.00005 REL 00000000 000770 000008 08 17 8 4 [10] .ctors PROGBITS 00000000 0000fc 000004 00 WA 0 0 4 [11] .rel.ctors REL 00000000 000778 000008 08 17 10 4 [hjl@gnu-6 pr46770-2]$
On 12/11/2010 4:00 PM, hjl.tools at gmail dot com wrote: > Really? Here is a testcase. Do you think goo's constructor > will be called before another constructor in another file > with priority 1005? Yes. (Or after, I don't remember if smaller numbers indicate higher priority. In either case, there is a deterministic order based on the priority number.) This is the point of the feature. If that were not the case, there would be no need to have .ctors.NNNN sections; everything would just go in .ctors.
(In reply to comment #38) > On 12/11/2010 4:00 PM, hjl.tools at gmail dot com wrote: > > > Really? Here is a testcase. Do you think goo's constructor > > will be called before another constructor in another file > > with priority 1005? > > Yes. Here it is [hjl@gnu-6 pr46770-2]$ cat bar.C class Two { private: int i, j, k; public: static int count; Two( int ii, int jj ) { i = ii; j = jj; k = count++; }; Two( void ) { i = 0; j = 0; k = count++; }; int eye( void ) { return i; }; int jay( void ) { return j; }; int kay( void ) { return k; }; }; extern Two xoo; extern Two bar; Two xoo __attribute__((init_priority(1005))) ( 5, 6 ); Two bar __attribute__((init_priority(1007))) = Two( 7, 8 ); [hjl@gnu-6 pr46770-2]$ gcc -m32 -c bar.C [hjl@gnu-6 pr46770-2]$ readelf -S --wide bar.o | grep ctor [ 8] .ctors.64530 PROGBITS 00000000 0000f8 000004 00 WA 0 0 4 [ 9] .rel.ctors.64530 REL 00000000 000778 000008 08 17 8 4 [10] .ctors.64528 PROGBITS 00000000 0000fc 000004 00 WA 0 0 4 [11] .rel.ctors.64528 REL 00000000 000780 000008 08 17 10 4 [hjl@gnu-6 pr46770-2]$ When bar and foo.o are linked together, can you tell me what the constructor order is? > (Or after, I don't remember if smaller numbers indicate higher priority. > In either case, there is a deterministic order based on the priority > number.) > > This is the point of the feature. If that were not the case, there > would be no need to have .ctors.NNNN sections; everything would just go > in .ctors. We only support constructor priority in single source file: --- Note that the particular values of PRIORITY do not matter; only their relative ordering. --- may be the clue.
On 12/11/2010 4:08 PM, hjl.tools at gmail dot com wrote: > We only support constructor priority in single source file: H.J., this is false. Please try writing three constructors, with priorities 1, 2, and 3. Put the constructors with priorities 1 and 3 in one file and 2 in another file. See what happens the program runs. Thank you,
(In reply to comment #40) > On 12/11/2010 4:08 PM, hjl.tools at gmail dot com wrote: > > > We only support constructor priority in single source file: > > H.J., this is false. > > Please try writing three constructors, with priorities 1, 2, and 3. Put > the constructors with priorities 1 and 3 in one file and 2 in another > file. See what happens the program runs. > That doesn't mean anything. My testcase shows that a constructor with priority 65535 may run after another constructor with priority 1007 in another file. We say explicitly --- Note that the particular values of PRIORITY do not matter; only their relative ordering. --- That means we only guarantee constructor priorities in one TU and my testcase confirms it.
Hi Mark, Did you mean one may interleave constructor priorities? But I don't think it is a documented feature.
On 12/11/2010 4:20 PM, hjl.tools at gmail dot com wrote: > That means we only guarantee constructor priorities in one TU and > my testcase confirms it. HJ, this isn't true. The experiment I suggested in my last email is pretty straightforward. If you're unwilling to do the experiment, it seems that you're not really very interested in figuring out the answer. Perhaps you should go ask some other people and see what they think.
(In reply to comment #43) > On 12/11/2010 4:20 PM, hjl.tools at gmail dot com wrote: > > > That means we only guarantee constructor priorities in one TU and > > my testcase confirms it. > > HJ, this isn't true. > > The experiment I suggested in my last email is pretty straightforward. > If you're unwilling to do the experiment, it seems that you're not > really very interested in figuring out the answer. > Mark, I may have misunderstood you. Correct me if I am wrong. Currently, it may be possible to interleave constructors between different object files by examing .ctors section names and passing object files in specific order to linker. But we can't do it between .init_array and .crors sections.
Since init_priority is global, I will work on binutils to allow mixing .ctors and .init_array.
On 12/11/2010 4:32 PM, hjl.tools at gmail dot com wrote: > Mark, I may have misunderstood you. Correct me if I am wrong. > Currently, it may be possible to interleave constructors > between different object files by examing .ctors section names > and passing object files in specific order to linker. It is possible. The linker sorts the section names, so a higher priority constructor always runs before a lower priority constructor, independent of object file order. You may also be able to play games with object file order to control the order of constructors with the same priority, but we don't document that anywhere, as far as I know. > But we can't do it between .init_array and .crors sections. Correct, we do not at present do that. That's the problem I'm raising with switching to .init_array. If you do that, and someone links in old object code using .ctors, we may run a low-priority .ctors constructor after a high-priority .init_array constructor, or we may run a low-priority .init_array constructor after a low-priority .ctors constructor. Either outcome would be a bug; we would break semantics. My opinion is that we can't switch to .init_array unless we either (a) make the linker detect the problem and fix it, or (b) at least make the linker detect the problem and issue an *error*. I do not think a warning is sufficient.
Jan Hubicka <hubicka@ucw.cz> writes: > 1) is there any kind of any documented requirement on initialization of > static libraries? (i.e. is EABI fully standard conforming?) Not in C++. > 2) I believe that the backwarding order of .ctor section was concious > QOI issue. Yes. Some programs may implicitly rely on the fact that global constructors in archives linked later are run before constructors in the object linked against those archives. That is, given g++ foo.o -lbar where bar is a static archive, not a shared library, then currently the global constructors in objects pulled in from libbar.c will be executed before the global constructors in foo.o. That was an intentional choice because it is more likely to be correct than the reverse. However, the C++ standard does not guarantee it, so any programs which relies on this ordering is technically invalid. But of course it does not follow that we should break such programs for no reason. > I wonder how much legacy code this might break when static > libraries start initializing after main modules. > i686-linux execute a lot more code than EABI. I don't know. Comment #1 refers to relative relocations. I'm sure which relocations this means. In a linked binary I would not expect to see any relocations in the .ctors section. As far as backward disk seeks, I assume this refers to the constructors that the program calls, not the .ctors section itself. The program will walk through the .ctors section forward to find then end and then backward to invoke the constructors, so no backward seek should be introduced there. So I assume the backward seek refers to the tendency of the constructors called earlier to be located later in the binary. I think the appropriate fix for this is better code positioning in the linker, which is completely in control. I'm not at all opposed to using .init_array, but changing the linker would be a better way to address this particular issue, as it would encourage such things as putting all the global constructors together rather than scattered across the program. As Mark says, obviously we can not switch to .init_array for code using constructor priorities unless we modify the linker. But I don't think that is a particularly big deal; we can continue to use .ctors for constructors with priorities and use .init_array for normal constructors, the latter case being vastly more common. Ian
On Sat, 11 Dec 2010, hjl.tools at gmail dot com wrote: > We introduced .init_array into gABI 10 years ago so that we can avoid > those crazy things in crt*.o. It is the time now to switch for Linux/x86/ I see no reason it could make sense for this to be specific to x86. GCC should be consistent between different targets where possible. As a gABI feature, this indicates enabling it for all ELF targets rather than just for x86 GNU/Linux - and maybe disabling for specific target OSes if there prove to be problems for those specific ELF targets.
A linker patch is posted at http://sourceware.org/ml/binutils/2010-12/msg00439.html
Sorry for jumping in so late here, but it sounds like the conclusions here match my recollections: - We added .init_array/.fini_array in order to blend the SVR4 version of .init, which contained actual code, with the HP-UX version, which contained function pointers and used a DT_INIT_SZ entry in the dynamic array rather than prologue and epilogue pieces contributed from crt*.o files. The HP-UX version was seen as an improvement, but it wasn't compatible, so we renamed the sections and the dynamic table entries so that the two versions could live side-by-side and implementations could transition slowly from one to the other. - On HP-UX, we used .init/.init_array for static constructors, and they registered the corresponding static destructors on a special atexit list, rather than adding destructors to .fini_array, so that we could handle destructors on dlclose() events properly (subject to your interpretation of "properly" in that context) [http://www.codesourcery.com/public/cxx-abi/abi.html#dso-dtor]. - Because .init was always executed from beginning to end (as code, there really wasn't much alternative), so was .init_array. - The gABI guaranteed that the init sections from a DT_NEEDED entry would execute before those from the library containing that DT_NEEDED entry (reverse topological order). - Constructor execution order within a translation unit was guaranteed, but there was no specified ordering between translation units within an executable or shared library (although in practice it was link order). Those of us in the discussions were mostly pro-shared library, so we weren't too worried about running initializers backwards with respect to link order. The C++ ABI group specified a way to record the constructor priorities, different from the .ctors.nnnnn method used by gcc [http://www.codesourcery.com/public/cxx-abi/abi.html#ctor-order]. If gcc switches from .ctors to .init_array, it needs to make sure to generate the constructors in forward order within the TU, rather than backwards order as it does in the .ctors section. I didn't see anything in HJ's patch that does that. We will still have an incompatibility with constructor order across TUs within an executable or shared library. The new order may be just as legal as the previous order according to the ABI and the language spec, but it will almost certainly cause previously-working code to fail. If we offer an option to switch from .ctors to .init_array, and encourage such code to use explicit priorities where order really matters, I'd think that would be OK.
(In reply to comment #50) > > If gcc switches from .ctors to .init_array, it needs to make sure to generate > the constructors in forward order within the TU, rather than backwards order as > it does in the .ctors section. I didn't see anything in HJ's patch that does > that. > It is handled in static section * get_elf_initfini_array_priority_section (int priority, bool constructor_p) { section *sec; if (priority != DEFAULT_INIT_PRIORITY) { char buf[18]; sprintf (buf, "%s.%.5u", constructor_p ? ".init_array" : ".fini_array", priority); sec = get_section (buf, SECTION_WRITE, NULL_TREE); } else sec = constructor_p ? init_array_section : fini_array_section; return sec; } It uses priority, instead of MAX_INIT_PRIORITY - priority, to generate NNNN for .init_arry.NNNN.
(In reply to comment #51) > > If gcc switches from .ctors to .init_array, it needs to make sure to generate > > the constructors in forward order within the TU, rather than backwards order as > > it does in the .ctors section. I didn't see anything in HJ's patch that does > > that. > > It uses priority, instead of MAX_INIT_PRIORITY - priority, to generate > NNNN for .init_arry.NNNN. No, I was talking about order of constructors within a TU without using priority. If you have static constructors for A then B in your source file, gcc will output B's constructor before A's in the .ctors section, so that A's will run first. Where does your patch reverse that to account for the fact that .init_array sections are processed in forward order?
(In reply to comment #52) > (In reply to comment #51) > > > If gcc switches from .ctors to .init_array, it needs to make sure to generate > > > the constructors in forward order within the TU, rather than backwards order as > > > it does in the .ctors section. I didn't see anything in HJ's patch that does > > > that. > > > > It uses priority, instead of MAX_INIT_PRIORITY - priority, to generate > > NNNN for .init_arry.NNNN. > > No, I was talking about order of constructors within a TU without using > priority. If you have static constructors for A then B in your source file, gcc > will output B's constructor before A's in the .ctors section, so that A's will > run first. Where does your patch reverse that to account for the fact that > .init_array sections are processed in forward order? Yes, since 1. ld sorts .init_array sections in forward order. 2. ld.so processes .init_array section in forward order.
H.J, Cary is talking about multiple global constructors in a single file, none of which use constructor priorities. In other words, the normal case. gcc generates those in a specific required order for the .ctors section. If it does not reverse the order for .init_array, I don't see how it could possible work correctly. Again: a single file, no priorities specified.
(In reply to comment #54) > H.J, Cary is talking about multiple global constructors in a single file, none > of which use constructor priorities. In other words, the normal case. gcc > generates those in a specific required order for the .ctors section. If it > does not reverse the order for .init_array, I don't see how it could possible > work correctly. > > Again: a single file, no priorities specified. It is handled by the C++ front end. Only one entry in .ctors/.init_array section in a single file. Order within a single file doesn't matter.
> H.J, Cary is talking about multiple global constructors in a single file, none > of which use constructor priorities. In other words, the normal case. gcc > generates those in a specific required order for the .ctors section. If it > does not reverse the order for .init_array, I don't see how it could possible > work correctly. > > Again: a single file, no priorities specified. Right. I looked deeper and now see that gcc generates a single function per CU that runs all the static constructors for that CU, then adds that single entry to the .ctors section. So my concern was groundless -- the order of constructors within the CU is controlled by the code in that one function. -cary
My current patch is on hjl/init-array branch at http://git.kernel.org/?p=devel/gcc/hjl/x86.git;a=summary It uses .init_array only if linker supports mixing .init_array.* and .ctors.* input sections. A linker patch is posted at http://sourceware.org/ml/binutils/2010-12/msg00446.html
Having everyone with knowledge of static construction alerted, can't we use the GNU constructor priorities to solve PR44952? I.e. having highest priority constructor to construct iostream in the module defining cout instead of having static construction in every module?
Sure, if you want to play with that I have no principled objections. I only add here that we probably have another related PR filed by Ian (is already in CC?) and that, as far as I know, those priorities don't work everywhere (I know very little about init priorities in general, sorry)
> Sure, if you want to play with that I have no principled objections. I only add > here that we probably have another related PR filed by Ian (is already in CC?) > and that, as far as I know, those priorities don't work everywhere (I know very > little about init priorities in general, sorry) Definitly the constructor priorities are not supported on non-GNU systems. But we can probably chose iostream implementation based on configure test and fall back into the static constructor code.
Agreed. If you can check that on GNU systems the trick actually works, I can help with the boring autoconf bits (it would be easier if somebody could outline a scheme for such test)
> Having everyone with knowledge of static construction alerted, can't we use the > GNU constructor priorities to solve PR44952? The two constraints are: (a) priorities aren't supported on all systems, so we need to have a fall-back mechanism (b) we need to document which range of priorities we're reserving for libstdc++ On RTOS platforms, high priorities are also used for things like C library initialization and even for device initialization. Thank you,
GCC 4.6.0 is being released, adjusting target milestone.
Re: comment #56 > gcc generates a single function per CU > that runs all the static constructors for that CU Note that if you add __attribute__ (( constructor )) into the mix this is no longer true. See http://sourceware.org/bugzilla/show_bug.cgi?id=12730 for an example.
The mainline versions of both GNU ld and gold now put .ctors sections into .init_array sections, and put .dtors sections into .fini_array sections. .ctors/.dtors sections with priorities are sorted correctly with .init_array/.fini_array sections with priorities. The gcc patch is still useful as it will permit eliminating the support for constructors and destructors in crtbegin.o and crtend.o. If we can do that I believe that crtend.o can be removed, and crtbegin.o will only be needed to call _Jv_RegisterClasses.
(In reply to comment #65) > The mainline versions of both GNU ld and gold now put .ctors sections into > .init_array sections, and put .dtors sections into .fini_array sections. > .ctors/.dtors sections with priorities are sorted correctly with > .init_array/.fini_array sections with priorities. > > The gcc patch is still useful as it will permit eliminating the support for > constructors and destructors in crtbegin.o and crtend.o. If we can do that I > believe that crtend.o can be removed, and crtbegin.o will only be needed to > call > _Jv_RegisterClasses. [hjl@gnu-6 libgcc]$ readelf -s crtend.o Symbol table '.symtab' contains 11 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 2: 0000000000000000 0 SECTION LOCAL DEFAULT 1 3: 0000000000000000 0 SECTION LOCAL DEFAULT 2 4: 0000000000000000 0 SECTION LOCAL DEFAULT 3 5: 0000000000000000 0 SECTION LOCAL DEFAULT 4 6: 0000000000000000 0 OBJECT LOCAL DEFAULT 4 __FRAME_END__ 7: 0000000000000000 0 SECTION LOCAL DEFAULT 5 8: 0000000000000000 0 OBJECT LOCAL DEFAULT 5 __JCR_END__ 9: 0000000000000000 0 SECTION LOCAL DEFAULT 7 10: 0000000000000000 0 SECTION LOCAL DEFAULT 6 We need __FRAME_END__ for exception handling and __JCR_END__ for _Jv_RegisterClasses.
We don't need __FRAME_END__ if we use --eh-frame-hdr. We don't need __JCR_END__ if we rename the .jcr section to jcr and use __stop_jcr. These will only work with GNU ld or gold, but that is the only case the .ctors/.dtors code will work anyhow.
You need crtend*.o to zero terminate .eh_frame section.
Author: hjl Date: Sat Aug 20 20:02:17 2011 New Revision: 177933 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=177933 Log: Use .init_arrary/.fini_array sections if possible. 2011-08-20 H.J. Lu <hongjiu.lu@intel.com> PR other/46770 * config.gcc (tm_file): Add initfini-array.h if .init_arrary/.fini_array are supported. * crtstuff.c: Don't generate .ctors nor .dtors sections if USE_INITFINI_ARRAY is defined. * output.h (default_elf_init_array_asm_out_constructor): New. (default_elf_fini_array_asm_out_destructor): Likewise. * varasm.c (elf_init_array_section): Likewise. (elf_fini_array_section): Likewise. (get_elf_initfini_array_priority_section): Likewise. (default_elf_init_array_asm_out_constructor): Likewise. (default_elf_fini_array_asm_out_destructor): Likewise. * config/initfini-array.h: New. Added: trunk/gcc/config/initfini-array.h Modified: trunk/gcc/ChangeLog trunk/gcc/config.gcc trunk/gcc/crtstuff.c trunk/gcc/output.h trunk/gcc/varasm.c
Fixed for GCC 4.7.0.
Author: jingyu Date: Sat Feb 18 04:55:31 2012 New Revision: 184368 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=184368 Log: 2012-02-17 Jing Yu <jingyu@google.com> Google Ref 47894 2011-12-07 H.J. Lu <hongjiu.lu@intel.com> Backport from mainline r177933. 2011-08-20 H.J. Lu <hongjiu.lu@intel.com> PR other/46770 * config.gcc (tm_file): Add initfini-array.h if .init_arrary/.fini_array are supported. * crtstuff.c: Don't generate .ctors nor .dtors sections if USE_INITFINI_ARRAY is defined. * output.h (default_elf_init_array_asm_out_constructor): New. (default_elf_fini_array_asm_out_destructor): Likewise. * varasm.c (elf_init_array_section): Likewise. (elf_fini_array_section): Likewise. (get_elf_initfini_array_priority_section): Likewise. (default_elf_init_array_asm_out_constructor): Likewise. (default_elf_fini_array_asm_out_destructor): Likewise. * config/initfini-array.h: New. Added: branches/google/gcc-4_6_2-mobile/gcc/initfini-array.h Modified: branches/google/gcc-4_6_2-mobile/gcc/ChangeLog.google-4_6 branches/google/gcc-4_6_2-mobile/gcc/config.gcc branches/google/gcc-4_6_2-mobile/gcc/crtstuff.c branches/google/gcc-4_6_2-mobile/gcc/output.h branches/google/gcc-4_6_2-mobile/gcc/varasm.c
Author: jingyu Date: Sat Feb 18 06:03:26 2012 New Revision: 184369 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=184369 Log: 2012-02-17 Jing Yu <jingyu@google.com> Google Ref 47894 2011-12-07 H.J. Lu <hongjiu.lu@intel.com> Backport from mainline r177933. 2011-08-20 H.J. Lu <hongjiu.lu@intel.com> PR other/46770 * config.gcc (tm_file): Add initfini-array.h if .init_arrary/.fini_array are supported. * crtstuff.c: Don't generate .ctors nor .dtors sections if USE_INITFINI_ARRAY is defined. * output.h (default_elf_init_array_asm_out_constructor): New. (default_elf_fini_array_asm_out_destructor): Likewise. * varasm.c (elf_init_array_section): Likewise. (elf_fini_array_section): Likewise. (get_elf_initfini_array_priority_section): Likewise. (default_elf_init_array_asm_out_constructor): Likewise. (default_elf_fini_array_asm_out_destructor): Likewise. * config/initfini-array.h: New. Added: branches/google/gcc-4_6/gcc/initfini-array.h Modified: branches/google/gcc-4_6/gcc/ChangeLog.google-4_6 branches/google/gcc-4_6/gcc/config.gcc branches/google/gcc-4_6/gcc/crtstuff.c branches/google/gcc-4_6/gcc/output.h branches/google/gcc-4_6/gcc/varasm.c
Author: jingyu Date: Wed Feb 22 22:04:39 2012 New Revision: 184493 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=184493 Log: 2012-02-21 Jing Yu <jingyu@google.com> Google Ref 47894 Backport from mainline r177933, r175181, r177963, r178116, r183299. 2011-08-20 H.J. Lu <hongjiu.lu@intel.com> PR other/46770 * config.gcc (tm_file): Add initfini-array.h if .init_arrary/.fini_array are supported. * crtstuff.c: Don't generate .ctors nor .dtors sections if USE_INITFINI_ARRAY is defined. * output.h (default_elf_init_array_asm_out_constructor): New. (default_elf_fini_array_asm_out_destructor): Likewise. * varasm.c (elf_init_array_section): Likewise. (elf_fini_array_section): Likewise. (get_elf_initfini_array_priority_section): Likewise. (default_elf_init_array_asm_out_constructor): Likewise. (default_elf_fini_array_asm_out_destructor): Likewise. * config/initfini-array.h: New. 2011-06-18 H.J. Lu <hongjiu.lu@intel.com> PR other/49325 * acinclude.m4 (gcc_AC_INITFINI_ARRAY): Properly check if .init_array can be used with .ctors on targets. * configure: Regenerated. 2011-08-22 H.J. Lu <hongjiu.lu@intel.com> * acinclude.m4 (gcc_AC_INITFINI_ARRAY): Error if __ELF__ isn't defined. * configure: Regenerated. 2011-08-26 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> PR target/50166 * acinclude.m4 (gcc_AC_INITFINI_ARRAY): Check count in main. * configure: Regenerate. 2012-01-19 Jakub Jelinek <jakub@redhat.com> PR bootstrap/50237 * config/initfini-array.h: Guard content of the header with #ifdef HAVE_INITFINI_ARRAY. * configure.ac: Move gcc_AC_INITFINI_ARRAY much later into the file. Add initfini-array.h to tm_file here. * acinclude.m4 (gcc_AC_INITFINI_ARRAY): For non-ia64 do a linker test. * config.gcc: Don't add initfini-array.h to tm_file here. * configure: Regenerated. Added: branches/google/gcc-4_6/gcc/config/initfini-array.h Modified: branches/google/gcc-4_6/gcc/ChangeLog.google-4_6 branches/google/gcc-4_6/gcc/acinclude.m4 branches/google/gcc-4_6/gcc/configure branches/google/gcc-4_6/gcc/configure.ac branches/google/gcc-4_6/gcc/crtstuff.c branches/google/gcc-4_6/gcc/output.h branches/google/gcc-4_6/gcc/varasm.c
We still have an unresolved issue here: we're effectively reversing the order in which the ctors are run across translation units. While explicitly undefined by any standard, it was mentioned upthread that this would probably break a lot of code that depended on ctors for later translation units (e.g., a statically-linked C++ library) running before those for earlier translation units. And, in fact, we have been finding lots of such code. We've temporarily worked around it by configuring GCC to continue to use .ctors sections, and by turning off --ctors-in-init-array in the linker, but I'd think it would be nice to fix this. I'd like to propose a --reverse-init-array option to the linker that would reverse the contributions to the .init_array section relative to one another (but not the actual contents of each contribution). With this option, the .init_array entries for translation unit A would come after those for translation unit B, when A comes before B on the link command. This would still conform to the standards, but would provide a more reasonable ordering, since it is natural to expect initializers for dependent libraries to execute before those for code that depends on them (as is the case for shared libraries already). As I recall the discussions from years ago when we first added .init_array, I think we would have always preferred to have the dynamic loader execute the .init_array entries in reverse, but we were trying to preserve the behavior that had always been observed with the old .init section (which, obviously, could not execute in reverse). I believe that was the original reason (or at least part of it) that GCC put ctors in a separate section rather than using .init or .init_array. Now that we're moving .ctors into .init_array, I think it's more important to preserve the old behavior of ctors rather than the old behavior of .init fragments. HJ, if I add this option to gold, would you add it to ld? If this is OK with everyone, we can then discuss whether or not the option should be on by default. -cary
(In reply to comment #74) > We still have an unresolved issue here: we're effectively reversing the order > in which the ctors are run across translation units. While explicitly undefined > by any standard, it was mentioned upthread that this would probably break a lot > of code that depended on ctors for later translation units (e.g., a > statically-linked C++ library) running before those for earlier translation > units. And, in fact, we have been finding lots of such code. We've temporarily > worked around it by configuring GCC to continue to use .ctors sections, and by > turning off --ctors-in-init-array in the linker, but I'd think it would be nice > to fix this. Can you provide a testcase? ARM EABI has been using .init_array from day one. How does it work for ARM EABI? > I'd like to propose a --reverse-init-array option to the linker that would > reverse the contributions to the .init_array section relative to one another > (but not the actual contents of each contribution). With this option, the > .init_array entries for translation unit A would come after those for > translation unit B, when A comes before B on the link command. This would still > conform to the standards, but would provide a more reasonable ordering, since > it is natural to expect initializers for dependent libraries to execute before > those for code that depends on them (as is the case for shared libraries > already). > > As I recall the discussions from years ago when we first added .init_array, I > think we would have always preferred to have the dynamic loader execute the > .init_array entries in reverse, but we were trying to preserve the behavior > that had always been observed with the old .init section (which, obviously, > could not execute in reverse). I believe that was the original reason (or at > least part of it) that GCC put ctors in a separate section rather than using > .init or .init_array. Now that we're moving .ctors into .init_array, I think > it's more important to preserve the old behavior of ctors rather than the old > behavior of .init fragments. > > HJ, if I add this option to gold, would you add it to ld? > > If this is OK with everyone, we can then discuss whether or not the option > should be on by default. > I think we should preserve the old behavior as much as we can, by default. --reverse-init-array should be the default. Thanks.
(In reply to comment #75) > Can you provide a testcase? // foo.h struct Foo { Foo(Foo *other) : x(other->x) { } Foo() : x(42) { } int x; private: Foo(const Foo&); }; extern Foo foo_global; // foo.cc #include "foo.h" Foo foo_global; // main.cc #include <assert.h> #include "foo.h" Foo foo(&foo_global); int main() { assert(foo.x == 42); } Above, foo.cc simulates a library, and main depends on that library having been initialized. Using pre-init_array GCC, this works: g++ main.cc foo.cc && a.out and this doesn't: g++ foo.cc main.cc && ./a.out a.out: main.cc:6: int main(): Assertion `foo.x == 42' failed. Using post-init_array GCC, the behavior is reversed: natural link order (libraries after main) is broken. > ARM EABI has been using .init_array from day > one. How does it work for ARM EABI? It doesn't. We have a *lot* of programs that don't run on ARM though, and they are all broken by this change. Note: we do understand that the example above depends on undefined behavior, and we do intend to eventually fix our source. But it will take a lot of effort.
I believe .init_array keeps the same order of .ctors within the same translation unit. The proposed --reverse-init-array switch will only reverse the order across translation units, while keeping the same order within translation unit. Is this correct?
(In reply to comment #77) > I believe .init_array keeps the same order of .ctors within > the same translation unit. I may be missing something, but I only see a single .ctors entry per CU, so I think your question is moot.
(In reply to comment #77) > I believe .init_array keeps the same order of .ctors within > the same translation unit. The proposed --reverse-init-array > switch will only reverse the order across translation units, > while keeping the same order within translation unit. Is this > correct? Yes. If you have translation unit A with .ctors entries A1 and A2, and translation unit B with .ctors entries B1 and B2, we'll build a .init_array section with: B1 B2 A1 A2 As Paul noted, this is a moot point in practice for .ctors, since GCC emits only a single .ctors entry per TU, but it could be significant for assembly code or for TUs with .init_array sections. -cary
(In reply to comment #79) > > As Paul noted, this is a moot point in practice for .ctors, since GCC emits > only a single .ctors entry per TU, but it could be significant for assembly > code or for TUs with .init_array sections. > That is my concern. .init_array section in the same TU can may have more than one entry due to: 1. Assembly code. 2. constructor attribute in C source. 3. .init_array section attribute in C source. We need to spell out exactly what --reverse-init-array should do.
>> As Paul noted, this is a moot point in practice for .ctors, since GCC emits >> only a single .ctors entry per TU, but it could be significant for assembly >> code or for TUs with .init_array sections. > > That is my concern. .init_array section in the same TU can may have > more than one entry due to: > > 1. Assembly code. > 2. constructor attribute in C source. > 3. .init_array section attribute in C source. > > We need to spell out exactly what --reverse-init-array should do. Didn't I just do that? -cary
(In reply to comment #81) > Didn't I just do that? > Let me ask it again: The proposed --reverse-init-array switch will only reverse the order across translation units, while keeping the same order within translation unit. Is this correct?
>> Didn't I just do that? > > Let me ask it again: > > The proposed --reverse-init-array switch will only reverse the order across > translation units, while keeping the same order within translation unit. > Is this correct? Maybe I'm misunderstanding the question. As I said before: If you have translation unit A with .ctors entries A1 and A2, and translation unit B with .ctors entries B1 and B2, we'll build a .init_array section with: B1 B2 A1 A2 Expanding on that, we will reverse the order of the individual input sections relative to one another, but we will not modify the contents of any input section at all. Everything I said for .ctors sections goes for .init_array sections, since we just map .ctors -> .init_array on the way in, and treat them as if they were .init_array sections from the beginning. Paul suggested to me offline that maybe you're asking about translation units with several .ctors or .init_array sections. Since that doesn't happen in practice, I don't really care so much, and would prefer to do the easy thing of just reversing the order of all input sections, even to the point of reversing the order of the sections within a translation unit. I think the important point is that we do not reverse the order of entries within a single input section. -cary
(In reply to comment #83) > > Paul suggested to me offline that maybe you're asking about > translation units with several .ctors or .init_array sections. Since > that doesn't happen in practice, I don't really care so much, and > would prefer to do the easy thing of just reversing the order of all > input sections, even to the point of reversing the order of the > sections within a translation unit. I think the important point is > that we do not reverse the order of entries within a single input > section. > I have seen codes like: void (*const init_array []) (void) __attribute__ ((section (".init_array"), aligned (sizeof (void *)))) = { &init_0, &init_1, &init_2 }; I don't want to reverse its order.
Just as a quick reminder, the reversed ctor execution order is big performance problem for C++ Apps inlcuding Mozilla and Chrome ;) So whatever we do, I would preffer to not have it by default.
> I have seen codes like: > > void (*const init_array []) (void) > __attribute__ ((section (".init_array"), aligned (sizeof (void *)))) = > { > &init_0, > &init_1, > &init_2 > }; > > I don't want to reverse its order. We will not reverse that order. Those three entries will all be in the same input section. -cary
> Just as a quick reminder, the reversed ctor execution order is big performance > problem for C++ Apps inlcuding Mozilla and Chrome ;) > So whatever we do, I would preffer to not have it by default. If the issue is the iteration over the contents of the final .init_array section, this solution won't have that problem -- the loader will still execute .init_array entries in forward order (we'll be reversing them at link time). If the issue is the code layout of the ctors themselves, that sounds like something that could be fixed through code layout optimizations (e.g., gold's --section-ordering-file option). -cary
(In reply to comment #86) > > I have seen codes like: > > > > void (*const init_array []) (void) > > __attribute__ ((section (".init_array"), aligned (sizeof (void *)))) = > > { > > &init_0, > > &init_1, > > &init_2 > > }; > > > > I don't want to reverse its order. > > We will not reverse that order. Those three entries will all be in the > same input section. I assume init priority will be handled as usual.
(In reply to comment #87) > > Just as a quick reminder, the reversed ctor execution order is big performance > > problem for C++ Apps inlcuding Mozilla and Chrome ;) > > So whatever we do, I would preffer to not have it by default. > > If the issue is the iteration over the contents of the final > .init_array section, this solution won't have that problem -- the > loader will still execute .init_array entries in forward order (we'll > be reversing them at link time). Your solution will reverse order of reference of .init_array entries with regards to the linker commandline. Linking translation units A B C, will result in C B A execution order. Unless you also change the linker to combine the translation units backwards(vs sequentially as is normal), this will ruin startup speed of chrome/firefox and every other large c++ program. > > If the issue is the code layout of the ctors themselves, that sounds > like something that could be fixed through code layout optimizations > (e.g., gold's --section-ordering-file option). Every single app would have to add this flag for good perf so some legacy build system can avoid reordering the .init_array section using a non-default flag.
(In reply to comment #89) > Your solution will reverse order of reference of .init_array entries with > regards to the linker commandline. > > Linking translation units A B C, will result in C B A execution order. Pardon my confusion ... AFAIU, before init_array was implemented, the .ctors *were* executed in C B A order (by the loader). Are you saying that you've re-ordered the link command line after init_array became available? Or that you kept the link command fixed, but switching to init_array gave you significant speed up, which you don't want to lose?
(In reply to comment #90) > > Or that you kept the link command fixed, but switching to init_array gave > you significant speed up, which you don't want to lose? This.
As I said in comment #47 and elsewhere, you should not confuse the order in which entries appear in .ctors or .init_array sections with the order in which they appear in the binary. If you want better layout in the binary, then tell the linker to change the layout in the binary. The order in the .ctors or .init_array sections is irrelevant. The fact that reversing the order of constructors happens to give you faster startup for firefox is just a coincidence. Don't let that coincidence drive you toward choices that make no sense.
(In reply to comment #92) > As I said in comment #47 and elsewhere, you should not confuse the order in > which entries appear in .ctors or .init_array sections with the order in which > they appear in the binary. If you want better layout in the binary, then tell > the linker to change the layout in the binary. The order in the .ctors or > .init_array sections is irrelevant. The fact that reversing the order of > constructors happens to give you faster startup for firefox is just a > coincidence. Don't let that coincidence drive you toward choices that make no > sense. I am not confusing the order in which entries appear. My concerns is the order in which code gets paged in from disk. Right now that's driven entirely by translation unit "concatenation" and how that relates to the order of ctor invocation. Currently the right thing(tm) happens, achieving the same by other means is considerably more complicated. There are 2 problems with using section ordering to solve this a) there is no way to do this kind of section ordering transparently(especially not by default) with current infrastructure. b) it doesn't work without lto because initializers pull in other code... I'll expand on b: We(C++ code like Firefox/Chrome/etc) have one initializer per TU. The initializer is often not self-contained and calls other code within the unit(and rarely in other units...this you can't solve without LTO) So if you pass a list of init sections to the linker...that list needs to be transitive and include all of the sections called from inits in order to achieve a useful level of locality post-reorder. Or you can keep TUs without any reordering, have decent locality(because related init code is generally nearby) and a sane page-in pattern if the order of init executions matches TU layout.
It is misleading to think that the linker accumulates code in translation unit order for a C++ program. E.g., that is not what happens for template code or string constants. And of course the placement of functions called in different translation units is arbitrary. A lot of work was done in both GNU ld and gold to move constructors from .ctors to .init_array, all to improve startup latency for firefox. If that same amount of work were done on better layout of initialization code, we would improve all programs. Gold already supports arbitrarily sophisticated section layout via plugins, and I do not think it would be hard to add that support to GNU ld as well. I really think that this whole approach has been chasing the wrong thing, fixing a side effect rather than attempting to address the real problem. In any case, on the issue at hand, changing the default order is the conservative approach. Firefox can use an option.
> It is misleading to think that the linker accumulates code in translation unit > order for a C++ program. E.g., that is not what happens for template code or > string constants. And of course the placement of functions called in different > translation units is arbitrary. > > A lot of work was done in both GNU ld and gold to move constructors from .ctors > to .init_array, all to improve startup latency for firefox. If that same > amount of work were done on better layout of initialization code, we would > improve all programs. I did some work on this, too. GCC now identify the functions executed only at startup and global destruction time and puts them into .text.startup subsections. This completely elliminate the problem for implicit constructors generated by #include <iostream>. Those just calls libstdc++ constructor that checks flags and does nothing most of time. Sadly I think gold still ignore those, so the optimization works only with GNU LD. With more complex constructors this logic helps. It is however not resonable to assume that ctors execute and access only stuff that can be recognized by reachability analysis to be only used at startup (after all they are constructing something). It is resonable to assume that static constructor in translation unit X will access functions and variables of unit X (because it is constructing them) + of course some other common stuff needed to do its job that is shared across rest of construction process. For this it makes IMO a lot of sense to make the (implicit to user) order of execution of constructors match the (impicit) order how sections are laid out. Sure that there are counterexamples where this does not help, but it is good heuristics and what we do by default now is almost always the slowest variant. Firefox is really not a special case here. C++ makes it extremely easy to introduce static constructors and destructors and thus most large C++ programs expose this problems (at least I know that Chrome and OOo do). I am not quite sure how linker ordering plugins and code layout is going to help here better. Some linkers do automatic reordering based on reconstructed callgraph. I prototyped code layout pass (ipa-reorder) based on static analysis of the callgraph at LTO. It works by clustering the callgraph/varpool nodes into sequences based on the presence of references hoping to get related code together. In my tests it however reaches very mixed results on Mozilla, because static analysis quickly lose track of virtual calls and use of pointers. It still seems to me that switching the default ctor execution order, at risk of breaking non-conforming C++ programs, is a good idea here. We get measurable improvements for most of large C++ packages out there and hopefully the fallout is not going to be great - many other runtimes already execute ctors in forwarding order. We could get the static function/variable reordering pass into GCC, implement in linker reordering and do reordering based on profile feedback, but all those are rather ortogonal to the issue discussed here. Honza
I'm a user that the switch to init_array just broke. Details are in http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53068, but to summarize: Large production environment Must use other compilers too Third party binaries as well as our code. Each project represented as a .a library. Static initialization dependencies between TUs in a project (and hence within .o's in a library). Static initialization dependencies among projects. Executables link some explicit .o's with libraries from other projects, and must provide semantically correct ordering. Hence: Can't use priorities (not supported on other compilers; can't add pragmas to 3rd party code; maintaining a global absolute order over hundreds of files that change dependencies each release is a headache) Can't use init_array (no way to control ordering among files extracted from a single library) So for a decade we have manually maintained a dependency graph (relative, not absolute like priorities) and used that to put explicit commands to position .ctor sections into a linker script. That broke in 4.7. Yes, the language leaves inter-TU order unspecified. But we the users have to control that particular unspecified to get our job done. There used to be a way to exercise that control, through hooks in the linker script. You have now gratuitously taken away that control *and left nothing else to use instead*. At this point our choices appear to be to stay at 4.6 forever (or at least until the roar of complaint makes you do something), or to do our own collect2. Pretty poor.
One option you have is to configure gcc with --disable-initfini-array.
It's OK if you reverse the default order - make it sideways if it gets a faster Firefox. We can cope. It's OK is you dump ctors for init_array if it simplifies your maintenance. We don't want you to be stuck with maintaining both systems. But give us some (documented!) way to control how the init_array gets populated, for when there's something you didn't think of in your planning. Like "using command line order breaks when there are intra-library order dependencies". Please. OK to re-open this ticket?
> OK to re-open this ticket? If ctor order was/is controllable via linker script, it seems that you need similar feature for init arrays. In that case it is binutils feature, not GCC, and for that please fill in http://sourceware.org/bugzilla/ I am sorry for the trouble. As Iant pointed out, disabling initarray support may be viable solution for you in meantime. Honza
As as side, Sunday-type, observation, we don't normally use the work 'ticket' here (if only because no money is involved, at least, not in the open ;)
Well, it's easy to say that it's the other guy's problem, but it isn't. You are assuming that the linker is always gnu ld; for big shops with multi-platform targets that's not necessarily true. We can't expect vendors of other linkers to deal with gcc decisions. Instead, may I suggest that the problem is in collect2, which is where gcc generates an init_array; the linker just includes the table in the load module, unchanged from what collect2 gives it. I there's another bug list separately for collect2 then please give me the URL and I'll go away and bother them instead. You used to produce a section for each init; the linker knows about sections, so we can use the linker to enforce order. You are no longer producing a section for each init, but are instead jamming them together into an anonymous opaque object that a linker cannot change (hacks in your own linker notwithstanding). So long as you are going to do the jamming yourself, we mere users need some scripting mechanism to control it. Yes, there are options to preserve the "legacy" behavior. Until you get tired of supporting two mechanisms, or bitrot creeps into the "legacy". I have enough trouble preserving C++ as a language of choice here in this shop, without gratuitous breakage of things that in truth are not part of the standard but nevertheless are needed for a working tool.
To be clear, nothing has changed in collect2. The only thing that has changed is that data that was being emitted in the .ctors section is now being emitted in the .init_array section (and similarly for .dtors and .fini_array). The reason this makes a difference is that the dynamic linker executes the entries in .init_array, whereas gcc-provided startup code executes the entries in .ctors. And they happen to execute the entries in different orders. The whole point of the change is in fact to execute the entries in a different order, though I continue to think that this would be better handled in a different way. In other words, it is not the case that gcc is producing an anoymous opaque object that the linker can not change.
I may be just displaying my ignorance, but my understanding is that order under init_array is governed by order of pointers within the array itself, and where the pointed-to sections are in the file is irrelevant. After all, a reason for the switch was so Firefox could get the inits with fewer disk reads. So even if I can rearrange the init_array.NNNN sections nothing will change, because the order is set by the pointers and you have left me with no control over that. Not so?
I'm not sure what you mean. Each object file will have a .init_array section. The linker will assemble those sections in the usual manner. The order of global constructors in a single translation unit is fixed by the language standard. The thing that is not fixed is the order between translation units. So each object file will have a .init_array section that will typically contain only a single pointer. The order in which those input .init_array sections are combined into an output .init_array section will determine the order in which the constructors are run.
Any news on that? With gcc 4.8.4 (ARM target), init_priority attribute doesn't work with a static library and main C++ file. I have a class declared in library with "__attribute__ ((init_priority (101)))". In main project, another class declared with no attributes. The main class constructor is called BEFORE library constructor (with high priority attribute).
Update: init_priority not work across TUs. It works to change constructor order in same CPP file. Between .cpp files or between cpp and library, it not work.
This problem report is closed. If you want to report a new bug, please open a new problem report. Using init_priority does work in general across translation units. There may be a bug in your environment. In your new problem report, be sure to give an example of source code, and mention the exact version of the compiler and linker you are using.