11 #include "vdl-linkmap.h" |
11 #include "vdl-linkmap.h" |
12 #include "vdl-file.h" |
12 #include "vdl-file.h" |
13 |
13 |
14 #define TLS_EXTRA_STATIC_ALLOC 1000 |
14 #define TLS_EXTRA_STATIC_ALLOC 1000 |
15 |
15 |
16 static unsigned long |
|
17 allocate_tls_index (void) |
|
18 { |
|
19 // This is the slowest but simplest implementation possible |
|
20 // For each possible module index, we try to find a module |
|
21 // which has been already assigned that module index. |
|
22 // If it has been already assigned, we try another one, otherwise, |
|
23 // we return it. |
|
24 unsigned long i; |
|
25 unsigned long ul_max = 0; |
|
26 ul_max = ~ul_max; |
|
27 struct VdlList *linkmap = vdl_linkmap_copy (); |
|
28 for (i = 1; i < ul_max; i++) |
|
29 { |
|
30 void **cur; |
|
31 for (cur = vdl_list_begin (linkmap); cur != vdl_list_end (linkmap); cur = vdl_list_next (cur)) |
|
32 { |
|
33 struct VdlFile *item = *cur; |
|
34 if (item->tls_initialized && |
|
35 item->has_tls && |
|
36 item->tls_index == i) |
|
37 { |
|
38 break; |
|
39 } |
|
40 } |
|
41 if (cur == vdl_list_end (linkmap)) |
|
42 { |
|
43 vdl_list_delete (linkmap); |
|
44 return i; |
|
45 } |
|
46 } |
|
47 VDL_LOG_ASSERT (0, "All tls module indexes are used up ? impossible !"); |
|
48 return 0; // quiet compiler |
|
49 } |
|
50 |
|
51 static void |
16 static void |
52 file_initialize (struct VdlFile *file) |
17 file_initialize (struct VdlFile *file) |
53 { |
18 { |
54 VDL_LOG_FUNCTION ("file=%s, initialized=%u", file->name, file->tls_initialized); |
19 VDL_LOG_FUNCTION ("file=%s, initialized=%u", file->name, file->tls_initialized); |
55 if (file->tls_initialized) |
20 if (file->tls_initialized) |
63 { |
28 { |
64 file->has_tls = 0; |
29 file->has_tls = 0; |
65 file->tls_initialized = 1; |
30 file->tls_initialized = 1; |
66 return; |
31 return; |
67 } |
32 } |
68 // note that the call below is _before tls_initialized = 1 because |
|
69 // it does matter. allocate_tls_index looks into the global g_vdl.link_map |
|
70 unsigned long tls_index = allocate_tls_index (); |
|
71 file->has_tls = 1; |
33 file->has_tls = 1; |
72 file->tls_initialized = 1; |
34 file->tls_initialized = 1; |
73 file->tls_tmpl_start = file->load_base + pt_tls->p_vaddr; |
35 file->tls_tmpl_start = file->load_base + pt_tls->p_vaddr; |
74 file->tls_tmpl_size = pt_tls->p_filesz; |
36 file->tls_tmpl_size = pt_tls->p_filesz; |
75 file->tls_init_zero_size = pt_tls->p_memsz - pt_tls->p_filesz; |
37 file->tls_init_zero_size = pt_tls->p_memsz - pt_tls->p_filesz; |
76 file->tls_align = pt_tls->p_align; |
38 file->tls_align = pt_tls->p_align; |
77 file->tls_index = tls_index; |
39 file->tls_index = g_vdl.tls_next_index; |
78 file->tls_is_static = (dt_flags & DF_STATIC_TLS)?1:0; |
40 file->tls_is_static = (dt_flags & DF_STATIC_TLS)?1:0; |
79 file->tls_tmpl_gen = g_vdl.tls_gen; |
41 file->tls_tmpl_gen = g_vdl.tls_gen; |
|
42 // XXX: the next_index increment code below is bad for many reasons. |
|
43 // Instead, we should try to reuse tls indexes that are not used anymore |
|
44 // to ensure that the tls index we use is as small as possible to ensure |
|
45 // that the dtv array is as small as possible. we should keep |
|
46 // track of all allocated indexes in a global list. |
|
47 g_vdl.tls_next_index++; |
80 g_vdl.tls_gen++; |
48 g_vdl.tls_gen++; |
81 g_vdl.tls_n_dtv++; |
49 g_vdl.tls_n_dtv++; |
82 VDL_LOG_DEBUG ("file=%s tmpl_size=%lu zero_size=%lu\n", |
50 VDL_LOG_DEBUG ("file=%s tmpl_size=%lu zero_size=%lu\n", |
83 file->name, file->tls_tmpl_size, |
51 file->name, file->tls_tmpl_size, |
84 file->tls_init_zero_size); |
52 file->tls_init_zero_size); |
124 { |
92 { |
125 // We calculate the size of the memory needed for the |
93 // We calculate the size of the memory needed for the |
126 // static and local tls model. We also initialize correctly |
94 // static and local tls model. We also initialize correctly |
127 // the tls_offset field to be able to perform relocations |
95 // the tls_offset field to be able to perform relocations |
128 // next (the TLS relocations need the tls_offset field). |
96 // next (the TLS relocations need the tls_offset field). |
129 unsigned long tcb_size = 0; |
97 unsigned long tcb_size = g_vdl.tls_static_current_size; |
130 unsigned long n_dtv = 0; |
98 unsigned long n_dtv = 0; |
131 unsigned long max_align = 1; |
99 unsigned long max_align = g_vdl.tls_static_align; |
132 void **cur; |
100 void **cur; |
133 for (cur = vdl_list_begin (list); |
101 for (cur = vdl_list_begin (list); |
134 cur != vdl_list_end (list); |
102 cur != vdl_list_end (list); |
135 cur = vdl_list_next (cur)) |
103 cur = vdl_list_next (cur)) |
136 { |
104 { |
159 bool |
127 bool |
160 vdl_tls_file_initialize (struct VdlList *files) |
128 vdl_tls_file_initialize (struct VdlList *files) |
161 { |
129 { |
162 file_list_initialize (files); |
130 file_list_initialize (files); |
163 struct static_tls static_tls = initialize_static_tls (files); |
131 struct static_tls static_tls = initialize_static_tls (files); |
164 long new_size = vdl_utils_align_up (g_vdl.tls_static_current_size + static_tls.size, |
132 if (static_tls.size < g_vdl.tls_static_total_size) |
165 static_tls.align); |
133 { |
166 if (new_size < g_vdl.tls_static_total_size) |
134 g_vdl.tls_static_current_size = static_tls.size; |
167 { |
135 g_vdl.tls_static_align = static_tls.align; |
168 g_vdl.tls_static_current_size = new_size; |
|
169 return true; |
136 return true; |
170 } |
137 } |
171 return false; |
138 return false; |
172 } |
139 } |
173 |
140 |
206 g_vdl.tls_gen = 1; |
173 g_vdl.tls_gen = 1; |
207 // We gather tls information for each module. |
174 // We gather tls information for each module. |
208 file_list_initialize (list); |
175 file_list_initialize (list); |
209 // then perform initial setup of the static tls area |
176 // then perform initial setup of the static tls area |
210 struct static_tls static_tls = initialize_static_tls (list); |
177 struct static_tls static_tls = initialize_static_tls (list); |
211 g_vdl.tls_static_current_size = vdl_utils_align_up (static_tls.size, static_tls.align); |
178 g_vdl.tls_static_current_size = static_tls.size; |
212 g_vdl.tls_static_total_size = vdl_utils_align_up (g_vdl.tls_static_current_size + TLS_EXTRA_STATIC_ALLOC, |
179 g_vdl.tls_static_total_size = vdl_utils_align_up (g_vdl.tls_static_current_size + TLS_EXTRA_STATIC_ALLOC, |
213 static_tls.align); |
180 static_tls.align); |
214 g_vdl.tls_static_align = static_tls.align; |
181 g_vdl.tls_static_align = static_tls.align; |
215 g_vdl.tls_tcb_created = false; |
|
216 } |
182 } |
217 |
183 |
218 unsigned long |
184 unsigned long |
219 vdl_tls_tcb_allocate (void) |
185 vdl_tls_tcb_allocate (void) |
220 { |
186 { |
221 // we allocate continuous memory for the set of tls blocks + libpthread TCB |
187 // we allocate continuous memory for the set of tls blocks + libpthread TCB |
222 unsigned long tcb_size = g_vdl.tls_static_total_size; |
188 unsigned long tcb_size = g_vdl.tls_static_total_size; |
223 g_vdl.tls_tcb_created = true; |
|
224 unsigned long total_size = tcb_size + CONFIG_TCB_SIZE; // specific to variant II |
189 unsigned long total_size = tcb_size + CONFIG_TCB_SIZE; // specific to variant II |
225 unsigned long buffer = (unsigned long) vdl_alloc_malloc (total_size); |
190 unsigned long buffer = (unsigned long) vdl_alloc_malloc (total_size); |
226 vdl_memset ((void*)buffer, 0, total_size); |
191 vdl_memset ((void*)buffer, 0, total_size); |
227 unsigned long tcb = buffer + tcb_size; |
192 unsigned long tcb = buffer + tcb_size; |
228 // complete setup of TCB |
193 // complete setup of TCB |
359 // extract the dtv from it |
324 // extract the dtv from it |
360 struct dtv_t *dtv; |
325 struct dtv_t *dtv; |
361 vdl_memcpy (&dtv, (void*)(tp+CONFIG_TCB_DTV_OFFSET), sizeof (dtv)); |
326 vdl_memcpy (&dtv, (void*)(tp+CONFIG_TCB_DTV_OFFSET), sizeof (dtv)); |
362 return dtv; |
327 return dtv; |
363 } |
328 } |
364 static void |
329 void |
365 update_dtv (void) |
330 vdl_tls_dtv_update (void) |
366 { |
331 { |
367 VDL_LOG_FUNCTION (""); |
332 VDL_LOG_FUNCTION (""); |
368 unsigned long tp = machine_thread_pointer_get (); |
333 unsigned long tp = machine_thread_pointer_get (); |
369 struct dtv_t *dtv = get_current_dtv (); |
334 struct dtv_t *dtv = get_current_dtv (); |
370 unsigned long dtv_size = dtv[-1].value; |
335 unsigned long dtv_size = dtv[-1].value; |
371 VDL_LOG_ASSERT (dtv[0].gen != g_vdl.tls_gen, |
336 if (dtv[0].gen == g_vdl.tls_gen) |
372 "dtv is not up-to-date"); |
337 { |
|
338 return; |
|
339 } |
373 |
340 |
374 // first, we update the currently-available entries of the dtv. |
341 // first, we update the currently-available entries of the dtv. |
375 { |
342 { |
376 unsigned long module; |
343 unsigned long module; |
377 for (module = 1; module <= dtv_size; module++) |
344 for (module = 1; module <= dtv_size; module++) |
440 // the module has been loaded and then unloaded before |
407 // the module has been loaded and then unloaded before |
441 // we updated our dtv so, well, |
408 // we updated our dtv so, well, |
442 // nothing to do here, just skip this empty entry |
409 // nothing to do here, just skip this empty entry |
443 continue; |
410 continue; |
444 } |
411 } |
445 VDL_LOG_ASSERT (!file->tls_is_static, "tls modules with static tls blocks should never" |
412 if (file->tls_is_static) |
446 "be initialized here"); |
413 { |
|
414 signed long tcb = machine_thread_pointer_get (); |
|
415 signed long dtvi = tcb + file->tls_offset; |
|
416 new_dtv[file->tls_index].value = dtvi; |
|
417 new_dtv[file->tls_index].is_static = 1; |
|
418 new_dtv[file->tls_index].gen = file->tls_tmpl_gen; |
|
419 // copy the template in the module tls block |
|
420 vdl_memcpy ((void*)dtvi, (void*)file->tls_tmpl_start, file->tls_tmpl_size); |
|
421 vdl_memset ((void*)(dtvi + file->tls_tmpl_size), 0, file->tls_init_zero_size); |
|
422 } |
447 } |
423 } |
448 // now that the dtv is updated, update the generation |
424 // now that the dtv is updated, update the generation |
449 new_dtv[0].gen = g_vdl.tls_gen; |
425 new_dtv[0].gen = g_vdl.tls_gen; |
450 // finally, clear the old dtv |
426 // finally, clear the old dtv |
451 vdl_alloc_free (&dtv[-1]); |
427 vdl_alloc_free (&dtv[-1]); |
492 dtv[module].is_static = 0; |
468 dtv[module].is_static = 0; |
493 // and return the requested value |
469 // and return the requested value |
494 return dtv[module].value + offset; |
470 return dtv[module].value + offset; |
495 } |
471 } |
496 // we know for sure that the dtv is _not_ uptodate now |
472 // we know for sure that the dtv is _not_ uptodate now |
497 update_dtv (); |
473 vdl_tls_dtv_update (); |
498 |
474 |
499 // now that the dtv is supposed to be uptodate, attempt to make |
475 // now that the dtv is supposed to be uptodate, attempt to make |
500 // the request again |
476 // the request again |
501 return vdl_tls_get_addr_slow (module, offset); |
477 return vdl_tls_get_addr_slow (module, offset); |
502 } |
478 } |