#define MH_HAS_TLV_DESCRIPTORS 0x800000
#endif
-#if __i386__ || __x86_64__
+
+typedef void (*TermFunc)(void*);
+
+
+
+#if __has_feature(tls) || __arm64__ || __arm__
typedef struct TLVHandler {
struct TLVHandler *next;
void* tlv_allocate_and_initialize_for_key(pthread_key_t key)
{
const struct mach_header* mh = tlv_get_image_for_key(key);
+ if ( mh == NULL )
+ return NULL; // if data structures are screwed up, don't crash
+
// first pass, find size and template
uint8_t* start = NULL;
- unsigned long size;
+ unsigned long size = 0;
intptr_t slide = 0;
bool slideComputed = false;
bool hasInitializers = false;
}
cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
}
+ // no thread local storage in image: should never happen
+ if ( size == 0 )
+ return NULL;
// allocate buffer and fill with template
void* buffer = malloc(size);
if ( (sect->flags & SECTION_TYPE) == S_THREAD_LOCAL_INIT_FUNCTION_POINTERS ) {
typedef void (*InitFunc)(void);
InitFunc* funcs = (InitFunc*)(sect->addr + slide);
- const uint32_t count = sect->size / sizeof(uintptr_t);
- for (uint32_t i=count; i > 0; --i) {
- InitFunc func = funcs[i-1];
+ const size_t count = sect->size / sizeof(uintptr_t);
+ for (size_t j=count; j > 0; --j) {
+ InitFunc func = funcs[j-1];
func();
}
}
}
}
-// called by dyld when a image is loaded
-static const char* tlv_load_notification(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+
+static void tlv_load_notification(const struct mach_header* mh, intptr_t slide)
{
- // this is called on all images, even those without TLVs, so we want
- // this to be fast. The linker sets MH_HAS_TLV_DESCRIPTORS so we don't
- // have to search images just to find the don't have TLVs.
- for (uint32_t i=0; i < infoCount; ++i) {
- if ( info[i].imageLoadAddress->flags & MH_HAS_TLV_DESCRIPTORS )
- tlv_initialize_descriptors(info[i].imageLoadAddress);
- }
- return NULL;
+ // This is called on all images, even those without TLVs. So we want this to be fast.
+ // The linker sets MH_HAS_TLV_DESCRIPTORS so we don't have to search images just to find the don't have TLVs.
+ if ( mh->flags & MH_HAS_TLV_DESCRIPTORS )
+ tlv_initialize_descriptors(mh);
}
// destructor key to come before the deallocation key.
//
-typedef void (*TermFunc)(void*);
struct TLVTerminatorListEntry
{
TermFunc termFunc;
pthread_setspecific(tlv_terminators_key, list);
}
else {
- if ( list->allocCount == list->allocCount ) {
+ if ( list->useCount == list->allocCount ) {
// handle resizing allocation
uint32_t newAllocCount = list->allocCount * 2;
- uint32_t newAllocSize = offsetof(struct TLVTerminatorList, entries[newAllocCount]);
+ size_t newAllocSize = offsetof(struct TLVTerminatorList, entries[newAllocCount]);
struct TLVTerminatorList* newlist = (struct TLVTerminatorList*)malloc(newAllocSize);
newlist->allocCount = newAllocCount;
newlist->useCount = list->useCount;
}
}
-// called by pthreads when the current thread is going way and
+// called by pthreads when the current thread is going away and
// _tlv_atexit() has been called on the thread.
static void tlv_finalize(void* storage)
{
struct TLVTerminatorList* list = (struct TLVTerminatorList*)storage;
- for(uint32_t i=0; i < list->useCount; ++i) {
- struct TLVTerminatorListEntry* entry = &list->entries[i];
+ // destroy in reverse order of construction
+ for(uint32_t i=list->useCount; i > 0 ; --i) {
+ struct TLVTerminatorListEntry* entry = &list->entries[i-1];
if ( entry->termFunc != NULL ) {
(*entry->termFunc)(entry->objAddr);
}
free(storage);
}
+// <rdar://problem/13741816>
+// called by exit() before it calls cxa_finalize() so that thread_local
+// objects are destroyed before global objects.
+void _tlv_exit()
+{
+ void* termFuncs = pthread_getspecific(tlv_terminators_key);
+ if ( termFuncs != NULL )
+ tlv_finalize(termFuncs);
+}
+
__attribute__((visibility("hidden")))
void tlv_initializer()
(void)pthread_key_create(&tlv_terminators_key, &tlv_finalize);
// register with dyld for notification when images are loaded
- dyld_register_image_state_change_handler(dyld_image_state_bound, true, tlv_load_notification);
+ _dyld_register_func_for_add_image(tlv_load_notification);
+
}
}
-// __i386__ || __x86_64__
+
#else
-// !(__i386__ || __x86_64__)
+
void dyld_register_tlv_state_change_handler(enum dyld_tlv_states state, dyld_tlv_state_change_handler handler)
{
}
+void _tlv_exit()
+{
+}
+
+void _tlv_atexit(TermFunc func, void* objAddr)
+{
+}
+
__attribute__((visibility("hidden")))
void tlv_initializer()
{
}
-// !(__i386__ || __x86_64__)
-#endif
+
+#endif // __has_feature(tls)