xref: /haiku/src/system/runtime_loader/elf_tls.cpp (revision e705c841d784f0035a0ef3e9e96f6e017df16681)
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 + 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);
89 	if (pointer == NULL)
90 		return TLSBlock();
91 	memcpy(pointer, fAddress, fFileSize);
92 	if (fMemorySize > fFileSize)
93 		memset((char*)pointer + fFileSize, 0, fMemorySize - fFileSize);
94 	return TLSBlock(pointer);
95 }
96 
97 
98 TLSBlockTemplates&
99 TLSBlockTemplates::Get()
100 {
101 	if (fInstance == NULL)
102 		fInstance = new TLSBlockTemplates;
103 	return *fInstance;
104 }
105 
106 
107 unsigned
108 TLSBlockTemplates::Register(const TLSBlockTemplate& block)
109 {
110 	unsigned dso;
111 
112 	if (!fFreeDSOs.empty()) {
113 		dso = fFreeDSOs.back();
114 		fFreeDSOs.pop_back();
115 		fTemplates[dso] = block;
116 	} else {
117 		dso = fTemplates.size();
118 		fTemplates.push_back(block);
119 	}
120 
121 	fTemplates[dso].SetGeneration(fGeneration);
122 	return dso;
123 }
124 
125 
126 void
127 TLSBlockTemplates::Unregister(unsigned dso)
128 {
129 	if (dso == unsigned(-1))
130 		return;
131 
132 	fGeneration++;
133 	fFreeDSOs.push_back(dso);
134 }
135 
136 
137 void
138 TLSBlockTemplates::SetBaseAddress(unsigned dso, addr_t baseAddress)
139 {
140 	if (dso != unsigned(-1))
141 		fTemplates[dso].SetBaseAddress(baseAddress);
142 }
143 
144 
145 unsigned
146 TLSBlockTemplates::GetGeneration(unsigned dso) const
147 {
148 	if (dso == unsigned(-1))
149 		return fGeneration;
150 	return fTemplates[dso].Generation();
151 }
152 
153 
154 TLSBlock
155 TLSBlockTemplates::CreateBlock(unsigned dso)
156 {
157 	return fTemplates[dso].CreateBlock();
158 }
159 
160 
161 TLSBlockTemplates::TLSBlockTemplates()
162 	:
163 	fGeneration(0)
164 {
165 }
166 
167 
168 TLSBlock::TLSBlock()
169 	:
170 	fPointer(NULL)
171 {
172 }
173 
174 
175 TLSBlock::TLSBlock(void* pointer)
176 	:
177 	fPointer(pointer)
178 {
179 }
180 
181 
182 status_t
183 TLSBlock::Initialize(unsigned dso)
184 {
185 	fPointer = TLSBlockTemplates::Get().CreateBlock(dso).fPointer;
186 	return fPointer != NULL ? B_OK : B_NO_MEMORY;
187 }
188 
189 
190 void
191 TLSBlock::Destroy()
192 {
193 	free(fPointer);
194 	fPointer = NULL;
195 }
196 
197 
198 Generation::Generation()
199 	:
200 	fCounter(0),
201 	fSize(0)
202 {
203 }
204 
205 
206 DynamicThreadVector::DynamicThreadVector()
207 	:
208 	fVector((TLSBlock**)tls_address(TLS_DYNAMIC_THREAD_VECTOR)),
209 	fGeneration(NULL)
210 {
211 	if (*fVector != NULL)
212 		fGeneration = (Generation*)*(void**)*fVector;
213 }
214 
215 
216 void
217 DynamicThreadVector::DestroyAll()
218 {
219 	for (unsigned i = 0; i < _Size(); i++) {
220 		TLSBlock& block = (*fVector)[i + 1];
221 		if (!block.IsInvalid())
222 			block.Destroy();
223 	}
224 
225 	free(*fVector);
226 	*fVector = NULL;
227 
228 	delete fGeneration;
229 }
230 
231 
232 TLSBlock&
233 DynamicThreadVector::operator[](unsigned dso)
234 {
235 	unsigned generation = TLSBlockTemplates::Get().GetGeneration(-1);
236 	if (_Generation() < generation) {
237 		for (unsigned i = 0; i < _Size(); i++) {
238 			TLSBlock& block = (*fVector)[i + 1];
239 			unsigned dsoGeneration
240 				= TLSBlockTemplates::Get().GetGeneration(dso);
241 			if (_Generation() < dsoGeneration && dsoGeneration <= generation)
242 				block.Destroy();
243 		}
244 
245 		fGeneration->SetCounter(generation);
246 	}
247 
248 	if (_Size() <= dso) {
249 		status_t result = _ResizeVector(dso + 1);
250 		if (result != B_OK)
251 			return fNullBlock;
252 	}
253 
254 	TLSBlock& block = (*fVector)[dso + 1];
255 	if (block.IsInvalid()) {
256 		status_t result = block.Initialize(dso);
257 		if (result != B_OK)
258 			return fNullBlock;
259 	};
260 
261 	return block;
262 }
263 
264 
265 unsigned
266 DynamicThreadVector::_Generation() const
267 {
268 	if (fGeneration != NULL)
269 		return fGeneration->Counter();
270 	return unsigned(-1);
271 }
272 
273 
274 status_t
275 DynamicThreadVector::_ResizeVector(unsigned minimumSize)
276 {
277 	static const unsigned kInitialSize = 4;
278 	unsigned size = std::max(minimumSize, kInitialSize);
279 	unsigned oldSize = _Size();
280 	if (size <= oldSize)
281 		return B_OK;
282 
283 	void* newVector = realloc(*fVector, (size + 1) * sizeof(TLSBlock));
284 	if (newVector == NULL)
285 		return B_NO_MEMORY;
286 
287 	*fVector = (TLSBlock*)newVector;
288 	memset(*fVector + oldSize + 1, 0, (size - oldSize) * sizeof(TLSBlock));
289 	if (fGeneration == NULL) {
290 		fGeneration = new Generation;
291 		if (fGeneration == NULL)
292 			return B_NO_MEMORY;
293 	}
294 
295 	*(Generation**)*fVector = fGeneration;
296 	fGeneration->SetSize(size);
297 
298 	return B_OK;
299 }
300 
301 
302 void*
303 get_tls_address(unsigned dso, addr_t offset)
304 {
305 	DynamicThreadVector dynamicThreadVector;
306 	TLSBlock& block = dynamicThreadVector[dso];
307 	if (block.IsInvalid())
308 		return NULL;
309 	return block + offset;
310 }
311 
312 
313 void
314 destroy_thread_tls()
315 {
316 	DynamicThreadVector().DestroyAll();
317 }
318 
319