Bug 46770 - Replace .ctors/.dtors with .init_array/.fini_array on targets supporting them
Summary: Replace .ctors/.dtors with .init_array/.fini_array on targets supporting them
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: other (show other bugs)
Version: 4.6.0
: P3 normal
Target Milestone: 4.7.0
Assignee: H.J. Lu
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-12-02 19:20 UTC by Mike Hommey
Modified: 2023-04-11 17:02 UTC (History)
17 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2010-12-07 15:44:50


Attachments
A patch (1.96 KB, patch)
2010-12-07 15:44 UTC, H.J. Lu
Details | Diff
A demo of mixing .init_array and .ctors (4.33 KB, application/octet-stream)
2010-12-11 19:44 UTC, H.J. Lu
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Mike Hommey 2010-12-02 19:20:51 UTC
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.
Comment 1 Mike Hommey 2010-12-02 19:24:44 UTC
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)
Comment 2 Jan Hubicka 2010-12-02 22:22:17 UTC
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
Comment 3 H.J. Lu 2010-12-02 23:01:14 UTC
(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.
Comment 4 H.J. Lu 2010-12-07 15:44:50 UTC
Created attachment 22671 [details]
A patch

I am testing this patch.
Comment 5 H.J. Lu 2010-12-07 16:45:11 UTC
(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]$
Comment 6 H.J. Lu 2010-12-09 17:55:41 UTC
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]$
Comment 7 Jan Hubicka 2010-12-11 14:15:04 UTC
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
Comment 8 H.J. Lu 2010-12-11 14:28:35 UTC
(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.
Comment 9 Mike Hommey 2010-12-11 14:36:36 UTC
(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.
Comment 10 Jan Hubicka 2010-12-11 15:01:34 UTC
> 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
Comment 11 H.J. Lu 2010-12-11 15:34:41 UTC
(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.
Comment 12 Jan Hubicka 2010-12-11 16:17:38 UTC
> >   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.
Comment 13 H.J. Lu 2010-12-11 16:53:41 UTC
(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/
Comment 14 Mark Mitchell 2010-12-11 18:32:58 UTC
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.
Comment 15 H.J. Lu 2010-12-11 18:46:48 UTC
(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.
Comment 16 Mark Mitchell 2010-12-11 18:50:11 UTC
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.
Comment 17 H.J. Lu 2010-12-11 19:02:40 UTC
(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.
Comment 18 Mark Mitchell 2010-12-11 19:33:17 UTC
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.
Comment 19 H.J. Lu 2010-12-11 19:44:30 UTC
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.
Comment 20 H.J. Lu 2010-12-11 19:46:46 UTC
(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.
Comment 21 Mark Mitchell 2010-12-11 19:47:38 UTC
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
Comment 22 H.J. Lu 2010-12-11 19:51:00 UTC
(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.
Comment 23 H.J. Lu 2010-12-11 19:53:05 UTC
(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."
Comment 24 Mark Mitchell 2010-12-11 19:56:43 UTC
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.*.)
Comment 25 H.J. Lu 2010-12-11 20:04:23 UTC
(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.
Comment 26 H.J. Lu 2010-12-11 20:16:56 UTC
(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.
Comment 27 Mark Mitchell 2010-12-11 20:19:23 UTC
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.
Comment 28 Jan Hubicka 2010-12-11 21:01:08 UTC
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
Comment 29 Mark Mitchell 2010-12-11 21:06:41 UTC
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.
Comment 30 H.J. Lu 2010-12-11 21:06:49 UTC
(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"?
Comment 31 H.J. Lu 2010-12-11 22:56:35 UTC
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.
Comment 32 Mark Mitchell 2010-12-11 23:19:05 UTC
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.
Comment 33 H.J. Lu 2010-12-11 23:28:01 UTC
(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"?
Comment 34 Mark Mitchell 2010-12-11 23:30:19 UTC
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.
Comment 35 H.J. Lu 2010-12-11 23:48:29 UTC
(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.
Comment 36 Mark Mitchell 2010-12-11 23:54:44 UTC
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.
Comment 37 H.J. Lu 2010-12-12 00:00:53 UTC
(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]$
Comment 38 Mark Mitchell 2010-12-12 00:03:22 UTC
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.
Comment 39 H.J. Lu 2010-12-12 00:08:29 UTC
(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.
Comment 40 Mark Mitchell 2010-12-12 00:11:56 UTC
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,
Comment 41 H.J. Lu 2010-12-12 00:19:54 UTC
(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.
Comment 42 H.J. Lu 2010-12-12 00:24:26 UTC
Hi Mark,

Did you mean one may interleave constructor priorities? But I don't
think it is a documented feature.
Comment 43 Mark Mitchell 2010-12-12 00:24:30 UTC
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.
Comment 44 H.J. Lu 2010-12-12 00:32:06 UTC
(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.
Comment 45 H.J. Lu 2010-12-12 15:54:16 UTC
Since init_priority is global, I will work on binutils
to allow mixing .ctors and .init_array.
Comment 46 Mark Mitchell 2010-12-12 18:40:35 UTC
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.
Comment 47 Ian Lance Taylor 2010-12-13 02:29:46 UTC
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
Comment 48 jsm-csl@polyomino.org.uk 2010-12-13 18:08:00 UTC
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.
Comment 49 H.J. Lu 2010-12-13 19:41:15 UTC
A linker patch is posted at

http://sourceware.org/ml/binutils/2010-12/msg00439.html
Comment 50 Cary Coutant 2010-12-13 20:24:43 UTC
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.
Comment 51 H.J. Lu 2010-12-13 20:30:58 UTC
(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.
Comment 52 Cary Coutant 2010-12-13 20:41:46 UTC
(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?
Comment 53 H.J. Lu 2010-12-13 20:47:44 UTC
(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.
Comment 54 Ian Lance Taylor 2010-12-14 00:38:41 UTC
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.
Comment 55 H.J. Lu 2010-12-14 01:14:22 UTC
(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.
Comment 56 Cary Coutant 2010-12-14 01:24:30 UTC
> 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
Comment 57 H.J. Lu 2010-12-14 01:31:56 UTC
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
Comment 58 Jan Hubicka 2010-12-14 12:52:06 UTC
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?
Comment 59 Paolo Carlini 2010-12-14 13:17:13 UTC
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)
Comment 60 Jan Hubicka 2010-12-14 13:25:32 UTC
> 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.
Comment 61 Paolo Carlini 2010-12-14 13:33:32 UTC
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)
Comment 62 Mark Mitchell 2010-12-14 15:17:25 UTC
> 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,
Comment 63 Jakub Jelinek 2011-03-25 19:52:17 UTC
GCC 4.6.0 is being released, adjusting target milestone.
Comment 64 Alan Modra 2011-05-09 09:52:44 UTC
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.
Comment 65 Ian Lance Taylor 2011-06-23 16:22:05 UTC
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.
Comment 66 H.J. Lu 2011-06-23 23:17:04 UTC
(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.
Comment 67 Ian Lance Taylor 2011-06-24 13:21:28 UTC
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.
Comment 68 Jakub Jelinek 2011-06-24 13:33:32 UTC
You need crtend*.o to zero terminate .eh_frame section.
Comment 69 hjl@gcc.gnu.org 2011-08-20 20:02:21 UTC
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
Comment 70 H.J. Lu 2011-08-20 20:06:16 UTC
Fixed for GCC 4.7.0.
Comment 71 Jing Yu 2012-02-18 04:55:37 UTC
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
Comment 72 Jing Yu 2012-02-18 06:03:30 UTC
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
Comment 73 Jing Yu 2012-02-22 22:04:44 UTC
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
Comment 74 Cary Coutant 2012-04-17 01:21:47 UTC
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
Comment 75 H.J. Lu 2012-04-17 14:47:27 UTC
(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.
Comment 76 Paul Pluzhnikov 2012-04-17 15:18:56 UTC
(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.
Comment 77 H.J. Lu 2012-04-17 15:41:04 UTC
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?
Comment 78 Paul Pluzhnikov 2012-04-17 17:16:10 UTC
(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.
Comment 79 Cary Coutant 2012-04-17 18:00:41 UTC
(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
Comment 80 H.J. Lu 2012-04-17 18:12:41 UTC
(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.
Comment 81 ccoutant 2012-04-17 18:52:11 UTC
>> 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
Comment 82 H.J. Lu 2012-04-17 19:02:22 UTC
(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?
Comment 83 ccoutant 2012-04-17 20:10:07 UTC
>> 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
Comment 84 H.J. Lu 2012-04-17 20:28:25 UTC
(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.
Comment 85 Jan Hubicka 2012-04-17 21:06:55 UTC
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.
Comment 86 ccoutant 2012-04-17 21:09:15 UTC
> 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
Comment 87 ccoutant 2012-04-17 21:52:12 UTC
> 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
Comment 88 H.J. Lu 2012-04-17 22:15:04 UTC
(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.
Comment 89 Taras Glek 2012-04-17 23:58:00 UTC
(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.
Comment 90 Paul Pluzhnikov 2012-04-18 00:50:06 UTC
(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?
Comment 91 Taras Glek 2012-04-18 01:27:58 UTC
(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.
Comment 92 Ian Lance Taylor 2012-04-18 03:50:51 UTC
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.
Comment 93 Taras Glek 2012-04-18 04:48:18 UTC
(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.
Comment 94 Ian Lance Taylor 2012-04-19 00:14:01 UTC
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.
Comment 95 Jan Hubicka 2012-04-19 15:07:27 UTC
> 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
Comment 96 Ivan Godard 2012-04-22 08:01:55 UTC
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.
Comment 97 Ian Lance Taylor 2012-04-22 17:03:24 UTC
One option you have is to configure gcc with --disable-initfini-array.
Comment 98 Ivan Godard 2012-04-22 17:44:24 UTC
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?
Comment 99 Jan Hubicka 2012-04-22 18:33:44 UTC
> 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
Comment 100 Paolo Carlini 2012-04-22 18:43:18 UTC
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 ;)
Comment 101 Ivan Godard 2012-04-22 19:35:08 UTC
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.
Comment 102 Ian Lance Taylor 2012-04-22 21:16:14 UTC
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.
Comment 103 Ivan Godard 2012-04-22 21:52:40 UTC
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?
Comment 104 Ian Lance Taylor 2012-04-22 22:26:50 UTC
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.
Comment 105 Marcelo Richter 2014-10-01 16:46:25 UTC
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).
Comment 106 Marcelo Richter 2014-10-01 18:16:39 UTC
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.
Comment 107 Ian Lance Taylor 2014-10-01 18:50:04 UTC
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.