1 /* 2 * Copyright 2014, Paweł Dziepak, pdziepak@quarnos.org. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "elf_tls.h" 7 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include <support/TLS.h> 12 13 #include <tls.h> 14 15 #include <util/kernel_cpp.h> 16 17 18 class TLSBlock { 19 public: 20 inline TLSBlock(); 21 inline TLSBlock(void* pointer); 22 23 inline status_t Initialize(unsigned dso); 24 25 void Destroy(); 26 27 bool IsInvalid() const { return fPointer == NULL; } 28 29 void* operator+(addr_t offset) const 30 { return (void*)((addr_t)fPointer + TLS_DTV_OFFSET + offset); } 31 32 private: 33 void* fPointer; 34 }; 35 36 class Generation { 37 public: 38 inline Generation(); 39 40 unsigned Counter() const { return fCounter; } 41 unsigned Size() const { return fSize; } 42 43 void SetCounter(unsigned counter) { fCounter = counter; } 44 void SetSize(unsigned size) { fSize = size; } 45 46 private: 47 unsigned fCounter; 48 unsigned fSize; 49 }; 50 51 class DynamicThreadVector { 52 public: 53 inline DynamicThreadVector(); 54 55 void DestroyAll(); 56 57 inline TLSBlock& operator[](unsigned dso); 58 59 private: 60 bool _DoesExist() const { return *fVector != NULL; } 61 unsigned _Size() const 62 { return _DoesExist() 63 ? fGeneration->Size() : 0; } 64 65 unsigned _Generation() const; 66 67 status_t _ResizeVector(unsigned minimumSize); 68 69 TLSBlock** fVector; 70 Generation* fGeneration; 71 TLSBlock fNullBlock; 72 }; 73 74 75 TLSBlockTemplates* TLSBlockTemplates::fInstance; 76 77 78 void 79 TLSBlockTemplate::SetBaseAddress(addr_t baseAddress) 80 { 81 fAddress = (void*)((addr_t)fAddress + baseAddress); 82 } 83 84 85 TLSBlock 86 TLSBlockTemplate::CreateBlock() 87 { 88 void* pointer = malloc(fMemorySize + TLS_DTV_OFFSET); 89 if (pointer == NULL) 90 return TLSBlock(); 91 memset(pointer, 0, TLS_DTV_OFFSET); 92 memcpy((char*)pointer + TLS_DTV_OFFSET, fAddress, fFileSize); 93 if (fMemorySize > fFileSize) 94 memset((char*)pointer + TLS_DTV_OFFSET + fFileSize, 0, fMemorySize - fFileSize); 95 return TLSBlock(pointer); 96 } 97 98 99 TLSBlockTemplates& 100 TLSBlockTemplates::Get() 101 { 102 if (fInstance == NULL) 103 fInstance = new TLSBlockTemplates; 104 return *fInstance; 105 } 106 107 108 unsigned 109 TLSBlockTemplates::Register(const TLSBlockTemplate& block) 110 { 111 unsigned dso; 112 113 if (!fFreeDSOs.empty()) { 114 dso = fFreeDSOs.back(); 115 fFreeDSOs.pop_back(); 116 fTemplates[dso] = block; 117 } else { 118 dso = fTemplates.size(); 119 fTemplates.push_back(block); 120 } 121 122 fTemplates[dso].SetGeneration(fGeneration); 123 return dso; 124 } 125 126 127 void 128 TLSBlockTemplates::Unregister(unsigned dso) 129 { 130 if (dso == unsigned(-1)) 131 return; 132 133 fGeneration++; 134 fFreeDSOs.push_back(dso); 135 } 136 137 138 void 139 TLSBlockTemplates::SetBaseAddress(unsigned dso, addr_t baseAddress) 140 { 141 if (dso != unsigned(-1)) 142 fTemplates[dso].SetBaseAddress(baseAddress); 143 } 144 145 146 unsigned 147 TLSBlockTemplates::GetGeneration(unsigned dso) const 148 { 149 if (dso == unsigned(-1)) 150 return fGeneration; 151 return fTemplates[dso].Generation(); 152 } 153 154 155 TLSBlock 156 TLSBlockTemplates::CreateBlock(unsigned dso) 157 { 158 return fTemplates[dso].CreateBlock(); 159 } 160 161 162 TLSBlockTemplates::TLSBlockTemplates() 163 : 164 fGeneration(0) 165 { 166 } 167 168 169 TLSBlock::TLSBlock() 170 : 171 fPointer(NULL) 172 { 173 } 174 175 176 TLSBlock::TLSBlock(void* pointer) 177 : 178 fPointer(pointer) 179 { 180 } 181 182 183 status_t 184 TLSBlock::Initialize(unsigned dso) 185 { 186 fPointer = TLSBlockTemplates::Get().CreateBlock(dso).fPointer; 187 return fPointer != NULL ? B_OK : B_NO_MEMORY; 188 } 189 190 191 void 192 TLSBlock::Destroy() 193 { 194 free(fPointer); 195 fPointer = NULL; 196 } 197 198 199 Generation::Generation() 200 : 201 fCounter(0), 202 fSize(0) 203 { 204 } 205 206 207 DynamicThreadVector::DynamicThreadVector() 208 : 209 fVector((TLSBlock**)tls_address(TLS_DYNAMIC_THREAD_VECTOR)), 210 fGeneration(NULL) 211 { 212 if (*fVector != NULL) 213 fGeneration = (Generation*)*(void**)*fVector; 214 } 215 216 217 void 218 DynamicThreadVector::DestroyAll() 219 { 220 for (unsigned i = 0; i < _Size(); i++) { 221 TLSBlock& block = (*fVector)[i + 1]; 222 if (!block.IsInvalid()) 223 block.Destroy(); 224 } 225 226 free(*fVector); 227 *fVector = NULL; 228 229 delete fGeneration; 230 } 231 232 233 TLSBlock& 234 DynamicThreadVector::operator[](unsigned dso) 235 { 236 unsigned generation = TLSBlockTemplates::Get().GetGeneration(-1); 237 if (_Generation() < generation) { 238 // We need to destroy any blocks whose DSO generation has changed 239 // to be greater than our own generation. 240 for (unsigned dsoIndex = 0; dsoIndex < _Size(); dsoIndex++) { 241 TLSBlock& block = (*fVector)[dsoIndex + 1]; 242 unsigned dsoGeneration 243 = TLSBlockTemplates::Get().GetGeneration(dsoIndex); 244 if (dsoGeneration > _Generation() && dsoGeneration <= generation) 245 block.Destroy(); 246 } 247 248 fGeneration->SetCounter(generation); 249 } 250 251 if (_Size() <= dso) { 252 status_t result = _ResizeVector(dso + 1); 253 if (result != B_OK) 254 return fNullBlock; 255 } 256 257 TLSBlock& block = (*fVector)[dso + 1]; 258 if (block.IsInvalid()) { 259 status_t result = block.Initialize(dso); 260 if (result != B_OK) 261 return fNullBlock; 262 } 263 264 return block; 265 } 266 267 268 unsigned 269 DynamicThreadVector::_Generation() const 270 { 271 if (fGeneration != NULL) 272 return fGeneration->Counter(); 273 return unsigned(-1); 274 } 275 276 277 status_t 278 DynamicThreadVector::_ResizeVector(unsigned minimumSize) 279 { 280 static const unsigned kInitialSize = 4; 281 unsigned size = std::max(minimumSize, kInitialSize); 282 unsigned oldSize = _Size(); 283 if (size <= oldSize) 284 return B_OK; 285 286 void* newVector = realloc(*fVector, (size + 1) * sizeof(TLSBlock)); 287 if (newVector == NULL) 288 return B_NO_MEMORY; 289 290 *fVector = (TLSBlock*)newVector; 291 memset(*fVector + oldSize + 1, 0, (size - oldSize) * sizeof(TLSBlock)); 292 if (fGeneration == NULL) { 293 fGeneration = new Generation; 294 if (fGeneration == NULL) 295 return B_NO_MEMORY; 296 } 297 298 *(Generation**)*fVector = fGeneration; 299 fGeneration->SetSize(size); 300 301 return B_OK; 302 } 303 304 305 void* 306 get_tls_address(unsigned dso, addr_t offset) 307 { 308 DynamicThreadVector dynamicThreadVector; 309 TLSBlock& block = dynamicThreadVector[dso]; 310 if (block.IsInvalid()) 311 return NULL; 312 return block + offset; 313 } 314 315 316 void 317 destroy_thread_tls() 318 { 319 DynamicThreadVector().DestroyAll(); 320 } 321 322