]> git.saurik.com Git - apple/dyld.git/blob - src/threadLocalVariables.c
2586455ed2f6462b725b73b1a7b5a3011af114f8
[apple/dyld.git] / src / threadLocalVariables.c
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2010 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
26 #include <stdlib.h>
27 #include <stdint.h>
28 #include <string.h>
29 #include <stddef.h>
30 #include <stdio.h>
31 #include <pthread.h>
32 #include <Block.h>
33 #include <malloc/malloc.h>
34 #include <mach-o/loader.h>
35 #include <libkern/OSAtomic.h>
36
37 #include "dyld_priv.h"
38
39
40 #if __LP64__
41 typedef struct mach_header_64 macho_header;
42 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
43 typedef struct segment_command_64 macho_segment_command;
44 typedef struct section_64 macho_section;
45 #else
46 typedef struct mach_header macho_header;
47 #define LC_SEGMENT_COMMAND LC_SEGMENT
48 typedef struct segment_command macho_segment_command;
49 typedef struct section macho_section;
50 #endif
51
52 #ifndef S_THREAD_LOCAL_REGULAR
53 #define S_THREAD_LOCAL_REGULAR 0x11
54 #endif
55
56 #ifndef S_THREAD_LOCAL_ZEROFILL
57 #define S_THREAD_LOCAL_ZEROFILL 0x12
58 #endif
59
60 #ifndef S_THREAD_LOCAL_VARIABLES
61 #define S_THREAD_LOCAL_VARIABLES 0x13
62 #endif
63
64 #ifndef S_THREAD_LOCAL_VARIABLE_POINTERS
65 #define S_THREAD_LOCAL_VARIABLE_POINTERS 0x14
66 #endif
67
68 #ifndef S_THREAD_LOCAL_INIT_FUNCTION_POINTERS
69 #define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15
70 #endif
71
72 #ifndef MH_HAS_TLV_DESCRIPTORS
73 #define MH_HAS_TLV_DESCRIPTORS 0x800000
74 #endif
75
76 #if __i386__ || __x86_64__
77
78 typedef struct TLVHandler {
79 struct TLVHandler *next;
80 dyld_tlv_state_change_handler handler;
81 enum dyld_tlv_states state;
82 } TLVHandler;
83
84 // lock-free prepend-only linked list
85 static TLVHandler * volatile tlv_handlers = NULL;
86
87
88 struct TLVDescriptor
89 {
90 void* (*thunk)(struct TLVDescriptor*);
91 unsigned long key;
92 unsigned long offset;
93 };
94 typedef struct TLVDescriptor TLVDescriptor;
95
96
97 // implemented in assembly
98 extern void* tlv_get_addr(TLVDescriptor*);
99
100 struct TLVImageInfo
101 {
102 pthread_key_t key;
103 const struct mach_header* mh;
104 };
105 typedef struct TLVImageInfo TLVImageInfo;
106
107 static TLVImageInfo* tlv_live_images = NULL;
108 static unsigned int tlv_live_image_alloc_count = 0;
109 static unsigned int tlv_live_image_used_count = 0;
110 static pthread_mutex_t tlv_live_image_lock = PTHREAD_MUTEX_INITIALIZER;
111
112 static void tlv_set_key_for_image(const struct mach_header* mh, pthread_key_t key)
113 {
114 pthread_mutex_lock(&tlv_live_image_lock);
115 if ( tlv_live_image_used_count == tlv_live_image_alloc_count ) {
116 unsigned int newCount = (tlv_live_images == NULL) ? 8 : 2*tlv_live_image_alloc_count;
117 struct TLVImageInfo* newBuffer = malloc(sizeof(TLVImageInfo)*newCount);
118 if ( tlv_live_images != NULL ) {
119 memcpy(newBuffer, tlv_live_images, sizeof(TLVImageInfo)*tlv_live_image_used_count);
120 free(tlv_live_images);
121 }
122 tlv_live_images = newBuffer;
123 tlv_live_image_alloc_count = newCount;
124 }
125 tlv_live_images[tlv_live_image_used_count].key = key;
126 tlv_live_images[tlv_live_image_used_count].mh = mh;
127 ++tlv_live_image_used_count;
128 pthread_mutex_unlock(&tlv_live_image_lock);
129 }
130
131 static const struct mach_header* tlv_get_image_for_key(pthread_key_t key)
132 {
133 const struct mach_header* result = NULL;
134 pthread_mutex_lock(&tlv_live_image_lock);
135 for(unsigned int i=0; i < tlv_live_image_used_count; ++i) {
136 if ( tlv_live_images[i].key == key ) {
137 result = tlv_live_images[i].mh;
138 break;
139 }
140 }
141 pthread_mutex_unlock(&tlv_live_image_lock);
142 return result;
143 }
144
145
146 static void
147 tlv_notify(enum dyld_tlv_states state, void *buffer)
148 {
149 if (!tlv_handlers) return;
150
151 // Always use malloc_size() to ensure allocated and deallocated states
152 // send the same size. tlv_free() doesn't have anything else recorded.
153 dyld_tlv_info info = { sizeof(info), buffer, malloc_size(buffer) };
154
155 for (TLVHandler *h = tlv_handlers; h != NULL; h = h->next) {
156 if (h->state == state && h->handler) {
157 h->handler(h->state, &info);
158 }
159 }
160 }
161
162
163 // called lazily when TLV is first accessed
164 __attribute__((visibility("hidden")))
165 void* tlv_allocate_and_initialize_for_key(pthread_key_t key)
166 {
167 const struct mach_header* mh = tlv_get_image_for_key(key);
168 // first pass, find size and template
169 uint8_t* start = NULL;
170 unsigned long size;
171 intptr_t slide = 0;
172 bool slideComputed = false;
173 bool hasInitializers = false;
174 const uint32_t cmd_count = mh->ncmds;
175 const struct load_command* const cmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header));
176 const struct load_command* cmd = cmds;
177 for (uint32_t i = 0; i < cmd_count; ++i) {
178 if ( cmd->cmd == LC_SEGMENT_COMMAND) {
179 const macho_segment_command* seg = (macho_segment_command*)cmd;
180 if ( !slideComputed && (seg->filesize != 0) ) {
181 slide = (uintptr_t)mh - seg->vmaddr;
182 slideComputed = true;
183 }
184 const macho_section* const sectionsStart = (macho_section*)((char*)seg + sizeof(macho_segment_command));
185 const macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
186 for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
187 switch ( sect->flags & SECTION_TYPE ) {
188 case S_THREAD_LOCAL_INIT_FUNCTION_POINTERS:
189 hasInitializers = true;
190 break;
191 case S_THREAD_LOCAL_ZEROFILL:
192 case S_THREAD_LOCAL_REGULAR:
193 if ( start == NULL ) {
194 // first of N contiguous TLV template sections, record as if this was only section
195 start = (uint8_t*)(sect->addr + slide);
196 size = sect->size;
197 }
198 else {
199 // non-first of N contiguous TLV template sections, accumlate values
200 const uint8_t* newEnd = (uint8_t*)(sect->addr + slide + sect->size);
201 size = newEnd - start;
202 }
203 break;
204 }
205 }
206 }
207 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
208 }
209
210 // allocate buffer and fill with template
211 void* buffer = malloc(size);
212 memcpy(buffer, start, size);
213
214 // set this thread's value for key to be the new buffer.
215 pthread_setspecific(key, buffer);
216
217 // send tlv state notifications
218 tlv_notify(dyld_tlv_state_allocated, buffer);
219
220 // second pass, run initializers
221 if ( hasInitializers ) {
222 cmd = cmds;
223 for (uint32_t i = 0; i < cmd_count; ++i) {
224 if ( cmd->cmd == LC_SEGMENT_COMMAND) {
225 const macho_segment_command* seg = (macho_segment_command*)cmd;
226 const macho_section* const sectionsStart = (macho_section*)((char*)seg + sizeof(macho_segment_command));
227 const macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
228 for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
229 if ( (sect->flags & SECTION_TYPE) == S_THREAD_LOCAL_INIT_FUNCTION_POINTERS ) {
230 typedef void (*InitFunc)(void);
231 InitFunc* funcs = (InitFunc*)(sect->addr + slide);
232 const uint32_t count = sect->size / sizeof(uintptr_t);
233 for (uint32_t i=count; i > 0; --i) {
234 InitFunc func = funcs[i-1];
235 func();
236 }
237 }
238 }
239 }
240 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
241 }
242 }
243 return buffer;
244 }
245
246
247 // pthread destructor for TLV storage
248 static void
249 tlv_free(void *storage)
250 {
251 tlv_notify(dyld_tlv_state_deallocated, storage);
252 free(storage);
253 }
254
255
256 // called when image is loaded
257 static void tlv_initialize_descriptors(const struct mach_header* mh)
258 {
259 pthread_key_t key = 0;
260 intptr_t slide = 0;
261 bool slideComputed = false;
262 const uint32_t cmd_count = mh->ncmds;
263 const struct load_command* const cmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header));
264 const struct load_command* cmd = cmds;
265 for (uint32_t i = 0; i < cmd_count; ++i) {
266 if ( cmd->cmd == LC_SEGMENT_COMMAND) {
267 const macho_segment_command* seg = (macho_segment_command*)cmd;
268 if ( !slideComputed && (seg->filesize != 0) ) {
269 slide = (uintptr_t)mh - seg->vmaddr;
270 slideComputed = true;
271 }
272 const macho_section* const sectionsStart = (macho_section*)((char*)seg + sizeof(macho_segment_command));
273 const macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
274 for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
275 if ( (sect->flags & SECTION_TYPE) == S_THREAD_LOCAL_VARIABLES ) {
276 if ( sect->size != 0 ) {
277 // allocate pthread key when we first discover this image has TLVs
278 if ( key == 0 ) {
279 int result = pthread_key_create(&key, &tlv_free);
280 if ( result != 0 )
281 abort();
282 tlv_set_key_for_image(mh, key);
283 }
284 // initialize each descriptor
285 TLVDescriptor* start = (TLVDescriptor*)(sect->addr + slide);
286 TLVDescriptor* end = (TLVDescriptor*)(sect->addr + sect->size + slide);
287 for (TLVDescriptor* d=start; d < end; ++d) {
288 d->thunk = tlv_get_addr;
289 d->key = key;
290 //d->offset = d->offset; // offset unchanged
291 }
292 }
293 }
294 }
295 }
296 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
297 }
298 }
299
300 // called by dyld when a image is loaded
301 static const char* tlv_load_notification(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
302 {
303 // this is called on all images, even those without TLVs, so we want
304 // this to be fast. The linker sets MH_HAS_TLV_DESCRIPTORS so we don't
305 // have to search images just to find the don't have TLVs.
306 for (uint32_t i=0; i < infoCount; ++i) {
307 if ( info[i].imageLoadAddress->flags & MH_HAS_TLV_DESCRIPTORS )
308 tlv_initialize_descriptors(info[i].imageLoadAddress);
309 }
310 return NULL;
311 }
312
313
314 void dyld_register_tlv_state_change_handler(enum dyld_tlv_states state, dyld_tlv_state_change_handler handler)
315 {
316 TLVHandler *h = malloc(sizeof(TLVHandler));
317 h->state = state;
318 h->handler = Block_copy(handler);
319
320 TLVHandler *old;
321 do {
322 old = tlv_handlers;
323 h->next = old;
324 } while (! OSAtomicCompareAndSwapPtrBarrier(old, h, (void * volatile *)&tlv_handlers));
325 }
326
327
328 void dyld_enumerate_tlv_storage(dyld_tlv_state_change_handler handler)
329 {
330 pthread_mutex_lock(&tlv_live_image_lock);
331 unsigned int count = tlv_live_image_used_count;
332 void *list[count];
333 for (unsigned int i = 0; i < count; ++i) {
334 list[i] = pthread_getspecific(tlv_live_images[i].key);
335 }
336 pthread_mutex_unlock(&tlv_live_image_lock);
337
338 for (unsigned int i = 0; i < count; ++i) {
339 if (list[i]) {
340 dyld_tlv_info info = { sizeof(info), list[i], malloc_size(list[i]) };
341 handler(dyld_tlv_state_allocated, &info);
342 }
343 }
344 }
345
346
347 //
348 // thread_local terminators
349 //
350 // C++ 0x allows thread_local C++ objects which have constructors run
351 // on the thread before any use of the object and the object's destructor
352 // is run on the thread when the thread terminates.
353 //
354 // To support this libdyld gets a pthread key early in process start up and
355 // uses tlv_finalize and the key's destructor function. This key must be
356 // allocated before any thread local variables are instantiated because when
357 // a thread is terminated, the pthread package runs the destructor function
358 // on each key's storage values in key allocation order. Since we want
359 // C++ objects to be destructred before they are deallocated, we need the
360 // destructor key to come before the deallocation key.
361 //
362
363 typedef void (*TermFunc)(void*);
364 struct TLVTerminatorListEntry
365 {
366 TermFunc termFunc;
367 void* objAddr;
368 };
369
370 struct TLVTerminatorList
371 {
372 uint32_t allocCount;
373 uint32_t useCount;
374 struct TLVTerminatorListEntry entries[1]; // variable length
375 };
376
377
378 static pthread_key_t tlv_terminators_key = 0;
379
380 void _tlv_atexit(TermFunc func, void* objAddr)
381 {
382 // NOTE: this does not need locks because it only operates on current thread data
383 struct TLVTerminatorList* list = (struct TLVTerminatorList*)pthread_getspecific(tlv_terminators_key);
384 if ( list == NULL ) {
385 // handle first allocation
386 list = (struct TLVTerminatorList*)malloc(offsetof(struct TLVTerminatorList, entries[1]));
387 list->allocCount = 1;
388 list->useCount = 1;
389 list->entries[0].termFunc = func;
390 list->entries[0].objAddr = objAddr;
391 pthread_setspecific(tlv_terminators_key, list);
392 }
393 else {
394 if ( list->allocCount == list->allocCount ) {
395 // handle resizing allocation
396 uint32_t newAllocCount = list->allocCount * 2;
397 uint32_t newAllocSize = offsetof(struct TLVTerminatorList, entries[newAllocCount]);
398 struct TLVTerminatorList* newlist = (struct TLVTerminatorList*)malloc(newAllocSize);
399 newlist->allocCount = newAllocCount;
400 newlist->useCount = list->useCount;
401 for(uint32_t i=0; i < list->useCount; ++i)
402 newlist->entries[i] = list->entries[i];
403 pthread_setspecific(tlv_terminators_key, newlist);
404 free(list);
405 list = newlist;
406 }
407 // handle appending new entry
408 list->entries[list->useCount].termFunc = func;
409 list->entries[list->useCount].objAddr = objAddr;
410 list->useCount += 1;
411 }
412 }
413
414 // called by pthreads when the current thread is going way and
415 // _tlv_atexit() has been called on the thread.
416 static void tlv_finalize(void* storage)
417 {
418 struct TLVTerminatorList* list = (struct TLVTerminatorList*)storage;
419 for(uint32_t i=0; i < list->useCount; ++i) {
420 struct TLVTerminatorListEntry* entry = &list->entries[i];
421 if ( entry->termFunc != NULL ) {
422 (*entry->termFunc)(entry->objAddr);
423 }
424 }
425 free(storage);
426 }
427
428
429 __attribute__((visibility("hidden")))
430 void tlv_initializer()
431 {
432 // create pthread key to handle thread_local destructors
433 // NOTE: this key must be allocated before any keys for TLV
434 // so that _pthread_tsd_cleanup will run destructors before deallocation
435 (void)pthread_key_create(&tlv_terminators_key, &tlv_finalize);
436
437 // register with dyld for notification when images are loaded
438 dyld_register_image_state_change_handler(dyld_image_state_bound, true, tlv_load_notification);
439 }
440
441
442 // linked images with TLV have references to this symbol, but it is never used at runtime
443 void _tlv_bootstrap()
444 {
445 abort();
446 }
447
448
449 // __i386__ || __x86_64__
450 #else
451 // !(__i386__ || __x86_64__)
452
453
454 void dyld_register_tlv_state_change_handler(enum dyld_tlv_states state, dyld_tlv_state_change_handler handler)
455 {
456 }
457
458 void dyld_enumerate_tlv_storage(dyld_tlv_state_change_handler handler)
459 {
460 }
461
462 __attribute__((visibility("hidden")))
463 void tlv_initializer()
464 {
465 }
466
467
468 // !(__i386__ || __x86_64__)
469 #endif
470
471