I’m using FreeRTOS V10.1.0 with gcc 6.3.1 on an STM32F427.
When I enable link time optimization (-flto) I get a linker error regarding vTaskSwitchContext():
/tmp/cczXZviN.ltrans3.ltrans.o: In function `PendSV_Handler':
<artificial>:(.text+0x42c): undefined reference to `vTaskSwitchContext'
This is because vTaskSwitchContext() is called from asm, and all places it gets called from in C are optimimized away.
There is a workaround for this in Source/portable/GCC/ARM_CM4F/port.c, vTaskSwitchContext() is called from xPortStartScheduler(), however gcc has become smart enough to detect that his code is never executed, and optimizes the call way.
Therefore I developed a new workaround, add a new function to Source/portable/GCC/ARM_CM4F/port.c (or any other C file if appropriate):
/* Call vTaskSwitchContext() from a function with the used attribute set
so that link time optimisation does not remove the symbol.*/
static void __attribute__((used)) vPortNoOptimize()
{
vTaskSwitchContext();
}
Thanks for reporting. Did you try V10.2.1? I think that has some
update to help with link time optimisation too - especially the new
memory barrier macro.
The same problem exists in V10.2.1, also the same workaround works for it.
I noticed the linker error does not occur if vTaskSuspend() is called anywhere from the project, because that calls vTaskSwitchContext().
This works regardless of using or even including vTaskSuspend .
The patch in xPortStartScheduler calling vTaskSwitchContext to trick LTO never worked for me.
Just my 2ct.
I thought this was in the code already, but now I look again I see it is
only in the ARMv8-M code (Cortex-M33/M23) not in the ARMv7-M code
(Cortex-M0/3/4/7).
Can’t put compiler specific syntax in a file that is built by more than 20 different compilers, but there are other ways - which kernel port are you using? For example, is this an ARM Cortex-M4F, or something else?
@Richard You can
By adding portDONT_DISCARD to portmacros.h and tag vTaskSwitchContext with it as proposed here.
Would be nice if I could ditch this little patch I’m keep adding for every update
$ arm-none-eabi-gcc.exe --version
arm-none-eabi-gcc.exe (GNU Tools for ARM Embedded Processors 6-2017-q2-update) 6.3.1 20170620 (release) [ARM/embedded-6-branch revision 249437]
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
No, I’m asking which FreeRTOS port are you using, not which compiler are you using. FreeRTOS runs on more than 40 different architectures, and some 20+ compilers - each combination of a compiler and an architecture is considered a port. I know which compiler you are using, but I don’t know which port you are using. Does the chip you use have an ARM Cortex-M4 core? If not, which core does it have? ARM9, ARM7, Cortex-M7, Cortex-M33, etc. are all examples of ARM cores, which I’m assuming this is. Alternatively, if you are not sure, tell me the part number of the chip you are using.
I see your point Richard. I can only say that the GCC ARM Cortex-M3 and M4 ports are affected. That’s what I’m using for my work. Seems that up to now GCC LTO is not smart enough to handle/detect function calls from inline assembler code properly. So I guess all GCC ports with a similar implementation like CM3/4 where asm xPortPendSVHandler calls vTaskSwitchContext might cause troubles using LTO. Unfortunately.
In rare cases it might cause other, hard to find and to fix troubles, too.
But the benefit in terms of code size/speed is pretty good and I found a solution for the 1-2 other issues I’ve encountered.
I’ve verified my patch. While migrating to GCC6.3.1 I’ve noticed that the added call to vTaskSwitchContext in Source\portable\GCC\ARM_CM3\port.c::xPortStartScheduler didn’t help (anymore) with my relevant optimizer flags -Os -flto. I’m pretty sure the optimizer just inlines this call.
Please note that I’ve configured INCLUDE_vTaskSuspend 0 and also the other optional config’s used in vTaskSwitchContext are disabled making it a very small function.
It’s getting harder and harder to trick the optimizers these days…
My thinking is this needs to be entered as a bug in the GCC tracker. By definition, optimization must not break valid code, and calling a C function from in line assembly is valid. If LTO doesn’t take into account possible references to the code in question from in line assembly, or other sources that don’t give it the details of the call, it is broken.