1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
   3  * Copyright (c) 2010 Apple Inc. All rights reserved. 
   5  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  22  * @APPLE_LICENSE_HEADER_END@ 
  33 #include <malloc/malloc.h> 
  34 #include <mach-o/loader.h> 
  35 #include <libkern/OSAtomic.h> 
  37 #include <mach-o/dyld_priv.h> 
  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
; 
  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
; 
  53 typedef void (*TermFunc
)(void*); 
  57 #if __has_feature(tls) || __arm64__ || __arm__ 
  60 // Info about thread-local variable storage. 
  63     size_t info_size
;    // sizeof(dyld_tlv_info) 
  64     void * tlv_addr
;     // Base address of TLV storage 
  65     size_t tlv_size
;     // Byte size of TLV storage 
  71         void*                   (*thunk
)(struct TLVDescriptor
*); 
  75 typedef struct TLVDescriptor  TLVDescriptor
; 
  78 // implemented in assembly 
  79 extern void* tlv_get_addr(TLVDescriptor
*); 
  84         const struct mach_header
*       mh
; 
  86 typedef struct TLVImageInfo             TLVImageInfo
; 
  88 static TLVImageInfo
*    tlv_live_images 
= NULL
; 
  89 static unsigned int             tlv_live_image_alloc_count 
= 0; 
  90 static unsigned int             tlv_live_image_used_count 
= 0; 
  91 static pthread_mutex_t  tlv_live_image_lock 
