On 12/12/2010 06:54, H.J. Lu wrote:

[ off-list, but it's not personal, so let's Cc the list back in, someone might
find this explanation of the mechanism useful in the archives. ]

> Can you check the assembly output? Since
> 
> ----
>     Note that the particular values of PRIORITY do not matter; only
>     their relative ordering.
> ---
> 
> on Linux, the numeric string in section name isn't the same as
> PRIORITY in source file. That means on Linux, the order
> of .ctors sections in 2 files isn't the relative ordering of PRIORITY
> of those 2 files.

  Well, at least on PE-COFF, the numeric string is (65536-priority).  It is
zero padded to five digits, so that the linker's alphabetical sort effectively
becomes a numeric sort, and the reason for the inverting the numeric order of
priorities is because .ctors gets read backwards at startup.

  I did actually check the assembly somewhere between writing "IIRC" and
finishing my email as it happens.  For a testcase based on your example:

class Some_Class {
  int x;
public:
  Some_Class();
  ~Some_Class();
};

Some_Class  A  __attribute__ ((init_priority (2000)));
Some_Class  B  __attribute__ ((init_priority (543)));

... what we get is a static_initialization_and_destruction function that takes
the init priority level as an argument and constructs or destroys (per a
second argument) everything at that level only:

        .file   "clas.c"
        .globl  _A
        .bss
        .align 4
_A:
        .space 4
        .globl  _B
        .align 4
_B:
        .space 4
        .text
        .def    __Z41__static_initialization_and_destruction_0ii;       .scl    
3;      .type   32;     .endef
__Z41__static_initialization_and_destruction_0ii:
LFB0:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register 5
        subl    $24, %esp
        cmpl    $1, 8(%ebp)
        jne     L2
        cmpl    $2000, 12(%ebp)
        ^^^^^^^^^^^^^^^^^^^^^^^
        jne     L3
        ^^^^^^^^^^
        movl    $_A, (%esp)
        call    __ZN10Some_ClassC1Ev
L3:
        cmpl    $543, 12(%ebp)
        ^^^^^^^^^^^^^^^^^^^^^^
        jne     L2
        ^^^^^^^^^^
        movl    $_B, (%esp)
        call    __ZN10Some_ClassC1Ev
L2:
        cmpl    $0, 8(%ebp)
        jne     L1
        cmpl    $543, 12(%ebp)
        ^^^^^^^^^^^^^^^^^^^^^^
        jne     L5
        ^^^^^^^^^^
        movl    $_B, (%esp)
        call    __ZN10Some_ClassD1Ev
L5:
        cmpl    $2000, 12(%ebp)
        ^^^^^^^^^^^^^^^^^^^^^^^
        jne     L1
        ^^^^^^^^^^
        movl    $_A, (%esp)
        call    __ZN10Some_ClassD1Ev
L1:
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
LFE0:


  Then we have __GLOBAL__[I/D] functions for each priority level, which load
the appropriate priority and construct/destruct argument and call that:

        .def    __GLOBAL__I.00543_A;    .scl    3;      .type   32;     .endef
__GLOBAL__I.00543_A:
LFB1:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register 5
        subl    $24, %esp
        movl    $543, 4(%esp)
        ^^^^^^^^^^^^^^^^^^^^^
        movl    $1, (%esp)
        ^^^^^^^^^^^^^^^^^^
        call    __Z41__static_initialization_and_destruction_0ii
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
LFE1:

        .def    __GLOBAL__D.00543_A;    .scl    3;      .type   32;     .endef
__GLOBAL__D.00543_A:
LFB2:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register 5
        subl    $24, %esp
        movl    $543, 4(%esp)
        ^^^^^^^^^^^^^^^^^^^^^
        movl    $0, (%esp)
        ^^^^^^^^^^^^^^^^^^
        call    __Z41__static_initialization_and_destruction_0ii
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
LFE2:

        .def    __GLOBAL__I.02000_A;    .scl    3;      .type   32;     .endef
__GLOBAL__I.02000_A:
LFB3:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register 5
        subl    $24, %esp
        movl    $2000, 4(%esp)
        ^^^^^^^^^^^^^^^^^^^^^^
        movl    $1, (%esp)
        ^^^^^^^^^^^^^^^^^^
        call    __Z41__static_initialization_and_destruction_0ii
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
LFE3:

        .def    __GLOBAL__D.02000_A;    .scl    3;      .type   32;     .endef
__GLOBAL__D.02000_A:
LFB4:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register 5
        subl    $24, %esp
        movl    $2000, 4(%esp)
        ^^^^^^^^^^^^^^^^^^^^^^
        movl    $0, (%esp)
        ^^^^^^^^^^^^^^^^^^
        call    __Z41__static_initialization_and_destruction_0ii
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
LFE4:

... and it is these routines that are inserted in reverse-priority order into
the .ctors and .dtors tables (don't forget that the .ctors table is run
backward, the .dtors is run forward):

        .section        .ctors.64992,"w"
        .align 4
        .long   __GLOBAL__I.00543_A
        .text

        .section        .dtors.64992,"w"
        .align 4
        .long   __GLOBAL__D.00543_A
        .text

        .section        .ctors.63535,"w"
        .align 4
        .long   __GLOBAL__I.02000_A
        .text

        .section        .dtors.63535,"w"
        .align 4
        .long   __GLOBAL__D.02000_A


  So that ought to be entirely global ordering at final-link time.  I don't
know if ELF does it differently.

    cheers,
      DaveK

Reply via email to