Using thread local storage

Thread-local variables can be declared and defined with the TL and UL storage-mapping classes.

Thread-local variables can be declared and defined with the TL and UL storage-mapping classes. The thread-local variables are referenced using code sequences defined by the AIX implementation.

A thread-local variable has a region handle and a region offset. In general, the __tls_get_addr() function is called to compute the address of a thread-local variable for the calling thread, given the variables region handle and offset.

Other access methods can be used in more restricted circumstances. The local-exec access method is used by the main program to reference variables also defined in the main program. The initial-exec access method is used to reference thread-local variables defined in the main program or any shared object loaded along with the main program. The local-dynamic access method is used by a module to reference thread-local variables defined in the same module.

Access to thread-local storage makes use of routines in the pthread library that have nonstandard calling conventions. These routines are __tls_get_addr() and __tls_get_mod(). The routine used in 32-bit programs is __get_tpointer(). In 64-bit programs, the current thread pointer is always contained in gpr13.

An uninitialized thread-local storage variable bar can be declared with the following statement:

       .comm bar[UL]
Similarly, a thread-local, initialized, integer variable foo can be declared with the following statements:

       .csect foo[TL]
       .long       1
Access method 32-bit code 64-bit code(if different) Comment
General-dynamic access method .tc foo[TC],foo[TL]   Variable offset
.tc .foo[TC],foo[TL]@m   Region handle
lwz 4,foo[TC](2) ld 4,foo[TC](2)  
lwz 3,.foo[TC](2) ld 3,.foo[TC](2)  
bla .__tls_get_addr   Modifies r0,r3,r4,r5,r11,lr,cr0
#r3 = &foo    
Local-dynamic access method .tc foo[TC],foo[TL]@ld   Variable offset, ld relocation specifier
.tc mh[TC],mh[TC]@ml   Module handle for the caller
lwz 3,mh[TC](2) ld 3,mh[TC](2)  
bla .__tls_get_mod   Modifies r0,r3,r4,r5,r11,lr,cr0
#r3 = &TLS for module    
lwz 4,foo[TC](2) ld 4,foo[TC](2)  
add 5,3,4   Compute &foo
.rename mh[TC], "_$TLSML"   Symbol for the module handle must have the name "_$TLSML"
Initial-exec access method .tc foo[TC],foo[TL]@ie   Variable offset, ie relocation specifier
bla __get_tpointer() # r13 contains tpointer __get_tpointer modifies r3
lwz 4,foo[TC](2) ld 4,foo[TC](2)  
add 5,3,4 add 5,4,13 Compute &foo
Local-exec access method .tc foo[TC],foo[TL]@le   Variable offset, le relocation specifier
bla __get_tpointer() # r13 contains tpointer __get_tpointer modifies r3
lwz 4,foo[TC](2) ld 4,foo[TC](2) Compute &foo
add 5,3,4 add 5,4,13  
The local-dynamic and local-exec access methods have a faster code sequence that can be used if the total size of thread-local variables is smaller than 62 KB. If the total size of the region is too large, the link-editor will patch the code by generating extra instructions, negating the benefit of using the faster code sequence.
Access method 32-bit code Comment
Local-dynamic access method .tc mh[TC],mh[TC]@ml Module handle for the caller
.rename mh[TC], "_$TLSML" Symbol for the module handle must have the name "_$TLSML"
lwz 3,mh[TC](2)  
bla .__tls_get_mod  
la 4,foo[TL]@ld(3) r4 = &foo
Local-exec access method bla .__get_tpointer Modifies r3
la 4,foo[TL]@ld(3) r4 = &foo
# OR  
lwz 5,foo[TL]@le(13) r5 = foo
Access method 64-bit code Comment
Local-dynamic access method .tc mh[TC],mh[TC]@ml Module handle for the caller
.rename mh[TC], "_$TLSML" Symbol for the module handle must have the name "_$TLSML"
ld 3,mh[TC](2)  
bla .__tls_get_mod  
la 4,foo[TL]@ld(3) r4 = &foo
Local-exec access method la 4,foo[TL]@le(13) r4 = &foo
# OR  
lwz 5,foo[TL]@le(13) r5 = foo