tsandmann / freertos-teensy

FreeRTOS port with C++ std::thread support for ARM boards Teensy 3.5, 3.6, 4.0 and 4.1 (cortex-m4f and cortex-m7f)
92 stars 15 forks source link

Failure to run __libc_init_array when using GCC 11.3.1 on Teensy 4.1 #15

Closed pionex closed 1 year ago

pionex commented 1 year ago

I am building a project for Teensy4.1 on platformio. I have created a very basic project, although I'm not even getting to main() (and of course setup()). Whenever I include this project, the startup code will not get past __libc_init_array(); in the startup file. I have tried with the latest gcc 11.3.1 xpack as well as the standard teensy platform compiler (5.4.1).

It seems to be dying when it tries to call the function in the init_array_start vector assigned to eh_alloc.c. This seems to be related to exception handlers although I have -fno-exceptions as a build flag set.

pionex commented 1 year ago

actually I don't think it has anything specifically to do with exceptions - I get crashes when it jumps to many different vectors

pionex commented 1 year ago

I was trying to integrate this into an existing project. I just went back to a fresh environment with your examples and had some success. I can't get the basic blinky example to work, but the std::thread and std::jthread examples work with the exception of the #include "freertos_time.h" and setting the RTC.

tsandmann commented 1 year ago

Actually there were two issues, one with the latest update of the startup code in the cores library and another one with the outdated examples (old clock API). Sorry, should be fixed now. Thanks for reporting this.

However, errors during init_array_start() usually caused by global or static object initializations, e.g. when the constructor of such an object does sth. that's not valid at early startup.

pionex commented 1 year ago

No expectation for you to troubleshoot for me, but I will ask in case you have experienced this. I have one initializer that is causing a strange issue. I have added an infinite loop that blinks the led just before jumping to main in order to make sure that it's getting past the libc init function. I have added the __libc_init_array function definition directly to the startup so that I can control what gets called. If I exclude one particular vector from being executed, then the led blinks as expected. If I do allow it to get called, then the led blinks very slowly (it's on for 7 seconds instead of 100ms). I can tell from the map which object file is being initialized, but I haven't yet narrowed down exactly what is causing it.

pionex commented 1 year ago

I have a static class that creates a std::mutex and allocates a freertos queue. Either one of those things seems to cause an issue when initialized before main. For now, i have just changed to using lazy instantiation so that they get allocated when needed during execution and so far it's working. Thanks for your work on this project.

tsandmann commented 1 year ago

Creating a std::mutex before vTaskStartScheduler() is indeed a problem, because uxCriticalNesting is not initialized for use with taskENTER_CRITICAL() / taskEXIT_CRITICAL() which is used by the mutex's constructor. Therefore after __libc_init_array() interrupts are disabled and things like delay() don't work. You could add portENABLE_INTERRUPTS(); after __libc_init_array() or as first instruction in setup() to see if that's causing your issue. It's the same for queues.

This behavior is intended by FreeRTOS, see https://github.com/FreeRTOS/FreeRTOS-Kernel/issues/254. If you use FreeRTOS APIs before the scheduler is started (std::mutex does), then interrupts are disabled until vTaskStartScheduler() is executed. I don't think there is a clean solution to solve or change this.