]> git.saurik.com Git - apple/objc4.git/blobdiff - runtime/objc-os.m
objc4-532.tar.gz
[apple/objc4.git] / runtime / objc-os.m
diff --git a/runtime/objc-os.m b/runtime/objc-os.m
deleted file mode 100644 (file)
index 4a8aa4d..0000000
+++ /dev/null
@@ -1,999 +0,0 @@
-/*
- * Copyright (c) 2007 Apple Inc.  All Rights Reserved.
- * 
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/***********************************************************************
-* objc-os.m
-* OS portability layer.
-**********************************************************************/
-
-#include "objc-os.h"
-#include "objc-private.h"
-#include "objc-loadmethod.h"
-
-#if TARGET_OS_WIN32
-
-#include "objc-runtime-old.h"
-#include "objcrt.h"
-
-malloc_zone_t *_objc_internal_zone(void) 
-{ 
-    return NULL; 
-}
-
-int monitor_init(monitor_t *c) 
-{
-    // fixme error checking
-    HANDLE mutex = CreateMutex(NULL, TRUE, NULL);
-    while (!c->mutex) {
-        // fixme memory barrier here?
-        if (0 == InterlockedCompareExchangePointer(&c->mutex, mutex, 0)) {
-            // we win - finish construction
-            c->waiters = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
-            c->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
-            InitializeCriticalSection(&c->waitCountLock);
-            c->waitCount = 0;
-            c->didBroadcast = 0;
-            ReleaseMutex(c->mutex);    
-            return 0;
-        }
-    }
-
-    // someone else allocated the mutex and constructed the monitor
-    ReleaseMutex(mutex);
-    CloseHandle(mutex);
-    return 0;
-}
-
-void mutex_init(mutex_t *m)
-{
-    while (!m->lock) {
-        CRITICAL_SECTION *newlock = malloc(sizeof(CRITICAL_SECTION));
-        InitializeCriticalSection(newlock);
-        // fixme memory barrier here?
-        if (0 == InterlockedCompareExchangePointer(&m->lock, newlock, 0)) {
-            return;
-        }
-        // someone else installed their lock first
-        DeleteCriticalSection(newlock);
-        free(newlock);
-    }
-}
-
-
-void recursive_mutex_init(recursive_mutex_t *m)
-{
-    // fixme error checking
-    HANDLE newmutex = CreateMutex(NULL, FALSE, NULL);
-    while (!m->mutex) {
-        // fixme memory barrier here?
-        if (0 == InterlockedCompareExchangePointer(&m->mutex, newmutex, 0)) {
-            // we win
-            return;
-        }
-    }
-    
-    // someone else installed their lock first
-    CloseHandle(newmutex);
-}
-
-
-WINBOOL APIENTRY DllMain( HMODULE hModule,
-                       DWORD  ul_reason_for_call,
-                       LPVOID lpReserved
-                                        )
-{
-    switch (ul_reason_for_call) {
-    case DLL_PROCESS_ATTACH:
-        environ_init();
-        tls_init();
-        lock_init();
-        sel_init(NO);
-        exception_init();        
-        break;
-
-    case DLL_THREAD_ATTACH:
-        break;
-
-    case DLL_THREAD_DETACH:
-    case DLL_PROCESS_DETACH:
-        break;
-    }
-    return TRUE;
-}
-
-OBJC_EXPORT void *_objc_init_image(HMODULE image, const objc_sections *sects)
-{
-    header_info *hi = _malloc_internal(sizeof(header_info));
-    size_t count, i;
-
-    hi->mhdr = (const headerType *)image;
-    hi->info = sects->iiStart;
-    hi->allClassesRealized = NO;
-    hi->os.modules = sects->modStart ? (Module *)((void **)sects->modStart+1) : 0;
-    hi->os.moduleCount = (Module *)sects->modEnd - hi->os.modules;
-    hi->os.protocols = sects->protoStart ? (struct old_protocol **)((void **)sects->protoStart+1) : 0;
-    hi->os.protocolCount = (struct old_protocol **)sects->protoEnd - hi->os.protocols;
-    hi->os.imageinfo = NULL;
-    hi->os.imageinfoBytes = 0;
-    // hi->os.imageinfo = sects->iiStart ? (uint8_t *)((void **)sects->iiStart+1) : 0;;
-//     hi->os.imageinfoBytes = (uint8_t *)sects->iiEnd - hi->os.imageinfo;
-    hi->os.selrefs = sects->selrefsStart ? (SEL *)((void **)sects->selrefsStart+1) : 0;
-    hi->os.selrefCount = (SEL *)sects->selrefsEnd - hi->os.selrefs;
-    hi->os.clsrefs = sects->clsrefsStart ? (Class *)((void **)sects->clsrefsStart+1) : 0;
-    hi->os.clsrefCount = (Class *)sects->clsrefsEnd - hi->os.clsrefs;
-
-    count = 0;
-    for (i = 0; i < hi->os.moduleCount; i++) {
-        if (hi->os.modules[i]) count++;
-    }
-    hi->mod_count = 0;
-    hi->mod_ptr = 0;
-    if (count > 0) {
-        hi->mod_ptr = malloc(count * sizeof(struct objc_module));
-        for (i = 0; i < hi->os.moduleCount; i++) {
-            if (hi->os.modules[i]) memcpy(&hi->mod_ptr[hi->mod_count++], hi->os.modules[i], sizeof(struct objc_module));
-        }
-    }
-    
-    hi->os.moduleName = malloc(MAX_PATH * sizeof(TCHAR));
-    GetModuleFileName((HMODULE)(hi->mhdr), hi->os.moduleName, MAX_PATH * sizeof(TCHAR));
-
-    _objc_appendHeader(hi);
-
-    if (PrintImages) {
-        _objc_inform("IMAGES: loading image for %s%s%s\n", 
-            _nameForHeader(hi->mhdr), 
-            headerIsBundle(hi) ? " (bundle)" : "", 
-            _objcHeaderIsReplacement(hi) ? " (replacement)":"");
-    }
-
-    _read_images(&hi, 1);
-
-    return hi;
-}
-
-OBJC_EXPORT void _objc_load_image(HMODULE image, header_info *hinfo)
-{
-    prepare_load_methods(hinfo);
-    call_load_methods();
-}
-
-OBJC_EXPORT void _objc_unload_image(HMODULE image, header_info *hinfo)
-{
-    _objc_fatal("image unload not supported");
-}
-
-
-PRIVATE_EXTERN bool crashlog_header_name(header_info *hi)
-{
-    return true;
-}
-
-
-// TARGET_OS_WIN32
-#elif TARGET_OS_MAC
-
-#if !__OBJC2__
-#include "objc-file-old.h"
-#endif
-
-PRIVATE_EXTERN void mutex_init(mutex_t *m)
-{
-    pthread_mutex_init(m, NULL);
-}
-
-
-PRIVATE_EXTERN void recursive_mutex_init(recursive_mutex_t *m)
-{
-    // fixme error checking
-    pthread_mutex_t *newmutex;
-
-    // Build recursive mutex attributes, if needed
-    static pthread_mutexattr_t *attr;
-    if (!attr) {
-        pthread_mutexattr_t *newattr = 
-            _malloc_internal(sizeof(pthread_mutexattr_t));
-        pthread_mutexattr_init(newattr);
-        pthread_mutexattr_settype(newattr, PTHREAD_MUTEX_RECURSIVE);
-        while (!attr) {
-            if (OSAtomicCompareAndSwapPtrBarrier(0, newattr, (void**)&attr)) {
-                // we win
-                goto attr_done;
-            }
-        }
-        // someone else built the attr first
-        _free_internal(newattr);
-    }
- attr_done:
-
-    // Build the mutex itself
-    newmutex = _malloc_internal(sizeof(pthread_mutex_t));
-    pthread_mutex_init(newmutex, attr);
-    while (!m->mutex) {
-        if (OSAtomicCompareAndSwapPtrBarrier(0, newmutex, (void**)&m->mutex)) {
-            // we win
-            return;
-        }
-    }
-    
-    // someone else installed their mutex first
-    pthread_mutex_destroy(newmutex);
-}
-
-
-/***********************************************************************
-* bad_magic.
-* Return YES if the header has invalid Mach-o magic.
-**********************************************************************/
-PRIVATE_EXTERN BOOL bad_magic(const headerType *mhdr)
-{
-    return (mhdr->magic != MH_MAGIC  &&  mhdr->magic != MH_MAGIC_64  &&  
-            mhdr->magic != MH_CIGAM  &&  mhdr->magic != MH_CIGAM_64);
-}
-
-
-static header_info * _objc_addHeader(const headerType *mhdr)
-{
-    size_t info_size = 0;
-    unsigned long seg_size;
-    const uint8_t *objc_segment;
-    const objc_image_info *image_info;
-    header_info *result;
-
-    if (bad_magic(mhdr)) return NULL;
-
-    // Weed out duplicates
-    for (result = FirstHeader; result; result = result->next) {
-        if (mhdr == result->mhdr) return NULL;
-    }
-
-    // Locate the __OBJC segment
-    image_info = _getObjcImageInfo(mhdr, &info_size);
-    objc_segment = getsegmentdata(mhdr, SEG_OBJC, &seg_size);
-    if (!objc_segment  &&  !image_info) return NULL;
-
-    // Allocate a header_info entry.
-    result = _calloc_internal(sizeof(header_info), 1);
-
-    // Set up the new header_info entry.
-    result->mhdr = mhdr;
-#if !__OBJC2__
-    // mhdr must already be set
-    result->mod_count = 0;
-    result->mod_ptr = _getObjcModules(result, &result->mod_count);
-#endif
-    result->info = image_info;
-    dladdr(result->mhdr, &result->os.dl_info);
-    result->allClassesRealized = NO;
-
-    // dylibs are not allowed to unload
-    // ...except those with image_info and nothing else (5359412)
-    if (result->mhdr->filetype == MH_DYLIB  &&  _hasObjcContents(result)) {
-        dlopen(result->os.dl_info.dli_fname, RTLD_NOLOAD);
-    }
-
-    // Make sure every copy of objc_image_info in this image is the same.
-    // This means same version and same bitwise contents.
-    if (result->info) {
-        const objc_image_info *start = result->info;
-        const objc_image_info *end = 
-            (objc_image_info *)(info_size + (uint8_t *)start);
-        const objc_image_info *info = start;
-        while (info < end) {
-            // version is byte size, except for version 0
-            size_t struct_size = info->version;
-            if (struct_size == 0) struct_size = 2 * sizeof(uint32_t);
-            if (info->version != start->version  ||  
-                0 != memcmp(info, start, struct_size))
-            {
-                _objc_inform("'%s' has inconsistently-compiled Objective-C "
-                            "code. Please recompile all code in it.", 
-                            _nameForHeader(mhdr));
-            }
-            info = (objc_image_info *)(struct_size + (uint8_t *)info);
-        }
-    }
-
-    _objc_appendHeader(result);
-    
-    return result;
-}
-
-
-#if !SUPPORT_GC
-
-PRIVATE_EXTERN const char *_gcForHInfo(const header_info *hinfo)
-{
-    return "";
-}
-PRIVATE_EXTERN const char *_gcForHInfo2(const header_info *hinfo)
-{
-    return "";
-}
-
-#else
-
-/***********************************************************************
-* _gcForHInfo.
-**********************************************************************/
-PRIVATE_EXTERN const char *_gcForHInfo(const header_info *hinfo)
-{
-    if (_objcHeaderRequiresGC(hinfo)) {
-        if (_objcHeaderSupportsCompaction(hinfo))
-            return "requires GC, supports compaction";
-        else
-            return "requires GC";
-    } else if (_objcHeaderSupportsGC(hinfo)) {
-        if (_objcHeaderSupportsCompaction(hinfo))
-            return "supports GC, supports compaction";
-        else
-            return "supports GC";
-    } else {
-        return "does not support GC";
-    }
-}
-PRIVATE_EXTERN const char *_gcForHInfo2(const header_info *hinfo)
-{
-    if (_objcHeaderRequiresGC(hinfo)) {
-        if (_objcHeaderSupportsCompaction(hinfo))
-            return "(requires GC) (supports compaction)";
-        else
-            return "(requires GC)";
-    } else if (_objcHeaderSupportsGC(hinfo)) {
-        if (_objcHeaderSupportsCompaction(hinfo))
-            return "(supports GC) (supports compaction)";
-        else
-            return "(supports GC)";
-    }
-    return "";
-}
-
-
-/***********************************************************************
-* check_gc
-* Check whether the executable supports or requires GC, and make sure 
-* all already-loaded libraries support the executable's GC mode.
-* Returns TRUE if the executable wants GC on.
-**********************************************************************/
-static void check_wants_gc(BOOL *appWantsGC, BOOL *appSupportsCompaction)
-{
-    const header_info *hi;
-
-    // Environment variables can override the following.
-    if (DisableGC) {
-        _objc_inform("GC: forcing GC OFF because OBJC_DISABLE_GC is set");
-        *appWantsGC = NO;
-        *appSupportsCompaction = NO;
-    }
-    else {
-        // Find the executable and check its GC bits. 
-        // If the executable cannot be found, default to NO.
-        // (The executable will not be found if the executable contains 
-        // no Objective-C code.)
-        *appWantsGC = NO;
-        *appSupportsCompaction = NO;
-        for (hi = FirstHeader; hi != NULL; hi = hi->next) {
-            if (hi->mhdr->filetype == MH_EXECUTE) {
-                *appWantsGC = _objcHeaderSupportsGC(hi) ? YES : NO;
-                *appSupportsCompaction = (*appWantsGC && _objcHeaderSupportsCompaction(hi)) ? YES : NO;
-                if (PrintGC) {
-                    _objc_inform("GC: executable '%s' %s",
-                                 _nameForHeader(hi->mhdr), _gcForHInfo(hi));
-                }
-            }
-        }
-    }
-}
-
-
-/***********************************************************************
-* verify_gc_readiness
-* if we want gc, verify that every header describes files compiled
-* and presumably ready for gc.
-************************************************************************/
-static void verify_gc_readiness(BOOL wantsGC, BOOL *wantsCompaction,
-                                header_info **hList, uint32_t hCount)
-{
-    BOOL busted = NO;
-    uint32_t i;
-
-    // Find the libraries and check their GC bits against the app's request
-    for (i = 0; i < hCount; i++) {
-        header_info *hi = hList[i];
-        if (hi->mhdr->filetype == MH_EXECUTE) {
-            continue;
-        }
-        else if (hi->mhdr == &_mh_dylib_header) {
-            // libobjc itself works with anything even though it is not 
-            // compiled with -fobjc-gc (fixme should it be?)
-        } 
-        else if (wantsGC  &&  ! _objcHeaderSupportsGC(hi)) {
-            // App wants GC but library does not support it - bad
-            _objc_inform_now_and_on_crash
-                ("'%s' was not compiled with -fobjc-gc or -fobjc-gc-only, "
-                 "but the application requires GC",
-                 _nameForHeader(hi->mhdr));
-            busted = YES;
-        } 
-        else if (!wantsGC  &&  _objcHeaderRequiresGC(hi)) {
-            // App doesn't want GC but library requires it - bad
-            _objc_inform_now_and_on_crash
-                ("'%s' was compiled with -fobjc-gc-only, "
-                 "but the application does not support GC",
-                 _nameForHeader(hi->mhdr));
-            busted = YES;            
-        }
-        
-        if (*wantsCompaction && !_objcHeaderSupportsCompaction(hi)) {
-            // App supports compaction, but library doesn't.
-            _objc_inform_now_and_on_crash
-                ("'%s' was not linked with -Xlinker -objc_gc_compaction, "
-                 "but the application wants compaction.",
-                 _nameForHeader(hi->mhdr));
-            // Simply warn for now until radars are filed. Eventually,
-            // objc_disableCompaction() will block until any current compaction completes.
-            objc_disableCompaction();
-            *wantsCompaction = NO;
-        }
-
-        if (PrintGC) {
-            _objc_inform("GC: library '%s' %s", 
-                         _nameForHeader(hi->mhdr), _gcForHInfo(hi));
-        }
-    }
-    
-    if (busted) {
-        // GC state is not consistent. 
-        // Kill the process unless one of the forcing flags is set.
-        if (!DisableGC) {
-            _objc_fatal("*** GC capability of application and some libraries did not match");
-        }
-    }
-}
-
-
-/***********************************************************************
-* gc_enforcer
-* Make sure that images about to be loaded by dyld are GC-acceptable.
-* Images linked to the executable are always permitted; they are 
-* enforced inside map_images() itself.
-**********************************************************************/
-static BOOL InitialDyldRegistration = NO;
-static const char *gc_enforcer(enum dyld_image_states state, 
-                               uint32_t infoCount, 
-                               const struct dyld_image_info info[])
-{
-    uint32_t i;
-
-    // Linked images get a free pass
-    if (InitialDyldRegistration) return NULL;
-
-    if (PrintImages) {
-        _objc_inform("IMAGES: checking %d images for compatibility...", 
-                     infoCount);
-    }
-
-    for (i = 0; i < infoCount; i++) {
-        crashlog_header_name_string(info[i].imageFilePath);
-
-        const headerType *mhdr = (const headerType *)info[i].imageLoadAddress;
-        if (bad_magic(mhdr)) continue;
-
-        objc_image_info *image_info;
-        size_t size;
-
-        if (mhdr == &_mh_dylib_header) {
-            // libobjc itself - OK
-            continue;
-        }
-
-#if !__OBJC2__
-        unsigned long seg_size;
-        // 32-bit: __OBJC seg but no image_info means no GC support
-        if (!getsegmentdata(mhdr, "__OBJC", &seg_size)) {
-            // not objc - assume OK
-            continue;
-        }
-        image_info = _getObjcImageInfo(mhdr, &size);
-        if (!image_info) {
-            // No image_info - assume GC unsupported
-            if (!UseGC) {
-                // GC is OFF - ok
-                continue;
-            } else {
-                // GC is ON - bad
-                if (PrintImages  ||  PrintGC) {
-                    _objc_inform("IMAGES: rejecting %d images because %s doesn't support GC (no image_info)", infoCount, info[i].imageFilePath);
-                }
-                goto reject;
-            }
-        }
-#else
-        // 64-bit: no image_info means no objc at all
-        image_info = _getObjcImageInfo(mhdr, &size);
-        if (!image_info) {
-            // not objc - assume OK
-            continue;
-        }
-#endif
-
-        if (UseGC  &&  !_objcInfoSupportsGC(image_info)) {
-            // GC is ON, but image does not support GC
-            if (PrintImages  ||  PrintGC) {
-                _objc_inform("IMAGES: rejecting %d images because %s doesn't support GC", infoCount, info[i].imageFilePath);
-            }
-            goto reject;
-        }
-        if (!UseGC  &&  _objcInfoRequiresGC(image_info)) {
-            // GC is OFF, but image requires GC
-            if (PrintImages  ||  PrintGC) {
-                _objc_inform("IMAGES: rejecting %d images because %s requires GC", infoCount, info[i].imageFilePath);
-            }
-            goto reject;
-        }
-    }
-
-    crashlog_header_name_string(NULL);
-    return NULL;
-
- reject:
-    crashlog_header_name_string(NULL);
-    return "GC capability mismatch";
-}
-
-// SUPPORT_GC
-#endif
-
-
-/***********************************************************************
-* map_images_nolock
-* Process the given images which are being mapped in by dyld.
-* All class registration and fixups are performed (or deferred pending
-* discovery of missing superclasses etc), and +load methods are called.
-*
-* info[] is in bottom-up order i.e. libobjc will be earlier in the 
-* array than any library that links to libobjc.
-*
-* Locking: loadMethodLock(old) or runtimeLock(new) acquired by map_images.
-**********************************************************************/
-PRIVATE_EXTERN const char *
-map_images_nolock(enum dyld_image_states state, uint32_t infoCount,
-                  const struct dyld_image_info infoList[])
-{
-    static BOOL firstTime = YES;
-    static BOOL wantsGC = NO;
-    static BOOL wantsCompaction = NO;
-    uint32_t i;
-    header_info *hi;
-    header_info *hList[infoCount];
-    uint32_t hCount;
-
-    // Perform first-time initialization if necessary.
-    // This function is called before ordinary library initializers. 
-    // fixme defer initialization until an objc-using image is found?
-    if (firstTime) {
-#if SUPPORT_GC
-        InitialDyldRegistration = YES;
-        dyld_register_image_state_change_handler(dyld_image_state_mapped, 0 /* batch */, &gc_enforcer);
-        InitialDyldRegistration = NO;
-#endif
-    }
-
-    if (PrintImages) {
-        _objc_inform("IMAGES: processing %u newly-mapped images...\n", infoCount);
-    }
-
-
-    // Find all images with Objective-C metadata.
-    hCount = 0;
-    i = infoCount;
-    while (i--) {
-        const headerType *mhdr = (headerType *)infoList[i].imageLoadAddress;
-
-        hi = _objc_addHeader(mhdr);
-        if (!hi) {
-            // no objc data in this entry
-            continue;
-        }
-
-        hList[hCount++] = hi;
-        
-
-        if (PrintImages) {
-            _objc_inform("IMAGES: loading image for %s%s%s%s%s\n", 
-                         _nameForHeader(mhdr), 
-                         mhdr->filetype == MH_BUNDLE ? " (bundle)" : "", 
-                         _objcHeaderIsReplacement(hi) ? " (replacement)" : "",
-                         _objcHeaderOptimizedByDyld(hi)?" (preoptimized)" : "",
-                         _gcForHInfo2(hi));
-        }
-    }
-
-    // Perform one-time runtime initialization that must be deferred until 
-    // the executable itself is found. This needs to be done before 
-    // further initialization.
-    // (The executable may not be present in this infoList if the 
-    // executable does not contain Objective-C code but Objective-C 
-    // is dynamically loaded later. In that case, check_wants_gc() 
-    // will do the right thing.)
-#if SUPPORT_GC
-    if (firstTime) {
-        check_wants_gc(&wantsGC, &wantsCompaction);
-
-        verify_gc_readiness(wantsGC, &wantsCompaction, hList, hCount);
-        
-        gc_init(wantsGC, wantsCompaction);  // needs executable for GC decision
-        rtp_init();                         // needs GC decision first
-    } else {
-        verify_gc_readiness(wantsGC, &wantsCompaction, hList, hCount);
-    }
-
-    if (wantsGC) {
-        // tell the collector about the data segment ranges.
-        for (i = 0; i < hCount; ++i) {
-            uint8_t *seg;
-            unsigned long seg_size;
-            hi = hList[i];
-
-            seg = getsegmentdata(hi->mhdr, "__DATA", &seg_size);
-            if (seg) gc_register_datasegment((uintptr_t)seg, seg_size);
-
-            seg = getsegmentdata(hi->mhdr, "__OBJC", &seg_size);
-            if (seg) gc_register_datasegment((uintptr_t)seg, seg_size);
-            // __OBJC contains no GC data, but pointers to it are 
-            // used as associated reference values (rdar://6953570)
-        }
-    }
-
-    // Need to fixup barriers in all libraries that call into libobjc, whether GC is on or not.
-    for (i = 0; i < infoCount; ++i) {
-        gc_fixup_barrier_stubs(&infoList[i]);
-    }
-#endif
-
-    if (firstTime) {
-        extern SEL FwdSel;  // in objc-msg-*.s
-        sel_init(wantsGC);
-        FwdSel = sel_registerName("forward::");
-
-        arr_init();
-    }
-
-    _read_images(hList, hCount);
-
-    firstTime = NO;
-
-    return NULL;
-}
-
-
-/***********************************************************************
-* load_images_nolock
-* Prepares +load in the given images which are being mapped in by dyld.
-* Returns YES if there are now +load methods to be called by call_load_methods.
-*
-* Locking: loadMethodLock(both) and runtimeLock(new) acquired by load_images
-**********************************************************************/
-PRIVATE_EXTERN BOOL 
-load_images_nolock(enum dyld_image_states state,uint32_t infoCount,
-                   const struct dyld_image_info infoList[])
-{
-    BOOL found = NO;
-    uint32_t i;
-
-    i = infoCount;
-    while (i--) {
-        header_info *hi;
-        for (hi = FirstHeader; hi != NULL; hi = hi->next) {
-            const headerType *mhdr = (headerType*)infoList[i].imageLoadAddress;
-            if (hi->mhdr == mhdr) {
-                prepare_load_methods(hi);
-                found = YES;
-            }
-        }
-    }
-
-    return found;
-}
-
-
-/***********************************************************************
-* unmap_image_nolock
-* Process the given image which is about to be unmapped by dyld.
-* mh is mach_header instead of headerType because that's what 
-*   dyld_priv.h says even for 64-bit.
-* 
-* Locking: loadMethodLock(both) and runtimeLock(new) acquired by unmap_image.
-**********************************************************************/
-PRIVATE_EXTERN void 
-unmap_image_nolock(const struct mach_header *mh)
-{
-    if (PrintImages) {
-        _objc_inform("IMAGES: processing 1 newly-unmapped image...\n");
-    }
-
-    header_info *hi;
-    
-    // Find the runtime's header_info struct for the image
-    for (hi = FirstHeader; hi != NULL; hi = hi->next) {
-        if (hi->mhdr == (const headerType *)mh) {
-            break;
-        }
-    }
-
-    if (!hi) return;
-
-    if (PrintImages) { 
-        _objc_inform("IMAGES: unloading image for %s%s%s%s\n", 
-                     _nameForHeader(hi->mhdr), 
-                     hi->mhdr->filetype == MH_BUNDLE ? " (bundle)" : "", 
-                     _objcHeaderIsReplacement(hi) ? " (replacement)" : "", 
-                     _gcForHInfo2(hi));
-    }
-
-#if SUPPORT_GC
-    if (UseGC) {
-        uint8_t *seg;
-        unsigned long seg_size;
-
-        seg = getsegmentdata(hi->mhdr, "__DATA", &seg_size);
-        if (seg) gc_unregister_datasegment((uintptr_t)seg, seg_size);
-
-        seg = getsegmentdata(hi->mhdr, "__OBJC", &seg_size);
-        if (seg) gc_unregister_datasegment((uintptr_t)seg, seg_size);
-    }
-#endif
-
-    _unload_image(hi);
-
-    // Remove header_info from header list
-    _objc_removeHeader(hi);
-    _free_internal(hi);
-}
-
-
-/***********************************************************************
-* _objc_init
-* Static initializer. Registers our image notifier with dyld.
-**********************************************************************/
-static __attribute__((constructor))
-void _objc_init(void)
-{
-    // fixme defer initialization until an objc-using image is found?
-    environ_init();
-    tls_init();
-    lock_init();
-    exception_init();
-        
-    // Register for unmap first, in case some +load unmaps something
-    _dyld_register_func_for_remove_image(&unmap_image);
-    dyld_register_image_state_change_handler(dyld_image_state_bound,
-                                             1/*batch*/, &map_images);
-    dyld_register_image_state_change_handler(dyld_image_state_dependents_initialized, 0/*not batch*/, &load_images);
-}
-
-
-/***********************************************************************
-* _headerForAddress.
-* addr can be a class or a category
-**********************************************************************/
-static const header_info *_headerForAddress(void *addr)
-{
-#if __OBJC2__
-    const char *segname = "__DATA";
-#else
-    const char *segname = "__OBJC";
-#endif
-    header_info *hi;
-
-    // Check all headers in the vector
-    for (hi = FirstHeader; hi != NULL; hi = hi->next)
-    {
-        uint8_t *seg;
-        unsigned long seg_size;
-
-        seg = getsegmentdata(hi->mhdr, segname, &seg_size);
-        if (!seg) continue;
-
-        // Is the class in this header?
-        if ((uint8_t *)addr >= seg  &&  (uint8_t *)addr < seg + seg_size)
-            return hi;
-    }
-
-    // Not found
-    return 0;
-}
-
-
-/***********************************************************************
-* _headerForClass
-* Return the image header containing this class, or NULL.
-* Returns NULL on runtime-constructed classes, and the NSCF classes.
-**********************************************************************/
-PRIVATE_EXTERN const header_info *_headerForClass(Class cls)
-{
-    return _headerForAddress(cls);
-}
-
-
-/**********************************************************************
-* secure_open
-* Securely open a file from a world-writable directory (like /tmp)
-* If the file does not exist, it will be atomically created with mode 0600
-* If the file exists, it must be, and remain after opening: 
-*   1. a regular file (in particular, not a symlink)
-*   2. owned by euid
-*   3. permissions 0600
-*   4. link count == 1
-* Returns a file descriptor or -1. Errno may or may not be set on error.
-**********************************************************************/
-PRIVATE_EXTERN int secure_open(const char *filename, int flags, uid_t euid)
-{
-    struct stat fs, ls;
-    int fd = -1;
-    BOOL truncate = NO;
-    BOOL create = NO;
-
-    if (flags & O_TRUNC) {
-        // Don't truncate the file until after it is open and verified.
-        truncate = YES;
-        flags &= ~O_TRUNC;
-    }
-    if (flags & O_CREAT) {
-        // Don't create except when we're ready for it
-        create = YES;
-        flags &= ~O_CREAT;
-        flags &= ~O_EXCL;
-    }
-
-    if (lstat(filename, &ls) < 0) {
-        if (errno == ENOENT  &&  create) {
-            // No such file - create it
-            fd = open(filename, flags | O_CREAT | O_EXCL, 0600);
-            if (fd >= 0) {
-                // File was created successfully.
-                // New file does not need to be truncated.
-                return fd;
-            } else {
-                // File creation failed.
-                return -1;
-            }
-        } else {
-            // lstat failed, or user doesn't want to create the file
-            return -1;
-        }
-    } else {
-        // lstat succeeded - verify attributes and open
-        if (S_ISREG(ls.st_mode)  &&  // regular file?
-            ls.st_nlink == 1  &&     // link count == 1?
-            ls.st_uid == euid  &&    // owned by euid?
-            (ls.st_mode & ALLPERMS) == (S_IRUSR | S_IWUSR))  // mode 0600?
-        {
-            // Attributes look ok - open it and check attributes again
-            fd = open(filename, flags, 0000);
-            if (fd >= 0) {
-                // File is open - double-check attributes
-                if (0 == fstat(fd, &fs)  &&  
-                    fs.st_nlink == ls.st_nlink  &&  // link count == 1?
-                    fs.st_uid == ls.st_uid  &&      // owned by euid?
-                    fs.st_mode == ls.st_mode  &&    // regular file, 0600?
-                    fs.st_ino == ls.st_ino  &&      // same inode as before?
-                    fs.st_dev == ls.st_dev)         // same device as before?
-                {
-                    // File is open and OK
-                    if (truncate) ftruncate(fd, 0);
-                    return fd;
-                } else {
-                    // Opened file looks funny - close it
-                    close(fd);
-                    return -1;
-                }
-            } else {
-                // File didn't open
-                return -1;
-            }
-        } else {
-            // Unopened file looks funny - don't open it
-            return -1;
-        }
-    }
-}
-
-
-/***********************************************************************
-* _objc_internal_zone.
-* Malloc zone for internal runtime data.
-* By default this is the default malloc zone, but a dedicated zone is 
-* used if environment variable OBJC_USE_INTERNAL_ZONE is set.
-**********************************************************************/
-PRIVATE_EXTERN malloc_zone_t *_objc_internal_zone(void)
-{
-    static malloc_zone_t *z = (malloc_zone_t *)-1;
-    if (z == (malloc_zone_t *)-1) {
-        if (UseInternalZone) {
-            z = malloc_create_zone(vm_page_size, 0);
-            malloc_set_zone_name(z, "ObjC");
-        } else {
-            z = malloc_default_zone();
-        }
-    }
-    return z;
-}
-
-
-PRIVATE_EXTERN const char *
-_getObjcHeaderName(const headerType *header)
-{
-    Dl_info info;
-
-    if (dladdr(header, &info)) {
-        return info.dli_fname;
-    }
-    else {
-        return (*_NSGetArgv())[0];
-    }
-}
-
-
-PRIVATE_EXTERN bool crashlog_header_name(header_info *hi)
-{
-    return crashlog_header_name_string(hi ? hi->os.dl_info.dli_fname : NULL);
-}
-
-PRIVATE_EXTERN bool crashlog_header_name_string(const char *name)
-{
-    CRSetCrashLogMessage2(name);
-    return true;
-}
-
-
-#if TARGET_OS_IPHONE
-
-PRIVATE_EXTERN const char *__crashreporter_info__ = NULL;
-
-PRIVATE_EXTERN const char *CRSetCrashLogMessage(const char *msg)
-{
-    __crashreporter_info__ = msg;
-    return msg;
-}
-PRIVATE_EXTERN const char *CRGetCrashLogMessage(void)
-{
-    return __crashreporter_info__;
-}
-
-PRIVATE_EXTERN const char *CRSetCrashLogMessage2(const char *msg)
-{
-    // sorry
-    return msg;
-}
-
-#endif
-
-// TARGET_OS_MAC
-#else
-
-
-#error unknown OS
-
-
-#endif