File: tls.md

package info (click to toggle)
picolibc 1.8.10-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 35,184 kB
  • sloc: ansic: 281,743; asm: 24,643; python: 2,282; sh: 2,237; perl: 680; pascal: 329; exp: 287; makefile: 209; cpp: 72; xml: 40
file content (107 lines) | stat: -rw-r--r-- 3,649 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# Thread Local Storage in Picolibc
Copyright © 2019 Keith Packard

The standard C library API includes many functions that use persistent
state held by the library not the application. One obvious example is
'errno', a global variable originall designed to hold error status
from the Unix kernel, but which was co-opted by libc to provide
additional error status values from the library itself. There are
numerous other examples of this kind of state.

To permit multiple threads sharing a single address space to use the
library without conflicting over this data, each thread needs a
private copy of data that it uses. Newlib did this by creating a
global structure holding all thread-specific values and then defining
an API for the library to get the global structure for the current
thread.

Picolibc does this by using the built-in thread-local-storage
mechanisms in the toolchain. This has several benefits:

 1) Source code is simpler as thread-local variables are
    accessed directly by name.

 2) Thread local storage contains only values used by the
    application.

 3) Generated code is smaller and faster.

## TLS model used by Picolibc

Picolibc is normally compiled with -ftls-model=local-exec. The selected
model is included in the .specs file so applications should not
include -ftls-model in their compile commands.

Local-exec defines a single block of storage for all TLS
variables. Each TLS variable is assigned an offset within this block
and those values are placed in the binary during relocation.

## Initial TLS block

The sample Picolibc linker script (picolibc.ld) allocates RAM for an
initial TLS block and arranges for it to be initialized as a part of
the normal data/bss initialization process for the application.

| flash | symbol |
| ----- | ------ |
| code  |        |
| rodata |       | 
| data initializers | __data_source |
| TLS data initializers | __tdata_source |

| RAM  | symbol |
| ---- | ------ |
| data | __data_start |
| TLS data | __tls_base |
|          | __data_end |
|          | __tdata_size = . - __tls_base |
| TLS bss | __bss_start |
|         | __tbss_size = . - __bss_start |
|         | __tls_size = . - __tls_base  |
| bss | |
|     | __bss_end 

The crt0 code copies __data_end - __data_start bytes from _data_source
to _data_start. This initializes the regular data segment *and* the
initial TLS data segment. Then, it clears memory from __bss_start to
__bss_end, initializing the TLS bss segment *and* the regular bss
segment. Finally, it sets the architecture-specific TLS data pointer
to __tls_base. Once that is set, access to TLS variables will
reference this initial TLS block.

## Creating more TLS blocks

If the application is multi-threaded and wants to allow these threads
to have separate TLS data, it may allocate memory for additional TLS
blocks:

 1) Allocate a block of size  __tls_size
 2) Copy __tdata_size bytes from __tdata_source to the new block to
    set the initial TLS values.
 3) Clear __tbss_size bytes starting _tdata_size bytes into the new
    block
 4) Set the TLS pointer as necessary

## Picolibc APIs related to TLS

Picolib provides a couple of helper APIs for TLS:

* _set_tls
```c
void
_set_tls(void *tls);
```
This is an architecture-specific function which sets the TLS
block pointer for the processor to `tls`.

* _init_tls
```c
void
_init_tls(void *tls);
```
This function initializes the specified TLS block, copying values
into the initialized data portion and clearing values in the
uninitialized data portion.

Picolib also provides architecture-specific internal GCC APIs as
necessary, for example, __aeabi_read_tp for ARM processors.