FreeRTOS won’t build on GCC if Linker Time Optimization is set (issue for STM32 ARM CM-7 – port.c:427: undefined reference to `vTaskSwitchContext)

Hello, FreeRTOS won’t build on GCC if Link-Time Optimization (-flto) is set. (issue for STM32 ARM CM-7) I consistently get this error in port.c:427: undefined reference to vTaskSwitchContext). The vTaskSwitchContext() function is clearly defined in tasks.c. This problem can be fixed in tasks.h if vTaskSwitchContext is declared thus at line 2172: void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION attribute((used)); For some reason the double underscores before and after the word attribute do not appear in the post. Can you fix this so that this is include in the next release? I realize this is GCC dependent so you’d have to make it apply only for a GCC build. Thanks.

FreeRTOS won’t build on GCC if Linker Time Optimization is set (issue for STM32 ARM CM-7 – port.c:427: undefined reference to `vTaskSwitchContext)

We can’t put GCC specific code in a non-GCC specific file. What happens if you add this prototype to the port.c file specific to the Cortex-M port you are using? Then there will be two prototypes for the same function visible to the file, so it might puke.

FreeRTOS won’t build on GCC if Linker Time Optimization is set (issue for STM32 ARM CM-7 – port.c:427: undefined reference to `vTaskSwitchContext)

I tried that – i.e. putting the prototype void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION attribute((used)); in port.c. The GCC compiler doesn’t object but it doesn’t get rid of the undefined reference to vTaskSwitchContext either. That is because the link time optimizer is optimizing away the actual vTaskSwitchContext function defined in tasks.c because it doesn’t see it referenced anywhere. It is the tasks.c source code file that needs to have that prototype, or the equivalent of it somewhere.

FreeRTOS won’t build on GCC if Linker Time Optimization is set (issue for STM32 ARM CM-7 – port.c:427: undefined reference to `vTaskSwitchContext)

This is what I have done in all my FreeRTOS ports: Using this in task.h: ~~~

ifdef GNUC /* << EST: ‘used’ attribute need for LTO (Link Time Optimization) */

void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION attribute((used));

else

void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION;

endif

~~~ Using this in task.c: ~~~

ifdef GNUC /* << EST */

attribute((used)) /* using C++ compiler, vTaskSwitchContext() might be removed even with -O0? */

endif

void vTaskSwitchContext( void ) ~~~ I have seen that problem both with -Lto and compiling the RTOS in C++ mode. I agree that using compiler specifc things like above is not ideal, but worked for me. Another option would be to use some defines in the GCC portmacro.h Erich

FreeRTOS won’t build on GCC if Linker Time Optimization is set (issue for STM32 ARM CM-7 – port.c:427: undefined reference to `vTaskSwitchContext)

Is that an acceptable solution for you?
Yes, I think so, it is a GCC specific fix (?) in a GCC specific code. I will add it into the main line too.

FreeRTOS won’t build on GCC if Linker Time Optimization is set (issue for STM32 ARM CM-7 – port.c:427: undefined reference to `vTaskSwitchContext)

Unfortunately I replied that it fixed the problem too soon. I subsequently edited my post above to indicate that inserting the prototype void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION attribute((used)); in the port.c file does NOT work. It is the tasks.h or tasks.c file that must contain it. I am in the fortunate position that I know I will only ever use GNU CC so I can put it directly into task.h in my own project. I realize that you can’t do that so you may want to find another solution.

FreeRTOS won’t build on GCC if Linker Time Optimization is set (issue for STM32 ARM CM-7 – port.c:427: undefined reference to `vTaskSwitchContext)

Ok – I had already made that change, but not checked it in, so its easy to undo. Another solution is required. Presumable if vTaskSwitchContext() was called by C code, rather than just asm code, then the compiler/linker would know to keep the function. Can you try calling the function, or at least referencing the function, after the scheduler has been started? The compiler will not know that in the GCC port prvPortStartFirstTask() will not return, so you can call vTaskSwitchContext() after prvPortStartFirstTask() within the xPortStartScheduler() function, which is itself in the FreeRTOS/Source/portable/GCC/ARM_CMx/port.c file. You will notice that prvTaskExitError() is already called there for a simliar (but not identical) reason.

FreeRTOS won’t build on GCC if Linker Time Optimization is set (issue for STM32 ARM CM-7 – port.c:427: undefined reference to `vTaskSwitchContext)

I will add that I hope the issue has also been forwarded to the GCC team (unless this falls under a documentent Known Issue), as it sounds like a serious bug in the Link Time Optimization routine. Optimizations must not break valid code.

FreeRTOS won’t build on GCC if Linker Time Optimization is set (issue for STM32 ARM CM-7 – port.c:427: undefined reference to `vTaskSwitchContext)

I think in this case the offending function is only called from asm code, so the compiler cannot see it, but as we are discussing link time optimisation the LINKER should be able to see it.

FreeRTOS won’t build on GCC if Linker Time Optimization is set (issue for STM32 ARM CM-7 – port.c:427: undefined reference to `vTaskSwitchContext)

I’ve added this to compiler/platform specific portmacro.h: ~~~

ifndef portFORCE_USED

#define portFORCE_USED  __attribute__(( used ))

endif

~~~ and appended portFORCE_USED to vTaskSwitchContext decl. in task.h: void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION portFORCE_USED; This should solve the GCC specfic issue in a generic way. (see feature req. ticket #90 LTO Support in FreeRTOS) Just my 2ct, HS2

FreeRTOS won’t build on GCC if Linker Time Optimization is set (issue for STM32 ARM CM-7 – port.c:427: undefined reference to `vTaskSwitchContext)

My guess, is that LTO is looking at the call context of the function to see if it can be profitably inlined, or perhaps some optimiazations for the code are possible, and not seeing any context is omitting the function, but the ASM reference SHOULD raise a flag that there is a (possible) call that is from an unknown context, so the compiler needs to be conservative in optimization. Perhaps the ((used)) attribute is a way of signalling it, but to me it really shouldn’t be needed. As Real Time Engineers commented, a simpler fix might just be to put a call to it in C code so it knows it will be needed.