Linker and Libraries Guide

x86: Thread-Local Variable Access

On x86, the following code sequence models are available for accessing TLS

x86: General Dynamic (GD)

This code sequence is the most general, and can be included both in a shared objects and dynamic executables. This code sequence can reference an external TLS variable in either a shared object or dynamic executable.

Table 8–8 x86: General Dynamic Thread-Local Variable Access Codes

Code Sequence 

Initial Relocations 

Symbol 

0x00 leal  x@tlsgd(,%ebx,1),%eax
0x07 call  x@tlsgdplt  

# %eax - contains address of TLS variable
R_386_TLS_GD
R_386_TLS_GD_PLT
x
x
 

Outstanding Relocations 

Symbol 

GOT[n]
GOT[n + 1]
R_386_TLS_DTPMOD32
R_386_TLS_DTPOFF32
x

The leal instruction generates a R_386_TLS_GD relocation which instructs the link-editor to allocate space in the global offset table to hold a TLS_index structure for variable x. The link-editor processes this relocation by substituting the GOT-relative offset for the new GOT entry.

Since the load object index and TLS block index for x are not known until runtime, the link-editor places the R_386_TLS_DTPMOD32 and R_386_TLS_DTPOFF32 relocations against the GOT for processing by the runtime linker. The address of the generated GOT entry is loaded into register %eax for the call to ___tls_get_addr().

The call instruction causes the generation of the R_386_TLS_GD_PLT relocation. This instructs the link-editor to bind the call to the ___tls_get_addr() function and associates the call instruction with the GD code sequence.

The call instruction must immediately follow the leal instruction. This is a required to permit the code transformations.

x86: Local Dynamic (LD)

This code sequence can be used in either a shared object or dynamic executable. This sequence is used when referencing a TLS variable bound to the same object as the reference. Because the dynamic tlsoffset can be bound at link-edit time, only one call to ___tls_get_addr() is required per function call for all symbols which are referenced via the LD code sequence.

Table 8–9 x86: Local Dynamic Thread-Local Variable Access Codes

Code Sequence 

Initial Relocations 

Symbol 

0x00 leal  x1@tlsldm(%ebx), %eax
0x06 call  x@tlsldmplt

# %eax - contains address of TLS block of current object

0x10 leal x1@dtpoff(%eax), %edx

# %edx - contains address of local TLS variable x1

0x20 leal x2@dtpoff(%eax), %edx

# %edx - contains address of local TLS variable x2
R_386_TLS_LDM
R_386_TLS_LDM_PLT
 
 
 
R_386_TLS_LDO_32
 
 
 
R_386_TLS_LDO_32
x1
x1
 
 
 
x1
 
 
 
x2
 

Outstanding Relocations 

Symbol 

GOT[n]
GOT[n + 1]
R_386_TLS_DTPMOD32
<none>
x

The first leal instruction generates a R_386_TLS_LDM relocation that instructs the link-editor to allocate space in the global offset table to hold a TLS_index structure for the current object. The link-editor process this relocation by substituting the GOT-relative offset for the new linkage table entry.

Since the load object index is not known until runtime, aR_386_TLS_DTPMOD32 relocation is created, and the ti_tlsoffset field of the structure is zero filled. The call instruction is tagged with the R_386_TLS_LDM_PLT relocation.

The TLS offset for each local symbol is known at link-edit time so the link-editor fills these values in directly.

When a procedure references more then one local symbol, the compiler generates code to obtain the base address of the TLS block once. This base address is then used to calculate the address of each symbol without a separate library call.

x86: Initial Executable (IE)

There are two code-sequences for the IE model. One sequence is for position independent code which uses a GOT-pointer. The other sequence is for position dependent code which does not use a GOT-pointer. Both of these code sequences can only be used in a dynamic executable. These code sequences can reference a TLS variable defined in either the executable or any of the shared libraries loaded at process startup. This model can not reference TLS variables from shared libraries loaded after process startup.

Table 8–10 x86: Initial Executable, Position Independent, Thread-Local Variable Access Codes

Code Sequence 

Initial Relocations 

Symbol 

