Each TLS reference follows one of the following access models. These models are listed from the most general, but least optimized, to the fastest, but most restrictive.
This model allows reference of all TLS variables, from either a shared object or a dynamic executable. This model also supports the deferred allocation of a TLS block when it is first referenced from a specific thread.
This model is a optimization of the GD model. If the compiler determines that a variable is bound locally, or protected, within the dynamic object being built, it instructs the link-editor to statically bind the dynamic tlsoffset and use this model. This provides a performance benefit over the GD model. Only one call to tls_get_addr() is required per function, to determine the address of dtv0,m. The dynamic TLS offset, bound at link-edit time, is added to the dtv0,m address for each reference.
This model can only reference TLS variables which are available as part of the initial static TLS template. This template is composed of all TLS blocks available at process startup. In this model, the thread pointer-relative offset for a given variable x is stored in the global offset table entry for x. This model can not reference TLS variables from shared libraries loaded after initial process startup, such as via lazy loading, filters, or dlopen(3DL). This model can not access TLS blocks which use deferred allocation.
This model can only reference TLS variables which are part of the TLS block of the dynamic executable itself. The link-editor calculates the thread pointer-relative offsets statically, without the need for dynamic relocations, or the extra reference to the global offset table. This model can not be used to reference variables outside of the dynamic executable.
The link-editor can transition code from the more general access models to the more optimized models, if it is determined appropriate to do so. This transitioning is achievable through the use of unique TLS relocations. These relocations, not only request updates be performed, but identify which TLS access model is being used.
Knowing the TLS access model, and the type of object being created, allows the link-editor to perform translations. For example, if a relocatable object using the GD access model is being linked into a dynamic executable, the link-editor can transition the references using the IE or LE access models, as appropriate. The relocations required for the model are then performed.
The following diagram illustrates the different access models, and when one model can be transitioned from one to the other.
On SPARC, the following code sequence models are available for accessing thread-local variables.
This code sequence is the most general, and can be included in both shared objects and dynamic executables. This code sequence can also reference an external TLS variable in either a shared object or dynamic executable.
Table 8–2 SPARC: 32-bit and 64-bit General Dynamic Thread-Local Variable Access Codes
Outstanding Relocations: 32-bit |
Symbol |
|
---|---|---|
GOT[n] GOT[n + 1] |
R_SPARC_TLS_DTPMOD32 R_SPARC_TLS_DTPOFF32 |
x x |
Outstanding Relocations: 64-bit |
Symbol |
|
---|---|---|
GOT[n] GOT[n + 1] |
R_SPARC_TLS_DTPMOD64 R_SPARC_TLS_DTPOFF64 |
x x |
The sethi, and add instructions generate R_SPARC_TLS_GD_HI22 and R_SPARC_TLS_GD_LO10 relocations respectively. These relocations instruct 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_SPARC_TLS_DTPMOD32 and R_SPARC_TLS_DPTOFF32 relocations against the GOT for processing by the runtime linker.
The add instruction causes the generation of the R_SPARC_TLS_GD_ADD relocation. This relocation is used only if the GD code sequence is changed to another sequence by the link-editor.
The call instruction generates the R_SPARC_TLS_GD_CALL relocation. This relocation 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 add instruction must appear before the call instruction. It cannot be placed into the delay slot for the call. This is required as the code-transformations that can occur later require a known order.
The register used as the GOT-pointer for the add instruction tagged by the R_SPARC_TLS_GD_ADD relocation, must be the first register in the add instruction. This permits the link-editor to identify the GOT-pointer register during a code transformation.
This code sequence can be used in either a shared object or dynamic executable. This sequence is used when referencing a TLS variable bound within 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 referenced via the LD code sequence.
Table 8–3 SPARC: 32-bit and 64-bit Local Dynamic Thread-Local Variable Access Codes
Outstanding Relocations: 32-bit |
Symbol |
|
---|---|---|
GOT[n] GOT[n + 1] |
R_SPARC_TLS_DTPMOD32 <none> |
x1 |
Outstanding Relocations: 64-bit |
Symbol |
|
---|---|---|
GOT[n] GOT[n + 1] |
R_SPARC_TLS_DTPMOD64 <none> |
x1 |
The first sethi and add instructions generate R_SPARC_TLS_LDM_HI22 and R_SPARC_TLS_LDM_LO10 relocations respectively. These relocations instruct the link-editor to allocate space in the global offset table to hold a TLS_index structure for the current object. The link-editor processes this relocation by substituting the GOT-relative offset for the new GOT entry.
Since the load object index is not known until runtime, a R_SPARC_TLS_DTPMOD32 relocation is created, and the ti_tlsoffset field of the TLS_index structure is zero filled.
The second add and the call instruction are tagged with the R_SPARC_TLS_LDM_ADD and R_SPARC_TLS_LDM_CALL relocations respectively.
The following sethi and or instructions generate the R_SPARC_LDO_HIX22 and R_SPARC_TLS_LDO_LOX10 relocations, respectively. The TLS offset for each local symbol is known at link-edit time, therefore these values are filled in directly. The add instruction is tagged with the R_SPARC_TLS_LDO_ADD relocation.
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.
The register containing the TLS object address in the add instruction tagged by the R_SPARC_TLS_LDO_ADD must be the first register in the instruction sequence. This permits the link-editor to identify the register during a code transformation.
This code sequence can only be used in a dynamic executable. It can reference a TLS variable defined in either the executable or any shared libraries loaded at process startup. This model can not reference TLS variables from shared libraries loaded after process startup.
Table 8–4 SPARC: 32-bit Initial Executable Thread-Local Variable Access Codes
Outstanding Relocations |
Symbol |
|
---|---|---|
GOT[n] |
R_SPARC_TLS_TPOFF32 |
x |
The sethi and or instructions generate R_SPARC_TLS_IE_HI22 and R_SPARC_TLS_IE_LO10 relocations, respectively. These relocations instruct the link-editor to create space in the global offset table to store the static TLS offset for symbol x. A R_SPARC_TLS_TPOFF32 relocation is left outstanding against the GOT for the runtime linker to fill in with the negative static TLS offset for symbol x. The ld and the add instructions are tagged with the R_SPARC_TLS_IE_LD and R_SPARC_TLS_IE_ADD relocations respectively.
The register used as the GOT-pointer for the add instruction tagged by the R_SPARC_TLS_IE_ADD relocation must be the first register in the instruction. This permits the link-editor to identify the GOT-pointer register during a code transformation.
This sequence is identical to the SPARC 32–bit sequence, except that an ldx instruction is used to load the 64–bit address instead of an ld instruction.
Table 8–5 SPARC: 64-bit Initial Executable Thread-Local Variable Access Codes
Outstanding Relocations |
Symbol |
|
---|---|---|
GOT[n] |
R_SPARC_TLS_TPOFF64 |
x |
This code sequence can only be used from within a dynamic executable to reference a TLS variable defined within the executable. If this is the case, the static tlsoffset is known at link-edit time and no runtime relocations are required.
Table 8–6 SPARC: 32-bit and 64-bit Local Executable Thread-Local Variable Access Codes
The sethi and or instructions generate R_SPARC_TLS_LE_HIX22 and R_SPARC_TLS_LE_LOX10 relocations respectively. The link-editor binds these relocations directly to the static TLS offset for the symbol defined in the executable. No relocation processing is required at runtime.
The TLS relocations listed in the following table are defined for SPARC. Descriptions in the table use the following notation:
Allocates two contiguous entries in the global offset table to hold a TLS_index structure. This information is passed to __tls_get_addr(). The instruction referencing this entry is bound to the address of the first of the two GOT entries.
Allocates two contiguous entries in the global offset table to hold a TLS_index structure. This information is passed to __tls_get_addr(). The ti_tlsoffset field of this structure is set to 0, and the ti_moduleid is filled in at runtime. The call to __tls_get_addr() returns the starting offset of the dynamic TLS block.
Calculates the tlsoffset relative to the TLS block.
Calculates the negative tlsoffset relative to the static TLS block. This value is added to the thread-pointer to calculate the TLS address.
Calculates the object identifier of the object containing symbol S.
Name |
Value |
Field |
Calculation |
---|---|---|---|
R_SPARC_TLS_GD_HI22 |
56 |
T-simm22 |
@dtlndx(S + A) >> 10 |
R_SPARC_TLS_GD_LO10 |
57 |
T-simm13 |
@dtlndx(S + A) & 0x3ff |
R_SPARC_TLS_GD_ADD |
58 |
None |
See R_SPARC_R_SPARC_TLS_GD_ADD |
R_SPARC_TLS_GD_CALL |
59 |
V-disp30 |
See R_SPARC_R_SPARC_TLS_GD_CALL |
R_SPARC_TLS_LDM_HI22 |
60 |
T-simm22 |
@tmndx(S + A) >> 10 |
R_SPARC_TLS_LDM_LO10 |
61 |
T-simm13 |
@tmndx(S + A) & 0x3ff |
R_SPARC_TLS_LDM_ADD |
62 |
None |
See R_SPARC_R_SPARC_TLS_LDM_ADD |
R_SPARC_TLS_LDM_CALL |
63 |
V-disp30 |
See R_SPARC_R_SPARC_TLS_LDM_CALL |
R_SPARC_TLS_LDO_HIX22 |
64 |
T-simm22 |
@dtpoff(S + A) >> 10 |
R_SPARC_TLS_LDO_LOX10 |
65 |
T-simm13 |
@dtpoff(S + A) & 0x3ff |
R_SPARC_TLS_LDO_ADD |
66 |
None |
See R_SPARC_R_SPARC_TLS_LDO_ADD |
R_SPARC_TLS_IE_HI22 |
67 |
T-simm22 |
@got(@tpoff(S + A)) >> 10 |
R_SPARC_TLS_IE_LO10 |
68 |
T-simm13 |
@got(@tpoff(S + A)) & 0x3ff |
R_SPARC_TLS_IE_LD |
69 |
None |
See R_SPARC_R_SPARC_TLS_IE_LD |
R_SPARC_TLS_IE_LDX |
70 |
None |
See R_SPARC_R_SPARC_TLS_IE_LDX |
R_SPARC_TLS_IE_ADD |
71 |
None |
See R_SPARC_R_SPARC_TLS_IE_ADD |
R_SPARC_TLS_LE_HIX22 |
72 |
T-imm22 |
(@tpoff(S + A) ^0xffffffffffffffff) >> 10 |
R_SPARC_TLS_LE_LOX10 |
73 |
T-simm13 |
(@tpoff(S + A) & 0x3ff) | 0x1c00 |
R_SPARC_TLS_DTPMOD32 |
74 |
V-word32 |
@dtpmod(S + A) |
R_SPARC_TLS_DTPMOD64 |
75 |
V-word64 |
@dtpmod(S + A) |
R_SPARC_TLS_DTPOFF32 |
76 |
V-word32 |
@dtpoff(S + A) |
R_SPARC_TLS_DTPOFF64 |
77 |
V-word64 |
@dtpoff(S + A) |
R_SPARC_TLS_TPOFF32 |
78 |
V-word32 |
@tpoff(S + A) |
R_SPARC_TLS_TPOFF64 |
79 |
V-word64 |
@tpoff(S + A) |
Some relocation types have semantics beyond simple calculations:
This relocation tags the add instruction of a GD code sequence. The register used for the GOT-pointer is the first register in the sequence. The instruction tagged by this relocation comes before the call instruction tagged by the R_SPARC_TLS_GD_CALL relocation. This is used to transition between TLS models at link-edit time.
This relocation is handled as if it were a R_SPARC_WPLT30 relocation referencing the __tls_get_addr() function. This relocation is part of a GD code sequence.
This relocation tags the first add instruction of a LD code sequence. The register used for the GOT-pointer is the first register in the sequence. The instruction tagged by this relocation comes before the call instruction tagged by the R_SPARC_TLS_GD_CALL relocation. This is used to transition between TLS models at link-edit time.
This relocation is handled as if it were a R_SPARC_WPLT30 relocation referencing the __tls_get_addr() function. This relocation is part of a LD code sequence.
This relocation tags the final add instruction in a LD code sequence. The register which contains the object address computed in the initial part of the code sequence is the first register in this instruction. This permits the link-editor to identify this register for code transformations.
This relocation tags the ld instruction in the 32–bit IE code sequence. This is used to transition between TLS models at link-edit time.
This relocation tags the ldx instruction in the 64–bit IE code sequence. This is used to transition between TLS models at link-edit time.
This relocation tags the add instruction in the IE code sequence. The register that is used for the GOT-pointer is the first register in the sequence.
On x86, the following code sequence models are available for accessing TLS
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.
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
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.
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.
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 |
The TLS relocations listed in the following table are defined for x86. Descriptions in the table use the following notation:
Allocates two contiguous entries in the GOT to hold a TLS_index structure. This structure is passed to ___tls_get_addr(). The instruction referencing this entry will be bound to the first of the two GOT entries.
This relocation is handled as if it were a R_386_PLT32 relocation referencing the ___tls_get_addr() function.
Allocates two contiguous entries in the GOT to hold a TLS_index structure. This structure is passed to the ___tls_get_addr(). Theti_tlsoffset field of the TLS_index is set to 0, and the ti_moduleid is filled in at runtime. The call to ___tls_get_addr() returns the starting offset of the dynamic TLS block.
Allocates a entry in the GOT, and initializes it with the negative tlsoffset relative to the static TLS block. This is performed at runtime via the R_386_TLS_TPOFF relocation.
This expression is similar to @gotntpoff, but used in position dependent code. @gotntpoff resolves to a GOT slot address relative to the start of the GOT in the movl or addl instructions. @indntpoff resolves to the absolute GOT slot address.
Calculates the negative offset of the variable it is added to relative to the static TLS block.
Calculates the tlsoffset relative to the TLS block. The value is used as an immediate value of an addend and is not associated with a specific register.
Calculates the object identifier of the object containing symbol S.
Name |
Value |
Field |
Calculation |
---|---|---|---|
R_386_TLS_GD_PLT |
12 |
Word32 |
@tlsgdplt |
R_386_TLS_LDM_PLT |
13 |
Word32 |
@tlsldmplt |
R_386_TLS_TPOFF |
14 |
Word32 |
@ntpoff(S) |
R_386_TLS_IE |
15 |
Word32 |
@indntpoff(S) |
R_386_TLS_GOTIE |
16 |
Word32 |
@gotntpoff(S) |
R_386_TLS_LE |
17 |
Word32 |
@ntpoff(S) |
R_386_TLS_GD |
18 |
Word32 |
@tlsgd(S) |
R_386_TLS_LDM |
19 |
Word32 |
@tlsldm(S) |
R_386_TLS_LDO_32 |
32 |
Word32 |
@dtpoff(S) |
R_386_TLS_DTPMOD32 |
35 |
Word32 |
@dtpmod(S) |
R_386_TLS_DTPOFF32 |
36 |
Word32 |
@dtpoff(S) |