[MSP432 - gcc] Works with linker option -Og but geneates hardfault with linker option -Os

bietians wrote on Thursday, March 16, 2017:

Hi,

I am using msp 432 port blinky demo modified to use software timer to toggle periodically instead of taskDelayUntil.
toolchain: GNU ARM embedded toolchain 5-2016-q3 update
ID: eclipse cdt with plugin http://gnuarmeclipse.github.io/

working set up:
compiler flags: -mcpu=cortex-m$(CORTEX_M) -march=armv7e-m -mfloat-abi=hard
-mfpu=fpv4-sp-d16 -mthumb -ffunction-sections -fdata-sections -Dgcc -Wall -std=c11
-Og -g -gstrict-dwarf -fmessage-length=80 --specs=nano.specs

linker flags: -mcpu=cortex-m$(CORTEX_M) -march=armv7e-m -mfloat-abi=hard
-mfpu=fpv4-sp-d16 -mthumb -ffunction-sections -fdata-sections -Dgcc -Wall
-Og -g -gstrict-dwarf -Xlinker --cref -Wl,–gc-sections --specs=nano.specs

Not working( hardfault ) set up:
compiler flags: -mcpu=cortex-m$(CORTEX_M) -march=armv7e-m -mfloat-abi=hard
-mfpu=fpv4-sp-d16 -mthumb -ffunction-sections -fdata-sections -Dgcc -Wall -std=c11
****-Os -g -gstrict-dwarf ****

linker flags: -mcpu=cortex-m$(CORTEX_M) -march=armv7e-m -mfloat-abi=hard
-mfpu=fpv4-sp-d16 -mthumb -ffunction-sections -fdata-sections -Dgcc -Wall
-Os -g -gstrict-dwarf -Xlinker --cref -Wl,–gc-sections --specs=nano.specs

the only difference between these two setups is the optimization level -Og and -Os.

I tried this setup: http://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html. It enters hardfault handler. But it doesnt hit the breakpoint at end of prvGetRegistersFromStack instead it jumps back to main.

Please provide inputs on how it could be resolved.

rtel wrote on Thursday, March 16, 2017:

Jumping back to main() makes it sound like the board is resetting.
Could it be a watchdog reset?

Do you have an infinite loop at the end of the hardfault handler?
Something like:

for( ;; );

so the code should not go anywhere even if the breakpoint is not hit? I
suspect the breakpoint isn’t being hit because with the high
optimisation level GCC cannot directly correlate a line of C code to its
assembly code output.

bietians wrote on Thursday, March 16, 2017:

Thank you for the reply. It seems like an issue in ResetHandler ISR and I added the code in ResetHandler to zero fill the bss and the problem seems to have disappeared.

Now, the question is, since bss was uninitialized and heap for freertos is in bss segment(as I observed in linker map file), would it have caused prvMalloc to fail? if yes, I do not understand why it worked with optimization level -Og ?

bietians wrote on Thursday, March 16, 2017:

yes, the hardfault handler has an infinite loop at the end but couldnt get it to hit the breakpoint.

rtel wrote on Friday, March 17, 2017:

Thank you for the reply. It seems like an issue in ResetHandler ISR and
I added the code in ResetHandler to zero fill the bss and the problem
seems to have disappeared.

None of executed compiled C code is going to be valid if the C run-time
is not set up BEFORE main() is called.

Now, the question is, since bss was uninitialized and heap for freertos
is in bss segment(as I observed in linker map file), would it have
caused prvMalloc to fail? if yes, I do not understand why it worked with
optimization level -Og ?

The answer to that is, it might have caused it to fail or it might not,
and it may have been inconsistent between builds. Like I said, C
assumes things are initialised correctly before the C code is executed,
and any execution that occurs when things are not initialised cannot be
predicted in advance. Changing the optimisation level will greatly
change how, when and which variables are accessed, and if the variables
have random numbers in them rather than initialised values then it is
conceivable the behaviour will be completely different at different
optimisation levels.

davidbrown wrote on Friday, March 17, 2017:

This seems to be an issue with TI’s compiler setup. For some reason, TI have always insisted on /not/ clearing bss at startup, with all their compilers and libraries. I first had problems with this 20 years ago, and it is still their policy on all their tools (it is part of the startup code, rather than the compiler itself, that is responsible for this clearing). I have seen a mention of this mis-feature deep within one of their compiler manuals, with a note saying that this is not standard C behaviour. Their reasoning is that clearing bss increases startup time, and means hardware watchdogs may trigger before main() starts - though there are several far better methods of solving such issues.

I think TI’s compilers should come with a warning message “Warning - TI feels it is more important that your code starts quickly than that it works correctly, and we don’t think following C standard behaviour is important.”

As for why the code works with -Og and not -Os, the most likely reason is that when you have -Og you are probably debugging and the microcontroller is not being powered off between runs. So once there is data in the bss variables that works (or appears to work), the next time you start the program you will see the same values there. But if you have been powering the card off and on again, then there will be random data in the memory.