0x00 movl  %gs:0, %eax
0x06 addl  x@gotntpoff(%ebx), %eax

# %eax - contains address of TLS variable
<none>
R_386_TLS_GOTIE
 
x
 

Outstanding Relocations 

Symbol 

GOT[n]
R_386_TLS_TPOFF
x

The addl instruction generates a R_386_TLS_GOTIE relocation that instructs the link–editor to create space in the global offset table to store the static TLS offset for symbol x. A R_386_TLS_TPOFF relocation is left outstanding against the GOT table for the runtime linker to fill in with the static TLS offset for symbol x.

Table 8–11 x86: Initial Executable, Position Dependent, Thread-Local Variable Access Codes

Code Sequence 

Initial Relocations 

Symbol 

0x00 movl  %gs:0, %eax
0x06 addl  x@indntpoff, %eax

# %eax - contains address of TLS variable
<none>
R_386_TLS_IE
 
x
 

Outstanding Relocations 

Symbol 

GOT[n]
R_386_TLS_TPOFF
x

The addl instruction generates a R_386_TLS_IE relocation, that instructs the link-editor to create space in the global offset table to store the static TLS offset for symbol x. The main difference between this sequence and the position independent form, is that the instruction is bound directly to the GOT entry created, instead of via an offset off of the GOT-pointer register. A R_386_TLS_TPOFF relocation is left outstanding against the GOT for the runtime linker to fill in with the static TLS offset for symbol x.

The contents of variable x, rather then the address, can be loaded by embedding the offset directly into the memory reference as shown in the next two sequences.

Table 8–12 x86: Initial Executable, Position Independent, Dynamic Thread-Local Variable Access Codes

Code Sequence 

Initial Relocations 

Symbol 

0x00 movl  x@gotntpoff(%ebx), %eax
0x06 movl  %gs:(%eax), %eax

# %eax - contains address of TLS variable
R_386_TLS_GOTIE
<none>
x
 

Outstanding Relocations 

Symbol 

GOT[n]
R_386_TLS_TPOFF
x

Table 8–13 x86: Initial Executable, Position Independent, Thread-Local Variable Access Codes

Code Sequence 

Initial Relocations 

Symbol 

0x00 movl  x@indntpoff, %ecx
0x06 movl  %gs:(%ecx), %eax

# %eax - contains address of TLS variable
R_386_TLS_IE
<none>
x
 

Outstanding Relocations 

Symbol 

GOT[n]
R_386_TLS_TPOFF
x

In the last sequence, if the %eax register is used instead of the %ecx above, the first instruction may be either 5 or 6 bytes long.

x86: Local Executable (LE)

This code sequence can only be used from within a dynamic executable and referencing a TLS variable defined within the executable. If this is the case the static tlsoffset it known at link-edit time and no runtime relocations are required.

Table 8–14 x86: Local Executable Thread-Local Variable Access Codes

Code Sequence 

Initial Relocations 

Symbol 

0x00 movl %gs:0, %eax
0x06 leal x@ntpoff(%eax), %eax

# %eax - contains address of TLS variable
<none>
R_386_TLS_LE
 
x

The movl instruction generates aR_386_TLS_LE_32 relocation. The link-editor binds this relocation directly to the static TLS offset for the symbol defined in the executable. No processing is required at runtime.

The contents of variable x, rather then the address, can be accessed with the same relocation by using the following instruction sequence.

Table 8–15 x86: Local Executable Thread-Local Variable Access Codes

Code Sequence 

Initial Relocations 

Symbol 

0x00 movl %gs:0, %eax
0x06 movl x@ntpoff(%eax), %eax

# %eax - contains address of TLS variable
<none>
R_386_TLS_LE
 
x

If instead of computing the address of the variable we want to load from it or store in it the following sequence can be used. Note that in this case we use the x@ntpoff expression not as an immediate value, but instead as an absolute address.

Table 8–16 x86: Local Executable Thread-Local Variable Access Codes

Code Sequence 

Initial Relocations 

Symbol 

0x00 movl %gs:x@ntpoff, %eax

# %eax - contains address of TLS variable
R_386_TLS_LE
x