Skip to content

Commit a445ee0

Browse files
authored
Define thread local storage conventions (#116)
1 parent 3a39a08 commit a445ee0

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

Linking.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,3 +528,49 @@ threads needs to support both of these proposals.
528528

529529
[passive_segments]: https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md#design
530530
[datacount_section]: https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md#datacount-section
531+
532+
Thread Local Storage
533+
--------------------
534+
535+
Currently, thread-local storage is only supported in the main WASM module
536+
and cannot be accessed outside of it. This corresponds to the ELF local
537+
exec TLS model.
538+
539+
Additionally, thread local storage depends on bulk memory instructions, and
540+
therefore support depends on the bulk memory proposal.
541+
542+
All thread local variables will be merged into one passive segment called
543+
`.tdata`. This section contains the starting values for all TLS variables.
544+
The thread local block of every thread will be initialized with this segment.
545+
546+
In a threaded build, the linker will create:
547+
548+
* an immutable global variable of type `i32` called `__tls_size`.
549+
Its value is the total size of the thread local block for the module,
550+
i.e. the sum of the sizes of all thread local variables plus padding.
551+
This value will be `0` if there are no thread-local variables.
552+
* a mutable global `i32` called `__tls_base`, with a `i32.const 0` initializer.
553+
* a global function called `__wasm_init_tls` with signature `(i32) -> ()`.
554+
555+
To initialize thread-local storage, a thread should do the equivalent of the
556+
following pseudo-code upon startup:
557+
558+
(if (global.get __tls_size) (then
559+
(call __wasm_init_tls (call malloc (global.get __tls_size)))))
560+
561+
`__wasm_init_tls` takes a pointer argument containing the memory block to use
562+
as the thread local storage block of the current thread. It should do nothing if
563+
there are no thread-local variables. Otherwise, the memory block will be
564+
initialized with the passive segment `.tdata` via the `memory.init` instruction.
565+
It will then set `__tls_base` to the address of the memory block passed to
566+
`__wasm_init_tls`.
567+
568+
The relocations for thread local variables shall resolve into offsets relative to
569+
the start of the TLS block. As such, adding the value of `__tls_base` yields the
570+
actual address of the variable. For example, a variable called `tls_var` would
571+
have its address computed as follows:
572+
573+
(i32.add (global.get __tls_base) (i32.const tls_var))
574+
575+
The variable can then be used as normal. Upon thread exit, the runtime should free
576+
the memory allocated for the TLS block.

0 commit comments

Comments
 (0)