Dynamic initialization of non-local C++ objects #213
Unanswered
wintermuteger
asked this question in
Bare metal embedded software
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
According to the C++ standard https://en.cppreference.com/w/cpp/language/initialization there are different initialization mechanisms for non-local variables in place. While static initialization is typically done during compile time (by placing the global/static in the data-segment of the resulting binary) dynamic initialization has to be done during the initialization phase of the binary.
The standard startup code generated by the compiler/linker typically takes care that all constructors of non-local variables are called bevore int main() is entered.
Current multi-core examples do not use a single main()-function, but have dedicated main-like functions for each core (e51(), u54_1(), u54_2, etc.). As the linker will not link correctly without main function the -nostartup flag shall be used. This has the side-effect that – seemingly – dynamic initialization is not taking place.
Code example (essence from actual code):
//------------------------------------------------------------------------------------
#include “mss_gpio.h”
class MyGpio {
private:
GPIO_TypeDef* selGpioBlk = GPIO2_LO;
public:
MyGpio();
};
class MySystem {
public:
MyGpio myGpio{};
MySystem() {};
};
MyGpio::MyGpio() //ATTENTION - Compiled for baremetal RISC the constructor IS NOT CALLED, if part of a global object!
: selGpioBlk{GPIO2_LO}
{
}
MySystem mySystem{}; //Global MySystem object, which should call all constructors BEFORE entering main, setting selGpioBlk to GPIO2_LO.
extern "C" void u54_1( void )
{ /My code using mySystem/
//mySystem.myGpio.selGpioBlk was not initialized here!
}
//------------------------------------------------------------------------------------
Breaking in u54_1 and printing the memory content it looks like selGpioBlk is not initialized.
After reviewing mss_entry.S and system_startup.c most likely root-cause for the observed issue was that constructors were never being executed as part of dynamic initialization (before non-existing main). This was confirmed by placing breakpoints on the constructors which were not hit after manual load to LIM in gdb.
It is unclear, why initialization “GPIO_TypeDef* selGpioBlk = GPIO2_LO;” inside of class definition, which in theory might be static, did not succeed either. Maybe it is skipped or combined with the non-default constructor function provided, and therefore not implemented statically but also dynamic.
Work workaround -> Adding manual initialization and copy operation.
//------------------------------------------------------------------------------------
extern "C" void u54_1( void )
{
mySystem = MySystem(); //Manual construction of a new object and copy to global/non-local mySystem
}
//------------------------------------------------------------------------------------
One big issue with the presented workaround is, that standardized C++ behavior is not guaranteed by design any longer. What happens e.g. with local static variables/objects, that are dynamically initialized? How to detect those errors upfront, so new team members will not repeat the same mistakes over and over again?
Did I miss something and is there some other better solution for this?
Beta Was this translation helpful? Give feedback.
All reactions