= PTHREAD_MUTEX_INITIALIZER
; 
  93 static void tlv_set_key_for_image(const struct mach_header
* mh
, pthread_key_t key
) 
  95         pthread_mutex_lock(&tlv_live_image_lock
); 
  96                 if ( tlv_live_image_used_count 
== tlv_live_image_alloc_count 
) { 
  97                         unsigned int newCount 
= (tlv_live_images 
== NULL
) ? 8 : 2*tlv_live_image_alloc_count
; 
  98                         struct TLVImageInfo
* newBuffer 
= malloc(sizeof(TLVImageInfo
)*newCount
); 
  99                         if ( tlv_live_images 
!= NULL 
) { 
 100                                 memcpy(newBuffer
, tlv_live_images
, sizeof(TLVImageInfo
)*tlv_live_image_used_count
); 
 101                                 free(tlv_live_images
); 
 103                         tlv_live_images 
= newBuffer
; 
 104                         tlv_live_image_alloc_count 
= newCount
; 
 106                 tlv_live_images
[tlv_live_image_used_count
].key 
= key
; 
 107                 tlv_live_images
[tlv_live_image_used_count
].mh 
= mh
; 
 108                 ++tlv_live_image_used_count
; 
 109         pthread_mutex_unlock(&tlv_live_image_lock
); 
 112 static const struct mach_header
* tlv_get_image_for_key(pthread_key_t key
) 
 114         const struct mach_header
* result 
= NULL
; 
 115         pthread_mutex_lock(&tlv_live_image_lock
); 
 116                 for(unsigned int i
=0; i 
< tlv_live_image_used_count
; ++i
) { 
 117                         if ( tlv_live_images
[i
].key 
== key 
) { 
 118                                 result 
= tlv_live_images
[i
].mh
; 
 122         pthread_mutex_unlock(&tlv_live_image_lock
); 
 127 // called lazily when TLV is first accessed 
 128 __attribute__((visibility("hidden"))) 
 129 void* tlv_allocate_and_initialize_for_key(pthread_key_t key
) 
 131         const struct mach_header
* mh 
= tlv_get_image_for_key(key
); 
 133                 return NULL
;    // if data structures are screwed up, don't crash 
 135         // first pass, find size and template 
 136         uint8_t*                start 
= NULL
; 
 137         unsigned long   size 
= 0; 
 139         bool                    slideComputed 
= false; 
 140         bool                    hasInitializers 
= false; 
 141         const uint32_t  cmd_count 
= mh
->ncmds
; 
 142         const struct load_command
* const cmds 
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
)); 
 143         const struct load_command
* cmd 
= cmds
; 
 144         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 145                 if ( cmd
->cmd 
== LC_SEGMENT_COMMAND
) { 
 146                         const macho_segment_command
* seg 
= (macho_segment_command
*)cmd
; 
 147                         if ( !slideComputed 
&& (seg
->filesize 
!= 0) ) { 
 148                                 slide 
= (uintptr_t)mh 
- seg
->vmaddr
; 
 149                                 slideComputed 
= true; 
 151                         const macho_section
* const sectionsStart 
= (macho_section
*)((char*)seg 
+ sizeof(macho_segment_command
)); 
 152                         const macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
 153                         for (const macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
 154                                 switch ( sect
->flags 
& SECTION_TYPE 
) { 
 155                                         case S_THREAD_LOCAL_INIT_FUNCTION_POINTERS
: 
 156                                                 hasInitializers 
= true; 
 158                                         case S_THREAD_LOCAL_ZEROFILL
: 
 159                                         case S_THREAD_LOCAL_REGULAR
: 
 160                                                 if ( start 
== NULL 
) { 
 161                                                         // first of N contiguous TLV template sections, record as if this was only section 
 162                                                         start 
= (uint8_t*)(sect
->addr 
+ slide
); 
 166                                                         // non-first of N contiguous TLV template sections, accumlate values 
 167                                                         const uint8_t* newEnd 
= (uint8_t*)(sect
->addr 
+ slide 
+ sect
->size
); 
 168                                                         size 
= newEnd 
- start
; 
 174                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 176     // no thread local storage in image: should never happen 
 180         // allocate buffer and fill with template 
 181         void* buffer 
= malloc(size
); 
 182         memcpy(buffer
, start
, size
); 
 184         // set this thread's value for key to be the new buffer. 
 185         pthread_setspecific(key
, buffer
); 
 187         // second pass, run initializers 
 188         if ( hasInitializers 
) { 
 190                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 191                         if ( cmd
->cmd 
== LC_SEGMENT_COMMAND
) { 
 192                                 const macho_segment_command
* seg 
= (macho_segment_command
*)cmd
; 
 193                                 const macho_section
* const sectionsStart 
= (macho_section
*)((char*)seg 
+ sizeof(macho_segment_command
)); 
 194                                 const macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
 195                                 for (const macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
 196                                         if ( (sect
->flags 
& SECTION_TYPE
) == S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 
) { 
 197                                                 typedef void (*InitFunc
)(void); 
 198                                                 InitFunc
* funcs 
= (InitFunc
*)(sect
->addr 
+ slide
); 
 199                                                 const size_t count 
= sect
->size 
/ sizeof(uintptr_t); 
 200                                                 for (size_t j
=count
; j 
> 0; --j
) { 
 201                                                         InitFunc func 
= funcs
[j
-1]; 
 207                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 214 // pthread destructor for TLV storage 
 216 tlv_free(void *storage
) 
 222 // called when image is loaded 
 223 static void tlv_initialize_descriptors(const struct mach_header
* mh
) 
 225         pthread_key_t   key 
= 0; 
 227         bool                    slideComputed 
= false; 
 228         const uint32_t cmd_count 
= mh
->ncmds
; 
 229         const struct load_command
* const cmds 
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
)); 
 230         const struct load_command
* cmd 
= cmds
; 
 231         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 232                 if ( cmd
->cmd 
== LC_SEGMENT_COMMAND
) { 
 233                         const macho_segment_command
* seg 
= (macho_segment_command
*)cmd
; 
 234                         if ( !slideComputed 
&& (seg
->filesize 
!= 0) ) { 
 235                                 slide 
= (uintptr_t)mh 
- seg
->vmaddr
; 
 236                                 slideComputed 
= true; 
 238                         const macho_section
* const sectionsStart 
= (macho_section
*)((char*)seg 
+ sizeof(macho_segment_command
)); 
 239                         const macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
 240                         for (const macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
 241                                 if ( (sect
->flags 
& SECTION_TYPE
) == S_THREAD_LOCAL_VARIABLES 
) { 
 242                                         if ( sect
->size 
!= 0 ) { 
 243                                                 // allocate pthread key when we first discover this image has TLVs 
 245                                                         int result 
= pthread_key_create(&key
, &tlv_free
); 
 248                                                         tlv_set_key_for_image(mh
, key
); 
 250                                                 // initialize each descriptor 
 251                                                 TLVDescriptor
* start 
= (TLVDescriptor
*)(sect
->addr 
+ slide
); 
 252                                                 TLVDescriptor
* end 
= (TLVDescriptor
*)(sect
->addr 
+ sect
->size 
+ slide
); 
 253                                                 for (TLVDescriptor
* d
=start
; d 
< end
; ++d
) { 
 254                                                         d
->thunk 
= tlv_get_addr
; 
 256                                                         //d->offset = d->offset;  // offset unchanged 
 262                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 267 static void tlv_load_notification(const struct mach_header
* mh
, intptr_t slide
) 
 269         // This is called on all images, even those without TLVs. So we want this to be fast. 
 270         // The linker sets MH_HAS_TLV_DESCRIPTORS so we don't have to search images just to find the don't have TLVs. 
 271         if ( mh
->flags 
& MH_HAS_TLV_DESCRIPTORS 
) 
 272                 tlv_initialize_descriptors(mh
); 
 277 //  thread_local terminators 
 279 // C++ 0x allows thread_local C++ objects which have constructors run 
 280 // on the thread before any use of the object and the object's destructor 
 281 // is run on the thread when the thread terminates. 
 283 // To support this libdyld gets a pthread key early in process start up and 
 284 // uses tlv_finalize and the key's destructor function.  This key must be 
 285 // allocated before any thread local variables are instantiated because when 
 286 // a thread is terminated, the pthread package runs the destructor function 
 287 // on each key's storage values in key allocation order.  Since we want 
 288 // C++ objects to be destructred before they are deallocated, we need the  
 289 // destructor key to come before the deallocation key. 
 292 struct TLVTerminatorListEntry
 
 298 struct TLVTerminatorList
 
 302     struct TLVTerminatorListEntry   entries
[1];  // variable length 
 306 static pthread_key_t tlv_terminators_key 
= 0; 
 308 void _tlv_atexit(TermFunc func
, void* objAddr
) 
 310     // NOTE: this does not need locks because it only operates on current thread data 
 311         struct TLVTerminatorList
* list 
= (struct TLVTerminatorList
*)pthread_getspecific(tlv_terminators_key
); 
 312     if ( list 
== NULL 
) { 
 313         // handle first allocation 
 314         list 
= (struct TLVTerminatorList
*)malloc(offsetof(struct TLVTerminatorList
, entries
[1])); 
 315         list
->allocCount 
= 1; 
 317         list
->entries
[0].termFunc 
= func
; 
 318         list
->entries
[0].objAddr 
= objAddr
; 
 319         pthread_setspecific(tlv_terminators_key
, list
); 
 322         if ( list
->useCount 
== list
->allocCount 
) { 
 323             // handle resizing allocation  
 324             uint32_t newAllocCount 
= list
->allocCount 
* 2; 
 325             size_t newAllocSize 
= offsetof(struct TLVTerminatorList
, entries
[newAllocCount
]); 
 326             struct TLVTerminatorList
* newlist 
= (struct TLVTerminatorList
*)malloc(newAllocSize
); 
 327             newlist
->allocCount 
= newAllocCount
; 
 328             newlist
->useCount 
= list
->useCount
; 
 329             for(uint32_t i
=0; i 
< list
->useCount
; ++i
) 
 330                 newlist
->entries
[i
] = list
->entries
[i
]; 
 331             pthread_setspecific(tlv_terminators_key
, newlist
); 
 335         // handle appending new entry 
 336         list
->entries
[list
->useCount
].termFunc 
= func
; 
 337         list
->entries
[list
->useCount
].objAddr 
= objAddr
; 
 342 static void tlv_finalize_list(struct TLVTerminatorList
* list
) { 
 343     // destroy in reverse order of construction 
 344     for(uint32_t i
=list
->useCount
; i 
> 0 ; --i
) { 
 345         struct TLVTerminatorListEntry
* entry 
= &list
->entries
[i
-1]; 
 346         if ( entry
->termFunc 
!= NULL 
) { 
 347             (*entry
->termFunc
)(entry
->objAddr
); 
 350         // If a new tlv was added via tlv_atexit, then we need to immediately 
 352         struct TLVTerminatorList
* newlist 
= (struct TLVTerminatorList
*)pthread_getspecific(tlv_terminators_key
); 
 353         if ( newlist 
!= NULL 
) { 
 354             // Set the list to NULL so that if yet another tlv is registered, we put it in a new list 
 355             pthread_setspecific(tlv_terminators_key
, NULL
); 
 356             tlv_finalize_list(newlist
); 
 362 // called by pthreads when the current thread is going away and 
 363 // _tlv_atexit() has been called on the thread. 
 364 static void tlv_finalize(void* storage
) 
 366     // Note, on entry to this function, _tlv_exit set the list to NULL.  libpthread 
 367     // also set it to NULL before calling us.  If new thread locals are added to our 
 368     // tlv_terminators_key, then they will be on a new list, but the list we have here 
 369     // is one we own and need to destroy it 
 370     tlv_finalize_list((struct TLVTerminatorList
*)storage
); 
 373 // <rdar://problem/13741816> 
 374 // called by exit() before it calls cxa_finalize() so that thread_local 
 375 // objects are destroyed before global objects. 
 376 // Note this is only called on macOS, and by libc. 
 377 // iOS only destroys tlv's when each thread is destroyed and libpthread calls 
 378 // tlv_finalize as that is the pointer we provided when we created the key 
 381     void* termFuncs 
= pthread_getspecific(tlv_terminators_key
); 
 382     if ( termFuncs 
!= NULL 
) { 
 383         // Clear the value so that calls to tlv_atexit during tlv_finalize 
 384         // will go on to a new list to destroy. 
 385         pthread_setspecific(tlv_terminators_key
, NULL
); 
 386         tlv_finalize(termFuncs
); 
 391 __attribute__((visibility("hidden"))) 
 392 void tlv_initializer() 
 394     // create pthread key to handle thread_local destructors 
 395     // NOTE: this key must be allocated before any keys for TLV 
 396     // so that _pthread_tsd_cleanup will run destructors before deallocation 
 397     (void)pthread_key_create(&tlv_terminators_key
, &tlv_finalize
); 
 399     // register with dyld for notification when images are loaded 
 400         _dyld_register_func_for_add_image(tlv_load_notification
); 
 405 // linked images with TLV have references to this symbol, but it is never used at runtime 
 406 void _tlv_bootstrap() 
 419 void _tlv_atexit(TermFunc func
, void* objAddr
) 
 423 __attribute__((visibility("hidden"))) 
 424 void tlv_initializer() 
 430 #endif // __has_feature(tls)