Skip to content

Commit 563c57e

Browse files
keith-packardKeith Packardaggarg
authored
Fix TLS and stack alignment when using picolibc (#637)
Both the TLS block and stack must be correctly aligned when using picolibc. The architecture stack alignment is represented by the portBYTE_ALIGNMENT_MASK and the TLS block alignment is provided by the Picolibc _tls_align() inline function for Picolibc version 1.8 and above. For older versions of Picolibc, we'll assume that the TLS block requires the same alignment as the stack. For downward growing stacks, this requires aligning the start of the TLS block to the maximum of the stack alignment and the TLS alignment. With this, both the TLS block and stack will now be correctly aligned. For upward growing stacks, the two areas must be aligned independently; the TLS block is aligned from the start of the stack, then the tls space is allocated, and then the stack is aligned above that. It's probably useful to know here that the linker ensures that variables within the TLS block are assigned offsets that match their alignment requirements. If the TLS block itself is correctly aligned, then everything within will also be. I have only tested the downward growing stack branch of this patch. Signed-off-by: Keith Packard <[email protected]> Co-authored-by: Keith Packard <[email protected]> Co-authored-by: Gaurav-Aggarwal-AWS <[email protected]>
1 parent ddd50d9 commit 563c57e

File tree

1 file changed

+31
-10
lines changed

1 file changed

+31
-10
lines changed

include/picolibc-freertos.h

+31-10
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,43 @@
4343

4444
#define configTLS_BLOCK_TYPE void *
4545

46+
#define picolibcTLS_SIZE ( ( portPOINTER_SIZE_TYPE ) _tls_size() )
47+
#define picolibcSTACK_ALIGNMENT_MASK ( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK )
48+
49+
#if __PICOLIBC_MAJOR__ > 1 || __PICOLIBC_MINOR__ >= 8
50+
51+
/* Picolibc 1.8 and newer have explicit alignment values provided
52+
* by the _tls_align() inline */
53+
#define picolibcTLS_ALIGNMENT_MASK ( ( portPOINTER_SIZE_TYPE ) ( _tls_align() - 1 ) )
54+
#else
55+
56+
/* For older Picolibc versions, use the general port alignment value */
57+
#define picolibcTLS_ALIGNMENT_MASK ( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK )
58+
#endif
59+
4660
/* Allocate thread local storage block off the end of the
4761
* stack. The _tls_size() function returns the size (in
4862
* bytes) of the total TLS area used by the application */
4963
#if ( portSTACK_GROWTH < 0 )
50-
#define configINIT_TLS_BLOCK( xTLSBlock, pxTopOfStack ) \
51-
do { \
52-
pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) - _tls_size() ); \
53-
xTLSBlock = pxTopOfStack; \
54-
_init_tls( xTLSBlock ); \
64+
65+
#define configINIT_TLS_BLOCK( xTLSBlock, pxTopOfStack ) \
66+
do { \
67+
pxTopOfStack = ( StackType_t * ) ( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) \
68+
- picolibcTLS_SIZE ) & ~ \
69+
configMAX( picolibcSTACK_ALIGNMENT_MASK, \
70+
picolibcTLS_ALIGNMENT_MASK ) ); \
71+
xTLSBlock = pxTopOfStack; \
72+
_init_tls( xTLSBlock ); \
5573
} while( 0 )
5674
#else /* portSTACK_GROWTH */
57-
#define configINIT_TLS_BLOCK( xTLSBlock, pxTopOfStack ) \
58-
do { \
59-
xTLSBlock = pxTopOfStack; \
60-
pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) + _tls_size() ); \
61-
_init_tls( xTLSBlock ); \
75+
#define configINIT_TLS_BLOCK( xTLSBlock, pxTopOfStack ) \
76+
do { \
77+
xTLSBlock = ( void * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack + \
78+
picolibcTLS_ALIGNMENT_MASK ) & ~picolibcTLS_ALIGNMENT_MASK ); \
79+
pxTopOfStack = ( StackType_t * ) ( ( ( ( ( portPOINTER_SIZE_TYPE ) xTLSBlock ) + \
80+
picolibcTLS_SIZE ) + picolibcSTACK_ALIGNMENT_MASK ) & \
81+
~picolibcSTACK_ALIGNMENT_MASK ); \
82+
_init_tls( xTLSBlock ); \
6283
} while( 0 )
6384
#endif /* portSTACK_GROWTH */
6485

0 commit comments

Comments
 (0)