xref: /haiku/src/system/runtime_loader/elf_tls.cpp (revision 52f7c9389475e19fc21487b38064b4390eeb6fea)
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 = (uint8*)malloc(fMemorySize + TLS_DTV_OFFSET);
89 	memset((uint8*)pointer, 0, TLS_DTV_OFFSET);
90 	if (pointer == NULL)
91 		return TLSBlock();
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 		for (unsigned i = 0; i < _Size(); i++) {
239 			TLSBlock& block = (*fVector)[i + 1];
240 			unsigned dsoGeneration
241 				= TLSBlockTemplates::Get().GetGeneration(dso);
242 			if (_Generation() < dsoGeneration && dsoGeneration <= generation)
243 				block.Destroy();
244 		}
245 
246 		fGeneration->SetCounter(generation);
247 	}
248 
249 	if (_Size() <= dso) {
250 		status_t result = _ResizeVector(dso + 1);
251 		if (result != B_OK)
252 			return fNullBlock;
253 	}
254 
255 	TLSBlock& block = (*fVector)[dso + 1];
256 	if (block.IsInvalid()) {
257 		status_t result = block.Initialize(dso);
258 		if (result != B_OK)
259 			return fNullBlock;
260 	};
261 
262 	return block;
263 }
264 
265 
266 unsigned
267 DynamicThreadVector::_Generation() const
268 {
269 	if (fGeneration != NULL)
270 		return fGeneration->Counter();
271 	return unsigned(-1);
272 }
273 
274 
275 status_t
276 DynamicThreadVector::_ResizeVector(unsigned minimumSize)
277 {
278 	static const unsigned kInitialSize = 4;
279 	unsigned size = std::max(minimumSize, kInitialSize);
280 	unsigned oldSize = _Size();
281 	if (size <= oldSize)
282 		return B_OK;
283 
284 	void* newVector = realloc(*fVector, (size + 1) * sizeof(TLSBlock));
285 	if (newVector == NULL)
286 		return B_NO_MEMORY;
287 
288 	*fVector = (TLSBlock*)newVector;
289 	memset(*fVector + oldSize + 1, 0, (size - oldSize) * sizeof(TLSBlock));
290 	if (fGeneration == NULL) {
291 		fGeneration = new Generation;
292 		if (fGeneration == NULL)
293 			return B_NO_MEMORY;
294 	}
295 
296 	*(Generation**)*fVector = fGeneration;
297 	fGeneration->SetSize(size);
298 
299 	return B_OK;
300 }
301 
302 
303 void*
304 get_tls_address(unsigned dso, addr_t offset)
305 {
306 	DynamicThreadVector dynamicThreadVector;
307 	TLSBlock& block = dynamicThreadVector[dso];
308 	if (block.IsInvalid())
309 		return NULL;
310 	return block + offset;
311 }
312 
313 
314 void
315 destroy_thread_tls()
316 {
317 	DynamicThreadVector().DestroyAll();
318 }
319 
320