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