johandc wrote on Thursday, October 28, 2010:
According to the new ARM Architecture Procedure Call Standard (AAPCS, 2.08, 16 october 2009) the stack pointer must be aligned to an 8 byte boundary.
In order to achieve this, it seems that FreeRTOS has a define called: portBYTE_ALIGNMENT. FreeRTOS then has a mechanism inside heap_1.c and heap_2.c that ensures that they return blocks aligned according to portBYTE_ALIGNMENT. However there is no guarantee that heap_3.c will return an 8 byte aligned block, but experience with newlib has shown that it does. So far so good. But…
Even though the stack area is allocated by malloc to a correct 8 byte address, FreeRTOS modifies the stack pointer in task.c:
pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
Subtracting 1 from the pointer now makes it aligned to only 4 bytes. And this breaks floating point compatibility with all the latest GCC compilers using the EABI. (Such as Codesourcery G++ and Yagarto).
The fix can be done either by subtracting 2 from the pointer in task.c, or as it was done for the Cortex-M3 port between version 6.0.0 to 6.0.1, an offset can be added in portMacro.h:
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters ) {
pxTopOfStack--;
....
}
This has the same effect, and it works for Cortex-M3 and also ARM7 ports. Note: All of the official ARM7 ports in /portable/gcc/arm7* are broken using the new EABI compiler and needs this fix. So far Cortex-M3 and PIC32 seems to be the only ones that are 8 byte aligned!
As shown above, also the usStackDepth is affecting the alignment of a pointer. This means that the stack depth must always be dividable with 2 in order for 8 byte alignment to work. A more secure solution would be to check the portBYTE_ALIGNMENT at runtime and subtract from the pointer until it is properly aligned.
while ((portSTACK_TYPE) pxTopOfStack % 8)
pxTopOfStack--;
This could be done in portmacro.h, but would require all ports to be modified, or the change could be made in task.c so it will always adhere to the portBYTE_ALIGNMENT before calling pxPortInitialiseStack…