1# Thread Local Storage in Picolibc 2Copyright © 2019 Keith Packard 3 4The standard C library API includes many functions that use persistent 5state held by the library not the application. One obvious example is 6'errno', a global variable originall designed to hold error status 7from the Unix kernel, but which was co-opted by libc to provide 8additional error status values from the library itself. There are 9numerous other examples of this kind of state. 10 11To permit multiple threads sharing a single address space to use the 12library without conflicting over this data, each thread needs a 13private copy of data that it uses. Newlib did this by creating a 14global structure holding all thread-specific values and then defining 15an API for the library to get the global structure for the current 16thread. 17 18Picolibc does this by using the built-in thread-local-storage 19mechanisms in the toolchain. This has several benefits: 20 21 1) Source code is simpler as thread-local variables are 22 accessed directly by name. 23 24 2) Thread local storage contains only values used by the 25 application. 26 27 3) Generated code is smaller and faster. 28 29## TLS model used by Picolibc 30 31Picolibc is normally compiled with -ftls-model=local-exec. The selected 32model is included in the .specs file so applications should not 33include -ftls-model in their compile commands. 34 35Local-exec defines a single block of storage for all TLS 36variables. Each TLS variable is assigned an offset within this block 37and those values are placed in the binary during relocation. 38 39## Initial TLS block 40 41The sample Picolibc linker script (picolibc.ld) allocates RAM for an 42initial TLS block and arranges for it to be initialized as a part of 43the normal data/bss initialization process for the application. 44 45| flash | symbol | 46| ----- | ------ | 47| code | | 48| rodata | | 49| data initializers | __data_source | 50| TLS data initializers | __tdata_source | 51 52| RAM | symbol | 53| ---- | ------ | 54| data | __data_start | 55| TLS data | __tls_base | 56| | __data_end | 57| | __tdata_size = . - __tls_base | 58| TLS bss | __bss_start | 59| | __tbss_size = . - __bss_start | 60| | __tls_size = . - __tls_base | 61| bss | | 62| | __bss_end 63 64The crt0 code copies __data_end - __data_start bytes from _data_source 65to _data_start. This initializes the regular data segment *and* the 66initial TLS data segment. Then, it clears memory from __bss_start to 67__bss_end, initializing the TLS bss segment *and* the regular bss 68segment. Finally, it sets the architecture-specific TLS data pointer 69to __tls_base. Once that is set, access to TLS variables will 70reference this initial TLS block. 71 72## Creating more TLS blocks 73 74If the application is multi-threaded and wants to allow these threads 75to have separate TLS data, it may allocate memory for additional TLS 76blocks: 77 78 1) Allocate a block of size __tls_size 79 2) Copy __tdata_size bytes from __tdata_source to the new block to 80 set the initial TLS values. 81 3) Clear __tbss_size bytes starting _tdata_size bytes into the new 82 block 83 4) Set the TLS pointer as necessary 84 85## Picolibc APIs related to TLS 86 87Picolib provides a couple of helper APIs for TLS: 88 89* _set_tls 90``` 91void 92_set_tls(void *tls); 93``` 94This is an architecture-specific function which sets the TLS 95block pointer for the processor to `tls`. 96 97* _init_tls 98``` 99void 100_init_tls(void *tls); 101``` 102This function initializes the specified TLS block, copying values 103into the initialized data portion and clearing values in the 104uninitialized data portion. 105 106Picolib also provides architecture-specific internal GCC APIs as 107necessary, for example, __aeabi_read_tp for ARM processors. 108