= Using C Plus Plus = = Using C++ = RTEMS provides support for C++ applications. Applications should be compiled with an RTEMS specific tool sets that provides RTEMS thread support. RTEMS tool sets are build with the '''-rtems''' target. The thread model of the compiler builds into the GCC libraries support for interacting with RTEMS to insure the thread safe operation of your application. = Size and Performance = It is common to see comments made about the size and speed of C++ applications. Using C++ does not effect the performance of RTEMS or the performance of accessing RTEMS services from C++. A C++ appication may result in a larger executable size as linking to the standard C++ library can pull in parts of the library, or using RTTI can result in extra data being including in the executable. The GNU compiler for RTEMS is built using the RTEMS thread model. This means it is best you use an RTEMS built tool chain when using C++. The thread model in GCC lets applications operate in a thread safe manner. The compiler is built with low level calls to RTEMS mutex type resources it uses when performing thread safe operations. ''More to come here.'' = Exceptions = A great description of the C++ Exception design in GCC including section and startup information is at - {{{ http://gcc.gnu.org/ml/gcc/2002-07/msg00352.html }}} = Linking = C++ programs need to link to the standard C++ library (libstd++.c) and the C++ front-end ('''g++''') is required to perform the linking task. Do not add '''-lstd++''' to the command line of '''gcc''', '''ld''' or a '''specs''' file. The rationale is quite simple: Linking c++ is more than "just adding a library". G++ reflects this thought and treats libstdc++ as an internal implementation detail users do not need to know about or touch. On some targets/with some compilers "linking c++" is effectively "just adding -lstdc++" but on most others it is more. What confuses some users is "gcc ... -lstdc++" once having been worked with old gcc (IIRC, gcc < 4.0) on i386 targets. If you use the RTEMS Makefile Template ($TARGET/make/Templates/Makefile.leaf), this is the easy way to link properly (example from the Template): {{{ # The following links using C++ rules to get the C++ libraries. # Be sure you BSP has a make-cxx-exe rule if you use this. ${ARCH}/xxx-your-program-here: ${OBJS} ${LINK_FILES} $(make-cxx-exe) }}} = Global Object Construction and Destruction = The C++ language allows the declaration of objects at a global level. A global object like every other type of object needs to be constructed how-ever it is not your code that defines when and how, as it does with heap or locally allocated objects. Global objects are constructed by the runtime supporting your application, RTEMS. Global objects that are not constructed may or may not work depending on the object. An object that uses virtual functions will not work and can result in bus type errors as the object's vtable pointer will not have been initialised. Global object construction requires the compiler and RTEMS work together. This is a constant source of maintenance issues as changes in one can effect the other. The compiler generates special code to construct and destruct each global object. The constructor and destructor pointer's to this code is placed in a special section, usually called .ctor and .dtor. The linker will pull all the pointers into a single section giving you a table of pointers to constructors and destructors. The order or placement of a specific pointer in these tables cannot be easily set and any application that relies on a specific order should be considered broken and needs to be fixed. RTEMS calls the constructors after the kernel is running, but before first '''Init''' task runs. This means global objects can allocate memory from the heap, and create objects such as threads and semaphores. These constructors run in the context of the Init task before its entry point is invoked. See _Thread_Handler() for details. Different processors can require different initialisation sequences. An example is the PowerPC and its support for the SYSV/EABI compliant environment. == PowerPC Initialisation == 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). RTEMS calls '''init()''' which among other things works through the C++ static constructor list -- provided that your linker script and '''bsp_specs''' files are correct. See [wiki:#InitMagic C++ .init Linker Magic] 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''' 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 provided by RTEMS such as '''malloc()'''. For the PowerPC a typical chicken and egg problem exists - #we want to call '''_eabi()''' early (libbsp/powerpc/shared/start/start.S) #we want to prevent '''_init()''' from being called too early (by '''eabi()''') #we want to call '''__init()''' at the apropriate time. #we dont want to hack gcc. Here's the solution using the '''.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 ([wiki:ThreadHandler ThreadHandler]). Hence here's what you need : * BSP's 'start.S' file must call '_eabi()' * 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 #[wiki:ThreadHandler 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) #... = C++ .init Linker Magic = #[wiki:InitMagic InitMagic] * Note''', '''_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