[rtems-users] C++ Virtual Functions

Till Straumann strauman at slac.stanford.edu
Thu Feb 3 20:33:50 UTC 2005


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





More information about the users mailing list