Okay, so I managed to get virtuals working. It was actually very simple, following the advice in the previously posted link.
Here’s my changes for anyone reading along.
I started with stmlib/linker_scripts/stm32f4xx_flash.ld
as provided by stmlib. Then I added a section into the .text: part like this:
.text :
{
. = ALIGN(16);
*(.text) /* remaining code */
*(.text.*) /* remaining code */
*(.rodata) /* read-only data (constants) */
*(.rodata*)
*(.glue_7)
*(.glue_7t)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
__init_array_start = .;
KEEP(*(.init_array)) /* C++ constructors */
KEEP(*(.ctors)) /* and vtable init */
__init_array_end = .;
. = ALIGN(16);
_etext = .;
_sidata = _etext;
} >FLASH
I decided to not call the constructors in the startup file, but in my main()
, so I can add RAM initialization and other low level init functions before allowing the C++ machinery to kick off. The function was basically copied from the mentioned link.
static void callConstructors()
{
// Start and end points of the constructor list,
// defined by the linker script.
extern void (*__init_array_start)();
extern void (*__init_array_end)();
// Call each function in the list.
// We have to take the address of the symbols, as __init_array_start *is*
// the first function pointer, not the address of it.
for (void (**p)() = &__init_array_start; p < &__init_array_end; ++p) {
(*p)();
}
}
void main()
{
// low level init things here
callConstructors();
...
}
The only thing left now is to fix some of the complaints the linker had at this point. I was missing a operator delete( void* )
(mentioned in the link as well) and a __cxa_pure_virtual()
handler. Both of which I added to the project like this (a good place to put those is where you have your handlers for hard fault, systick, bus fault, etc.):
extern "C" {
void __cxa_pure_virtual() { while (1); } // nice to pick this up with the debugger
void operator delete(void* p) { while (1); } // will never need this in this project, so this is a dummy
}
This seems to do it for me. Constructors for globals are called and virtual functions seem to work as well.
If you get undefined reference to 'vtable for XYZ'
, then you probably forgot to give an implementation for a non-pure virtual function of that class (had that error before & had it again… some mistakes you make over and over…)
Thanks @pichenettes and @mqtthiqs!