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

Till Straumann strauman at slac.stanford.edu
Fri Feb 4 20:49:24 UTC 2005


(comments inserted below)

Smith, Gene wrote:
> 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.

Make sure you zero .sbss and .sbss2, too!

> 
>>
>>     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.)

Here's what I do

powerpc/mybsp/start/Makefile.am:

VPATH = @srcdir@:@srcdir@/../../shared/start

S_FILES = start.S rtems_crti.S

I have my own 'start.S' but no rtems_crti.S -- hence
gmake will pick up the one from the shared area as
instructed by the VPATH.

If you configured --enable-maintainer-mode, the necessary
'automake' etc. should be triggered automatically...

> 
>>               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.)

I believe '.init' sections of linked objects (and only '.init' sections)
should go into a '.init' section of the output - but probably it doesn't
really matter (as long as you link ecrti/ecrtn and the linker glues
all the '.init' sections together). Same applies to '.fini'.

The sectioning of the final executable is only of significance to
your boot loader and unless you expect it to do specific things
for your BSP there's no use for them [many BSPs convert to binary
anyways].

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

You must not. The whole point of 'rtems_crti' was introducing
a '_init' symbol at the right place.

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

You probably should - I never bothered about cleanly leaving the
RTEMS executive...

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

They are probably not really schools of thought but reflect the
status of gcc at the time the BSP was developed. (In some cases
even worse: they reflect the status of the system/gcc they were
copied from...)

> 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__ ?

The amazing answer seems to be that it doesn't matter. Ultimately,
it depends on what gcc is doing (gcc/crtstuff.c) and the gcc-3.2.3
I'm looking at seems to handle things itself. It sticks local (static)
definitions of __CTOR_LIST__ and __CTOR_END__ right into the '.ctor'
sections of crtbegin/crtend and uses these when traversing the list.

> (I did not did not provide length and zero termination, again like psim 
> example.)

Again: ultimately, your linkcmds and bsp_specs have to be in sync with
your gcc and peeking into some gcc source files, disassembly of e.g.,
ecrti.o and the like are very reasonable things to do!

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

For me neither but it's certainly desirable to do things right...

-- Till
> 
> Thanks to everyone for the excellent help!
> -gene
> 





More information about the users mailing list