understanding the __libc_init_array

后端 未结 4 1646
后悔当初
后悔当初 2020-12-24 08:48

I viewed the source code of __libc_init_array from http://newlib.sourcearchive.com/documentation/1.18.0/init_8c-source.html .
But I don\'t quite understand what this fun

4条回答
  •  不知归路
    2020-12-24 09:24

    The answer from @Robotbugs is interesting, but I found some additional information that might satisfy the curiosity of others.

    The System V Application Binary Interface seems to apply to the executables produced by gcc (and I guess some other compilers - clang comes to mind).

    The special sections chapter states (only relevant parts, reordered by me):

    .preinit_array:

    This section holds an array of function pointers that contributes to a single pre-initialization array for the executable or shared object containing the section.

    .init_array

    This section holds an array of function pointers that contributes to a single initialization array for the executable or shared object containing the section.

    .fini_array

    This section holds an array of function pointers that contributes to a single termination array for the executable or shared object containing the section.

    The file init.c from newlib includes:

    /* Iterate over all the init routines.  */
    void
    __libc_init_array (void)
    {
        size_t count;
        size_t i;
    
        count = __preinit_array_end - __preinit_array_start;
        for (i = 0; i < count; i++)
            __preinit_array_start[i] ();
    
    #ifdef HAVE_INIT_FINI
        _init ();
    #endif
    
        count = __init_array_end - __init_array_start;
        for (i = 0; i < count; i++)
        __init_array_start[i] ();
    }
    

    This corresponds to the canonical linker script solution for STM32 processors (as an example):

    .preinit_array     :
    {
        PROVIDE_HIDDEN (__preinit_array_start = .);
        KEEP (*(.preinit_array*))
        PROVIDE_HIDDEN (__preinit_array_end = .);
    } >FLASH
    .init_array :
    {
        PROVIDE_HIDDEN (__init_array_start = .);
        KEEP (*(SORT(.init_array.*)))
        KEEP (*(.init_array*))
        PROVIDE_HIDDEN (__init_array_end = .);
    } >FLASH
    .fini_array :
    {
        PROVIDE_HIDDEN (__fini_array_start = .);
        KEEP (*(SORT(.fini_array.*)))
        KEEP (*(.fini_array*))
        PROVIDE_HIDDEN (__fini_array_end = .);
    } >FLASH
    

    That linker script portion is quite clear: it defines the symbols necessary for Newlib to execute the array functions specified by the System V Application Binary Interface for preinit and init. This seems to be the standard solution for static constructors in C++. And fini would corresponds to static destructors.

    The most ironic part of this story, of course, is that using static C++ objects without the Construct On First Use Idiom is the best way to get the static initialization order problem! I.e. C++ objects should in practice never be constructed via the preinit/init array above!

提交回复
热议问题