[rtems-users] C++ Virtual Functions--SOLVED!

Smith, Gene gene.smith at siemens.com
Fri Feb 4 00:10:48 UTC 2005


Excellent!!!
Virtual functions now work. I did exactly what Joel said to do using the 
psim example and Till's write-up explains the theory behind it.
(please see a few comments/questions below)

Till Straumann wrote, On 2/3/2005 3:33 PM:

> 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()'

	bl	__eabi
/shared/start/start.S does this right before zeroing .bss so I will too 
in my startup assembly file.

> 
>     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
>                                 */

I manually copied rtems_crti.o from where I built it in 
powerpc/mybsp/start/ to be with the other "installed" files like 
crtbegin.o under /opt/rtems-4.6. If not copied, the examples fail to 
link during rtems build since bsp_specs calls out this file. Is there a 
right way to handle this. (Possibly BSP(s) that use 
powerpc/shared/start/ have this figured out.)

>               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 you need a separate section called .init or, as most BSPs seem to do, 
put them in the .text section?  (I made a separate section.)

Also, do you need to define the _init sysbol in linkcmds, e.g.,
PROVIDE (_init = .);
(I did not define this symbol.)

Do you need a .fini section in linkcmds and define a _fini symbol?
(I included this section and defined the symbol per psim example.)

> 
>         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!

What is the "correct" way to make your .ctors and .dtors sections in 
linkcmds. There seems to be several schools of thought in the various 
BSPs. I.e, do you need a length value in the section and a terminating 
zero  and/or just a symbol defining the .[cd]tors start, i.e. 
__CTOR_LIST__ ?
(I did not did not provide length and zero termination, again like psim 
example.)

Finally, what about dtors? Should they work too? I have not tried them 
since shutting down is not a big priority right now.

Thanks to everyone for the excellent help!
-gene




More information about the users mailing list