I try to embed c++ code into the freertos-based firmware of the crazyflie drone, with an arm embedded gcc.
I succeeded in compiling, linking, launching, but dynamic_cast<> always returns nullptr, and exceptions raised are not caught. I enabled flags such as -fexceptions, -rtti, to no avail. Something to know: it’s freertos that launches a task that eventually calls a c++ function which in turn does c++ stuff.
Has anyone succeeded in doing this? I searched on numerous forums, including this one, but couldn’t find any information.
(and I’m aware rtti and exception are not recommended in embedded apps, but I still want to try)
I have used dynamic_cast in a FreeRTOS based C++ application and it works fine. My first guess is that your problem is totally unrelated to FreeRTOS, as you can’t derive from its structs to use RTTI anyway.
My thoughts on possible sources, make sure your main is i a .cpp file, and that you are linking the project as a C++ project. Also make sure the classes you are trying to use dynamic_cast on have virtual functions (at minimum a virtual destructor).
I would say that there isn’t that much of an issue with RTTI in embedded, it will space in the flash for the type tables, but doesn’t really impact execution when you are not using it. Exceptions may be a bit problematic, you need to make sure the exception handling is thread safe, and that all tasks that might leak an exception are wrapped in a catch all clause.
FreeRTOS does NOT redefine new and delete, but provides a thread safe version of memory allocation. If you are using new, then you need to make sure that the underlying library malloc(), free() and family have been made thread safe, often it isn’t good enough to just make new and delete safe, because other parts of the library may still be using malloc and free.
You likely used a different implementation to run on your Mac, (it may still be gcc, but it could have different options bundled in), you should check the options that your embedded gcc is using to make sure that RTTI is enabled, and the linker file that that information is actually being linked in.
No, using FreeRTOS you don’t want to try to fix new and delete, but you want to fix malloc and free, which new/delete are almost certain to call. as fixing new/delete isn’t enough, as parts of the library will be using malloc/free, and fixing that will very likely fix new/delete.
The 0000000 in the lib dump isn’t necessarily bad, as I think that is saying the the dynamic cast function is at relative 0 to the segment .text.__dynamic_cast (i.e the beginning of the segment), you will likely find many functions with a 0 offset like that.
No, using FreeRTOS you don’t want to try to fix new and delete, but you want to fix malloc and free, which new/delete are almost certain to call. as fixing new/delete isn’t enough, as parts of the library will be using malloc/free, and fixing that will very likely fix new/delete.
The 0000000 in the lib dump isn’t necessarily bad, as I think that is saying the the dynamic cast function is at relative 0 to the segment .text.__dynamic_cast (i.e the beginning of the segment), you will likely find many functions with a 0 offset like that.
ok, the function might exist then, and I do not know what is happening. It’s a pity I cannot run gdb remotely, I do not have means to do that…
Taking a quick look at the Crazyfiie web site, the unit is designed for C++, and should have no problem running gdb over the SWD link with a simple adaptor cable (maybe trouble doing it actually flying, but you should be able to do a lot of debugging with the system tethered.
Unless they have crippled their version of GCC to only use the so-called ‘embedded C++’, which omits features like this to save resources, it should work.
You can reverse-check the GCC features by using this: echo /nul | arm-none-eabi-g++.exe -x c++ -dM -E - > _builtin_defines.hpp
on Windows (and also in a similar way on Linux) and check the generated header file for e.g. #define __EXCEPTIONS 1
and #define __GXX_RTTI 1
Yep, looks like Wikipedia is wrong there. I tend to trust Wikipedia for simple thing like this until it become important, then it become just a source to point to how to verify.
I had some free time to go back to this problem.
It turned out that it was entirely my fault, as expected.
I figured that c++ code in headers was working as intended, but not the code in object files that I was compiling externally.
This led me to the insight that I was not compiling them correctly.
Using this small command (*), I could figure out that some files were compiled with -fpic, and some were not, which made the c++ code behave incorrectly.
Case closed, sorry for the noise, and thanks for your help.