Nios® II Processor Reference Guide

ID 683836
Date 8/28/2023
Document Table of Contents Thread-Local Storage

The Nios® II processor uses the Variant I model for thread-local storage.

The end of the thread control block (TCB) is located 0x7000 bytes before the thread pointer. The TCB is eight bytes long. The first word is the dynamic thread pointer (DTV) pointer and the second word is reserved. Each module’s dynamic thread pointer is biased by 0x8000 (when retrieved using __tls_get_addr). The thread library can store additional private information before the TCB.

In the GNU Linux toolchain, the GOT pointer (_gp_got) is always kept in r22, and the thread pointer is always kept in r23.

In the following examples, any registers can be used, except that the argument to __tls_get_addr is always passed in r4 and its return value is always returned in r2. Calls to __tls_get_addr must use the normal position-independent code (PIC) calling convention in PIC code; these sequences are for example only, and the compiler might generate different sequences. No linker relaxations are defined.

General Dynamic Model

addi r4, r22, %tls_gd(x)         # R_NIOS2_TLS_GD16 x
call __tls_get_addr              # R_NIOS2_CALL26 __tls_get_addr
# Address of x in r2

In the general dynamic model, a two-word GOT slot is allocated for x, as shown in "GOT Slot for General Dynamic Model" example.

GOT Slot for General Dynamic Model

GOT[n]                R_NIOS2_TLS_DTPMOD x
GOT[n+1]              R_NIOS2_TLS_DTPREL x

 Local Dynamic Model

addi r4, r22, %tls_ldm(x)             # R_NIOS2_TLS_LDM16 x
call __tls_get_addr                   # R_NIOS2_CALL26 __tls_get_addr
addi r5, r2, %tls_ldo(x)              # R_NIOS2_TLS_LDO16 x
# Address of x in r5
ldw r6, %tls_ldo(x2)(r2)              # R_NIOS2_TLS_LDO16 x2
# Value of x2 in r6

One 2-word GOT slot is allocated for all R_NIOS2_TLS_LDM16 operations in the linked object. Any thread-local symbol in this object can be used, as shown in "GOT Slot with Thread-Local Storage" example.

GOT Slot with Thread-Local Storage

GOT[n]          R_NIOS2_TLS_DTPMOD x
GOT[n+1]        0

Initial Exec Model

ldw       r4, %tls_ie(x)(r22)       # R_NIOS2_TLS_IE16 x
add       r4, r23, r4
# Address of x in r4

A single GOT slot is allocated to hold the offset of x from the thread pointer, as shown in "GOT SLot for Initial Exec Model" example.

GOT Slot for Initial Exec Model

GOT[n]          R_NIOS2_TLS_TPREL x

Local Exec Model

addi       r4, r23, %tls_le(x)       # R_NIOS2_TLS_LE16 x
# Address of x in r4

There is no GOT slot associated with the local exec model.

Debug information uses the GNU extension DW_OP_GNU_push_tls_address.

Debug Information

.byte 0x03                # DW_OP_addr
.word %tls_ldo(x)         # R_NIOS2_TLS_DTPREL x
.byte 0xe0                # DW_OP_GNU_push_tls_address