xref: /haiku/src/system/runtime_loader/elf_tls.cpp (revision d3b1caa62d83444c7c95a73cdc2094d2087fb818)
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