[rtems-users] C++ Virtual Functions

Joel Sherrill <joel@OARcorp.com> joel.sherrill at OARcorp.com
Thu Feb 3 20:49:33 UTC 2005


Thanks Till.  I forgot that I had started a Wiki Page on this.
Feel free to add info to it:

http://www.rtems.com/phpwiki/index.php/Using%20C%2B%2B

Till Straumann wrote:
> Here's my recollection of things [powerpc] -- sorry for the lengthy
> explanation...
> 
> 1) BSP should call [gcc provided] '_eabi()' very early to set up a
>    SYSV/EABI compliant environment [load r2/r13, stack align etc.].
>    If you don't do this, e.g., SYSV/EABI short data areas won't work
>    (see gcc -msdata -meabi options) !!
> 
> 2) RTEMS calls '_init()' which among other things works through the
>    C++ static constructor list -- provided that your linker stript
>    and bsp_specs files are correct. (See Appendix on how it works.)
> 
> HOWEVER: There is a problem here, in that '_eabi()' ends up calling
>    '_init()' [actually, '__init()' -- we renamed to fix the problem
>    described here] when it is still too early to initialize the
>    C++ environment.
> 
>    Note that both details are of the 'seems to work' type. You
>    won't notice anything if you don't call _eabi() until you try
>    to use an essential SYSV/EABI feature.
>    Likewise, calling '_init()' too early might not cause problems
>    in many cases until one of your constructors uses an yet unavailable
>    feature [such as e.g., 'malloc()'].
> 
> ==> a typical chicken + egg. problem
> 
>    1) we want to call _eabi() early [libbsp/powerpc/shared/start/start.S]
>    2) we want to prevent __init() from being called too early (by _eabi())
>    3) we want to call __init() at the apropriate time.
>    4) we dont want to hack gcc.
> 
> Here's the solution [uses '.init' magic as described in the appendix]:
> 
>    an additional startup file 'rtems_crti.S' "terminates" __init()
>    so it becomes a no-op and introduces a new '_init()' entry point
>    to be used by rtems (ThreadHandler).
> 
> Hence here's what you need:
> 
>    o BSP's 'start.S' file must call '_eabi()'
> 
>    o BSP's bsp_specs:
>        *startfile: must contain [order is crucial]
> 
>              ecrti%O%s        /* prologue of __init() */
>              rtems_crti%0%s   /* epilogue of __init(), prologue of 
> _init() */
>                               /* now _init() does everything __init() 
> usually
>                                * does
>                                */
>              crtbegin.o%s     /* crucial stuff, e.g. C++ exceptions, 
> dtors */
> 
>        *endfile: must contain [order is essential]
> 
>              crtend.o%s       /* crucial stuff, e.g., C++ exceptions, 
> ctors */
>              ecrtn.o%s        /* _init() epilogue() */
> 
> Here's what happens (properly linked executable):
> 
>    - BSP start.s calls _eabi(); SYSVI/EABI environment setup
>    - _eabi() calls __init()
>    - __init() returns immediately
>    - BSP initializes
>    - RTEMS starts up; initializes newlibc
>    - ThreadHandler calls _init() [points to what __init() was intended 
> to do]
>    - _init() walks through code snippets provided by various '.init' 
> sections
>    - _init() encounters _do_global_ctors_aux() [provided by crtend.o]
>    - _do_global_ctors_aux() initializes C++ environment [exceptions, ctors]
>    - ...
> 
> HTH
> 
> -- Till
> 
> 
> APPENDIX on '.init' linker magic
> --------------------------------
> 
>    Note that '_init()' is not an ordinary function but 'compiler/linker
>    magic' which uses the special '.init' section. An object file's
>    '.init' section must be composed of small snippets of code like
> 
>        do_something();
>        do_something_else();
> 
>    that should eventually go into the '_init()' routine. Any object
>    may contain such code.
>    The linker finally gathers all these snippets (in the order the objects
>    are linked together) and that's where the 'ecrti.o/ecrtn.o' files
>    come into play. These two files bracket the '.init' snippets with
>    a proper function prologue (from ecrti.o) and epilogue (ecrtn.o),
>    i.e., if you link (ecrti/ecrtn implicitely provided by gcc specs)
> 
>      ecrti.o  my_object.o ecrtn.o
> 
>    you end up with something like ('translated into C'):
> 
>      _init ()
>      { /* from ecrti.o */
> 
>      do_something();
>      do_something_else();  /* from my_object.o */
> 
>      } /* from ecrtn.o */
> 
>    Hence, the rtems_crti.S file does the following:
> 
>      /* from ecrti.o: */
>      __init()
>      {
>      /* from rtems_crti.o */
>      }
> 
>      _init()
>      {
>      /* '.init' sections from other objects */
> 
>      /* from crtend.o: */
>      __do_global_ctors_aux();
> 
>      /* from ecrtn.o:  */
>      }
> 
> 
>    GCC uses this feature to call C++ static constructors by sticking
>    a call to
> 
>      __do_global_ctors_aux()
> 
>    into the '.init' section of 'crtend.o' -- hence if you don't link
>    against 'crtbegin/crtend' [bsp_specs] your constructors are not
>    called.
> 
>    ==> your gcc configuration, linkcmds and bsp_specs must harmonize!
> 
> 
> Phil Torre wrote:
> 
>> On Thu, Feb 03, 2005 at 09:07:44AM -0500, Smith, Gene wrote:
>>
>>> I went back a read everything I could find on this list regarding this
>>> and several people have reported this problem. The only one who reported
>>> a resolution did like you and wrote their own initializer (Phil Torre).
>>> However there was a lot of discussion about "eabi" that got into the
>>> ctor init and pointed out that it occurs in a call to _init() in
>>> _Thread_Handler when __USE_INIT_FINI__ is defined. The _init() call
>>> occurs on my system as described which in turn calls etext and
>>> eventually __do_global_ctors_aux__ but I never see any constructors
>>> actually called before _init() returns. I assume it is supposed to call
>>> the constructors for any globally or statically defined c++ objects
>>> somewhere inside the _init() call?  Also, are these c++ objects supposed
>>> to be in the .bss section?
>>> -gene
>>
>>
>>
>> Someone subsequently pointed out to me that this was the wrong thing
>> to do, so these days I have added crtbegin.o and crtend.o to our 
>> bsp_specs file, like so:
>>
>> *startfile:
>> %{!qrtems: %(old_startfile)} %{!nostdlib: %{qrtems:  ecrti%O%s 
>> crtbegin.o%s \
>> %{!qrtems_debug: start.o%s} \
>> %{qrtems_debug: start_g.o%s}}}
>>
>> *endfile:
>> %{!qrtems: %(old_endfile)} %{qrtems: crtend.o%s ecrtn%O%s}
>>
>> (I'm guity of cargo-cult programming here, as I don't actually understand
>> why this works.  It does the trick, though, and without requiring me to
>> explicitly call my own initializer function.)
>>
>> -Phil
> 
> 
> 


-- 
Joel Sherrill, Ph.D.             Director of Research & Development
joel at OARcorp.com                 On-Line Applications Research
Ask me about RTEMS: a free RTOS  Huntsville AL 35805
    Support Available             (256) 722-9985




More information about the users mailing list