1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20: #include <assert.h>
21: #include <errno.h>
22: #include <libintl.h>
23: #include <signal.h>
24: #include <stdlib.h>
25: #include <unistd.h>
26: #include <sys/param.h>
27:
28: #include <tls.h>
29: #include <dl-tls.h>
30: #include <ldsodefs.h>
31:
32:
33:
34: #define TLS_STATIC_SURPLUS 64 + DL_NNS * 100
35:
36:
37: #define TLS_DTV_UNALLOCATED ((void *) -1l)
38:
39:
40:
41: #ifdef SHARED
42: static void
43: __attribute__ ((__noreturn__))
44: oom (void)
45: {
46: _dl_fatal_printf ("cannot allocate memory for thread-local data: ABORT\n");
47: }
48: #endif
49:
50:
51: size_t
52: internal_function
53: _dl_next_tls_modid (void)
54: {
55: size_t result;
56:
57: if (__builtin_expect (GL(dl_tls_dtv_gaps), false))
58: {
59: size_t disp = 0;
60: struct dtv_slotinfo_list *runp = GL(dl_tls_dtv_slotinfo_list);
61:
62:
63:
64:
65:
66:
67:
68:
69: result = GL(dl_tls_static_nelem) + 1;
70: if (result <= GL(dl_tls_max_dtv_idx))
71: do
72: {
73: while (result - disp < runp->len)
74: {
75: if (runp->slotinfo[result - disp].map == NULL)
76: break;
77:
78: ++result;
79: assert (result <= GL(dl_tls_max_dtv_idx) + 1);
80: }
81:
82: if (result - disp < runp->len)
83: break;
84:
85: disp += runp->len;
86: }
87: while ((runp = runp->next) != NULL);
88:
89: if (result > GL(dl_tls_max_dtv_idx))
90: {
91:
92:
93: assert (result == GL(dl_tls_max_dtv_idx) + 1);
94:
95: GL(dl_tls_dtv_gaps) = false;
96:
97: goto nogaps;
98: }
99: }
100: else
101: {
102:
103: nogaps:
104:
105: result = ++GL(dl_tls_max_dtv_idx);
106: }
107:
108: return result;
109: }
110:
111:
112: #ifdef SHARED
113: void
114: internal_function
115: _dl_determine_tlsoffset (void)
116: {
117: size_t max_align = TLS_TCB_ALIGN;
118: size_t freetop = 0;
119: size_t freebottom = 0;
120:
121:
122: assert (GL(dl_tls_dtv_slotinfo_list) != NULL);
123:
124:
125: assert (GL(dl_tls_dtv_slotinfo_list)->next == NULL);
126:
127: struct dtv_slotinfo *slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157: #if TLS_TCB_AT_TP
158:
159: size_t offset = 0;
160:
161: for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
162: {
163: assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
164:
165: size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset
166: & (slotinfo[cnt].map->l_tls_align - 1));
167: size_t off;
168: max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align);
169:
170: if (freebottom - freetop >= slotinfo[cnt].map->l_tls_blocksize)
171: {
172: off = roundup (freetop + slotinfo[cnt].map->l_tls_blocksize
173: - firstbyte, slotinfo[cnt].map->l_tls_align)
174: + firstbyte;
175: if (off <= freebottom)
176: {
177: freetop = off;
178:
179:
180:
181: slotinfo[cnt].map->l_tls_offset = off;
182: continue;
183: }
184: }
185:
186: off = roundup (offset + slotinfo[cnt].map->l_tls_blocksize - firstbyte,
187: slotinfo[cnt].map->l_tls_align) + firstbyte;
188: if (off > offset + slotinfo[cnt].map->l_tls_blocksize
189: + (freebottom - freetop))
190: {
191: freetop = offset;
192: freebottom = off - slotinfo[cnt].map->l_tls_blocksize;
193: }
194: offset = off;
195:
196:
197:
198: slotinfo[cnt].map->l_tls_offset = off;
199: }
200:
201: GL(dl_tls_static_used) = offset;
202: GL(dl_tls_static_size) = (roundup (offset + TLS_STATIC_SURPLUS, max_align)
203: + TLS_TCB_SIZE);
204: #elif TLS_DTV_AT_TP
205:
206: size_t offset = TLS_TCB_SIZE;
207:
208: for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
209: {
210: assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
211:
212: size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset
213: & (slotinfo[cnt].map->l_tls_align - 1));
214: size_t off;
215: max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align);
216:
217: if (slotinfo[cnt].map->l_tls_blocksize <= freetop - freebottom)
218: {
219: off = roundup (freebottom, slotinfo[cnt].map->l_tls_align);
220: if (off - freebottom < firstbyte)
221: off += slotinfo[cnt].map->l_tls_align;
222: if (off + slotinfo[cnt].map->l_tls_blocksize - firstbyte <= freetop)
223: {
224: slotinfo[cnt].map->l_tls_offset = off - firstbyte;
225: freebottom = (off + slotinfo[cnt].map->l_tls_blocksize
226: - firstbyte);
227: continue;
228: }
229: }
230:
231: off = roundup (offset, slotinfo[cnt].map->l_tls_align);
232: if (off - offset < firstbyte)
233: off += slotinfo[cnt].map->l_tls_align;
234:
235: slotinfo[cnt].map->l_tls_offset = off - firstbyte;
236: if (off - firstbyte - offset > freetop - freebottom)
237: {
238: freebottom = offset;
239: freetop = off - firstbyte;
240: }
241:
242: offset = off + slotinfo[cnt].map->l_tls_blocksize - firstbyte;
243: }
244:
245: GL(dl_tls_static_used) = offset;
246: GL(dl_tls_static_size) = roundup (offset + TLS_STATIC_SURPLUS,
247: TLS_TCB_ALIGN);
248: #else
249: # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
250: #endif
251:
252:
253: GL(dl_tls_static_align) = max_align;
254: }
255:
256:
257:
258:
259:
260: int
261: internal_function
262: _dl_tls_setup (void)
263: {
264: assert (GL(dl_tls_dtv_slotinfo_list) == NULL);
265: assert (GL(dl_tls_max_dtv_idx) == 0);
266:
267: const size_t nelem = 2 + TLS_SLOTINFO_SURPLUS;
268:
269: GL(dl_tls_dtv_slotinfo_list)
270: = calloc (1, (sizeof (struct dtv_slotinfo_list)
271: + nelem * sizeof (struct dtv_slotinfo)));
272: if (GL(dl_tls_dtv_slotinfo_list) == NULL)
273: return -1;
274:
275: GL(dl_tls_dtv_slotinfo_list)->len = nelem;
276:
277:
278:
279: GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx) = 1;
280:
281:
282: _dl_determine_tlsoffset ();
283:
284: return 0;
285: }
286: rtld_hidden_def (_dl_tls_setup)
287: #endif
288:
289: static void *
290: internal_function
291: allocate_dtv (void *result)
292: {
293: dtv_t *dtv;
294: size_t dtv_length;
295:
296:
297:
298:
299: dtv_length = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
300: dtv = calloc (dtv_length + 2, sizeof (dtv_t));
301: if (dtv != NULL)
302: {
303:
304: dtv[0].counter = dtv_length;
305:
306:
307:
308:
309:
310: INSTALL_DTV (result, dtv);
311: }
312: else
313: result = NULL;
314:
315: return result;
316: }
317:
318:
319:
320: void
321: internal_function
322: _dl_get_tls_static_info (size_t *sizep, size_t *alignp)
323: {
324: *sizep = GL(dl_tls_static_size);
325: *alignp = GL(dl_tls_static_align);
326: }
327:
328:
329: void *
330: internal_function
331: _dl_allocate_tls_storage (void)
332: {
333: void *result;
334: size_t size = GL(dl_tls_static_size);
335:
336: #if TLS_DTV_AT_TP
337:
338:
339:
340: size += (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1)
341: & ~(GL(dl_tls_static_align) - 1);
342: #endif
343:
344:
345: result = __libc_memalign (GL(dl_tls_static_align), size);
346: if (__builtin_expect (result != NULL, 1))
347: {
348:
349: void *allocated = result;
350:
351: #if TLS_TCB_AT_TP
352:
353: result = (char *) result + size - TLS_TCB_SIZE;
354:
355:
356:
357: memset (result, '\0', TLS_TCB_SIZE);
358: #elif TLS_DTV_AT_TP
359: result = (char *) result + size - GL(dl_tls_static_size);
360:
361:
362:
363:
364: memset ((char *) result - TLS_PRE_TCB_SIZE, '\0',
365: TLS_PRE_TCB_SIZE + TLS_TCB_SIZE);
366: #endif
367:
368: result = allocate_dtv (result);
369: if (result == NULL)
370: free (allocated);
371: }
372:
373: return result;
374: }
375:
376:
377: void *
378: internal_function
379: _dl_allocate_tls_init (void *result)
380: {
381: if (result == NULL)
382:
383: return NULL;
384:
385: dtv_t *dtv = GET_DTV (result);
386: struct dtv_slotinfo_list *listp;
387: size_t total = 0;
388: size_t maxgen = 0;
389:
390:
391:
392:
393: listp = GL(dl_tls_dtv_slotinfo_list);
394: while (1)
395: {
396: size_t cnt;
397:
398: for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
399: {
400: struct link_map *map;
401: void *dest;
402:
403:
404: if (total + cnt > GL(dl_tls_max_dtv_idx))
405: break;
406:
407: map = listp->slotinfo[cnt].map;
408: if (map == NULL)
409:
410: continue;
411:
412:
413:
414: maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
415:
416: if (map->l_tls_offset == NO_TLS_OFFSET)
417: {
418:
419:
420: dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
421: dtv[map->l_tls_modid].pointer.is_static = false;
422: continue;
423: }
424:
425: assert (map->l_tls_modid == cnt);
426: assert (map->l_tls_blocksize >= map->l_tls_initimage_size);
427: #if TLS_TCB_AT_TP
428: assert ((size_t) map->l_tls_offset >= map->l_tls_blocksize);
429: dest = (char *) result - map->l_tls_offset;
430: #elif TLS_DTV_AT_TP
431: dest = (char *) result + map->l_tls_offset;
432: #else
433: # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
434: #endif
435:
436:
437: dtv[map->l_tls_modid].pointer.val = dest;
438: dtv[map->l_tls_modid].pointer.is_static = true;
439: memset (__mempcpy (dest, map->l_tls_initimage,
440: map->l_tls_initimage_size), '\0',
441: map->l_tls_blocksize - map->l_tls_initimage_size);
442: }
443:
444: total += cnt;
445: if (total >= GL(dl_tls_max_dtv_idx))
446: break;
447:
448: listp = listp->next;
449: assert (listp != NULL);
450: }
451:
452:
453: dtv[0].counter = maxgen;
454:
455: return result;
456: }
457: rtld_hidden_def (_dl_allocate_tls_init)
458:
459: void *
460: internal_function
461: _dl_allocate_tls (void *mem)
462: {
463: return _dl_allocate_tls_init (mem == NULL
464: ? _dl_allocate_tls_storage ()
465: : allocate_dtv (mem));
466: }
467: rtld_hidden_def (_dl_allocate_tls)
468:
469:
470: void
471: internal_function
472: _dl_deallocate_tls (void *tcb, bool dealloc_tcb)
473: {
474: dtv_t *dtv = GET_DTV (tcb);
475:
476:
477: for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
478: if (! dtv[1 + cnt].pointer.is_static
479: && dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
480: free (dtv[1 + cnt].pointer.val);
481:
482:
483: #ifdef SHARED
484: if (dtv != GL(dl_initial_dtv))
485: #endif
486: free (dtv - 1);
487:
488: if (dealloc_tcb)
489: {
490: #if TLS_TCB_AT_TP
491:
492: tcb -= GL(dl_tls_static_size) - TLS_TCB_SIZE;
493: #elif TLS_DTV_AT_TP
494:
495: tcb -= (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1)
496: & ~(GL(dl_tls_static_align) - 1);
497: #endif
498: free (tcb);
499: }
500: }
501: rtld_hidden_def (_dl_deallocate_tls)
502:
503:
504: #ifdef SHARED
505:
506:
507:
508:
509:
510:
511:
512: # ifndef GET_ADDR_ARGS
513: # define GET_ADDR_ARGS tls_index *ti
514: # endif
515: # ifndef GET_ADDR_MODULE
516: # define GET_ADDR_MODULE ti->ti_module
517: # endif
518: # ifndef GET_ADDR_OFFSET
519: # define GET_ADDR_OFFSET ti->ti_offset
520: # endif
521:
522:
523: static void *
524: allocate_and_init (struct link_map *map)
525: {
526: void *newp;
527:
528: newp = __libc_memalign (map->l_tls_align, map->l_tls_blocksize);
529: if (newp == NULL)
530: oom ();
531:
532:
533: memset (__mempcpy (newp, map->l_tls_initimage, map->l_tls_initimage_size),
534: '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
535:
536: return newp;
537: }
538:
539:
540: struct link_map *
541: _dl_update_slotinfo (unsigned long int req_modid)
542: {
543: struct link_map *the_map = NULL;
544: dtv_t *dtv = THREAD_DTV ();
545:
546:
547:
548:
549:
550:
551:
552:
553:
554:
555:
556:
557:
558:
559:
560:
561: unsigned long int idx = req_modid;
562: struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
563:
564: while (idx >= listp->len)
565: {
566: idx -= listp->len;
567: listp = listp->next;
568: }
569:
570: if (dtv[0].counter < listp->slotinfo[idx].gen)
571: {
572:
573:
574:
575:
576: size_t new_gen = listp->slotinfo[idx].gen;
577: size_t total = 0;
578:
579:
580: listp = GL(dl_tls_dtv_slotinfo_list);
581: do
582: {
583: for (size_t cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
584: {
585: size_t gen = listp->slotinfo[cnt].gen;
586:
587: if (gen > new_gen)
588:
589:
590:
591: continue;
592:
593:
594:
595: if (gen <= dtv[0].counter)
596: continue;
597:
598: