|
70 | 70 | // compiled to a function call! The module ID and the offset are |
71 | 71 | // usually stored to GOT as two consecutive words. |
72 | 72 | // |
73 | | -// The last access method provides the most generic, so the compiler emits |
74 | | -// such code by default. But that's the most expensive one, so the linker |
| 73 | +// The last access method is the most generic, so the compiler emits such |
| 74 | +// code by default. But that's the most expensive one, so the linker |
75 | 75 | // rewrites instructions if possible so that 3) is relaxed to 2) or even |
76 | 76 | // to 1). |
77 | 77 | // |
| 78 | +// 1) is often called the Local Exec access model. 2) is Initial Exec, and |
| 79 | +// 3) is called General Dynamic. |
| 80 | +// |
78 | 81 | // There's also a trick that the compiler can use if it knows two TLVs are |
79 | 82 | // in the same ELF file (usually in the same file as the code is). In this |
80 | 83 | // case, we can call __tls_get_addr() only once with a module ID and the |
81 | 84 | // offset 0 to obtain the base address of the ELF file's TLS block. |
82 | 85 | // The base address obtained this way is sometimes called Dynamic Thread |
83 | 86 | // Pointer or DTP. We can then compute TLVs' addresses by adding their |
84 | | -// DTP-relative addresses to DTP. |
| 87 | +// DTP-relative addresses to DTP. This access model is called the Local |
| 88 | +// Dynamic. |
| 89 | +// |
| 90 | +// |
| 91 | +// === TLS Descriptor access model === |
| 92 | +// |
| 93 | +// As described above, there are arguably too many different TLS access |
| 94 | +// models from the most generic one you can use in any ELF file to the |
| 95 | +// most efficient one you can use only in the main executable. Compiling |
| 96 | +// source code with an appropriate TLS access model is bothersome. |
| 97 | +// To solve the problem, a new TLS access model was proposed. That is |
| 98 | +// called the TLS Descriptor (TLSDESC) model. |
| 99 | +// |
| 100 | +// For a TLV compiled with TLSDESC, we allocate two consecutive GOT slots |
| 101 | +// and create a TLSDESC dynamic relocation for them. The dynamic linker |
| 102 | +// sets a function pointer to the first GOT slot and its argument to the |
| 103 | +// second slot. |
| 104 | +// |
| 105 | +// To access the TLV, we call the function pointer with the argument we |
| 106 | +// read from the second GOT slot. The function returns the TLV's |
| 107 | +// TP-relative address. |
| 108 | +// |
| 109 | +// The runtime chooses the best access method depending on the situation |
| 110 | +// and sets a pointer to the most efficient code to the first GOT slot. |
| 111 | +// For example, if a TLV's TP-relative address is known at process startup |
| 112 | +// time, the runtime sets that address to the second GOT slot and set a |
| 113 | +// function that just returns its argument to the first GOT slot. |
| 114 | +// |
| 115 | +// With TLSDECS, the compiler can always emit the same code for TLVs |
| 116 | +// without sacrificing runtime performance. |
| 117 | +// |
| 118 | +// TLSDESC is better than the traditional, non-TLSDESC TLS access models. |
| 119 | +// It's the default on ARM64, but on other targets, TLSDESC is |
| 120 | +// unfortunately either optional or even not supported at all. So we still |
| 121 | +// need to support both the traditional TLS models and the TLSDESC model. |
85 | 122 |
|
86 | 123 | #include "mold.h" |
87 | 124 |
|
|
0 commit comments