D763 - A title module's thread-locals are served by module id

Status: decided Date: 2026-10-08 known_by: published (the ELF thread-local storage ABI's dynamic models)

The executable's thread-locals are module 1, whose block sits below the thread pointer, where its TPOFF64 relocations reach it. The modules a title ships have their own blocks. The title's indexth module is module index + 2. Its local DTPMOD64 relocations write that id, and its DTPOFF64 relocations write their addend. A TPOFF64 in one is deferred, because its block is not below the thread pointer.

__tls_get_addr(&{module, offset}) answers the calling thread's address of the variable. For module 1 that is the thread pointer, less the executable's block size, plus the offset. For any other module it is that thread's block for the module plus the offset. The block is reserved the first time the thread asks, in its own arena at 0x6C00_0000_0000. It starts with the module's .tdata as relocation left it, and its .tbss reads as zero. An index naming no module answers null.

Why: relocation answered module 1 for every module, so the title's own libc.prx (PPSA02664) was told its variables were the executable's. Its __tls_get_addr calls answered the placeholder, which it then dereferenced.

Rejected: