I am programming an STM32F413 microcontroller with SystemWorkbench 4 stm32. The Interrupt vectors are defined in an assembly startup file as weak aliases like follows:
.weak TIM1_UP_TIM10_IRQHandler
.thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
And referenced in an object like follows:
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.....
.word TIM1_UP_TIM10_IRQHandler
.....
So that the g_pfnVectors
is a list of the addresses of the IRQ Handler functions. They are declared as weak aliases, so that if they are not defined by the user, the default handler is used.
I have defined the handler like this:
extern "C" {
void TIM1_UP_TIM10_IRQHandler() {
if (SU_TIM->SR & TIM_SR_UIF) {
SU_TIM->SR &= ~TIM_SR_UIF;
...
}
}
}
This works fine with the normal compiler optimization flags, however I wanted to try if I get smaller and possibly faster code with -flto
(mainly for trying it, don't really needed it). But when compiling with -flto
, g++ ignores my implementation of the handler and just uses the default handler, my handler isn't in the code at all.
So I tried to force g++ to include the function by adding __attribute__((used))
to the function definition, but it was still not compiled. However if I give it another name, then it was included in the binary. Also if I remove the weak alias and just have a reference to the handler in the startup file, it works too.
So somehow the weak aliases don't work with g++ link time optimization. Maybe someone can tell me what the error is and what I'm doing wrong here.
EDIT:
I have looked at which symbols are created with nm on the resulting .elf File, and the TIM1_UP_TIM10_IRQHandler
is exported as a weak symbol with the address of the DefaultHandler. However when viewing just the .o file from the compilation unit containing the TIM1_UP_TIM10_IRQHandler
function, it is exported as a symbol in the text section (T). So the linker, for some reason, chooses to keep the weak symbol, even though there is a strong symbol with the same name.
I think you should inform the compiler that it the interrupt __attribute__ ((interrupt ("IRQ")))
, which is not needed normally as F4 has the stack by default aligned to 8 by the hardware.
If it does not help the workaround is to have a function pointer assigned with the handler, which will prevent it from discarding (if the pointer itself will not be discarded itself - check with your debugger).
The last resort - change the .s file with the vector table definitions
For those looking for this, still, there is apparently a confirmed bug in GCC 7 related to link-time optimization (-flto
):
https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966
I have just run into this, again, with GCC 8 (gcc-arm-none-eabi-8-2019-q3-update release), the behavior is still the same.
The workaround that also works for me (from https://github.com/ObKo/stm32-cmake/issues/78) is to remove or comment the weak definitions at the end of the startup_XXX.s
file, so change, for example
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
to
/*
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
*/
and replace them with your own implementation in a source file:
void NMI_Handler(void)
{
//...
}
All weak handlers need to be removed that are being called, so for example if you have UART1_Handler()
defined in the HAL/LL drivers, you need to remove the corresponding .weak
entry from the startup_XXX.s
file, otherwise the interrupt will lock up the MCU by getting stuck in the default infinite loop, without executing the intended interrupt handler and returning from the interrupt, allowing other code execution to resume.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With