preface

  • _objc_initisruntimeInitialize the function inos_objec_initAfter the call

  • _objc_initIn the concrete implementation
void _objc_init(void)

{
    static bool initialized = false;

    if (initialized) return;

    initialized = true;

    // fixme defer initialization until an objc-using image is found?

    // Environment variables are initialized

    environ_init();

    // Thread key binding

    tls_init();

    // call the C++ constructor in libc before dylb calls the constructor

    static_init();

    // The runtime environment is initialized

    runtime_init();

    // Exception handling

    exception_init();

#if __OBJC2__

    // Cache initialization

    cache_t::init();

#endif

    // Perform the callback

    _imp_implementationWithBlock_init();

    // DyLD register notification, dyLD call registerObjCNotifiers

    // Map_images () is called immediately after registration.

    Enum DYLD_image_states {dyLD_image_state_mapped = 10, // No batch notification for this dyld_image_state_dependents_mapped = 20, // Only Batch notification for this is sent Only once. dyld_image_state_dependents_initialized = 45, // Only single notification for this dyld_image_state_initialized = 50, dyld_image_state_terminated = 60 // Only single notification for this }; * /

    // _dyld_start -> main -> instantiateFromLoadedImage -> ImageLoaderMachO::instantiateMainExecutable -> setMapped -> FState = dyLD_IMAGE_STATE_mapped Import is not a UUID for the shared cache image

    // _dyld_start -> main(...) -> link(...) -> ImageLoader::Link(...) -> ImageLoader:: recursiveLoadLibraries -> fState = dyLD_IMAGe_STATE_dependentS_Mapped Image Dependency load, then register into the kernel

    // _dyld_start -> main(...) -> link(...) -> ImageLoader::Link(...) -> ImageLoader::recursiveRebaseWithAccounting -> ImageLoader::recursiveRebase -> fState = dyld_image_state_rebased; Rebase image dependencies and images

    // _dyld_start -> main(...) -> ImageLoader::recursiveBind -> fState = dyld_image_state_bound; Bind image dependencies to image

    // _dyld_start -> main(...) -> initializeMainExecutable() -> ImageLoader::runInitializers -> ImageLoader::processInitializers -> ImageLoader: : recursiveInitialization () - > fState = dyld_image_state_dependents_initialized (began to initialize the image) - > DoInitialization (initialize image) -> Whether libSystem is initialized -
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
#if __OBJC2__

    didCallDyldNotifyRegister = true;

#endif
}
Copy the code

Analysis of the

static bool initialized = false;

if (initialized) return;

initialized = true;
Copy the code
  • This is easy to understand, use a static variable to mark if it has been initialized, if it has been initialized, directlyreturn

environ_init();

  • Environment variable initialization, which can be configured inxcodeAccording to their own needs inlldbPrint out the variables you need to debug
  • Input at terminalexport OBJC_HELP=1export OBJC_PRINT_OPTIONS=1, you can print out environment variables and their corresponding descriptions

  • And then you canxcodeConfiguration, which is configured below to print all callsloadPlace of method

Dyld environment variable

const char* const * DYLD_FRAMEWORK_PATH;

const char* const * DYLD_FALLBACK_FRAMEWORK_PATH;

const char* const * DYLD_LIBRARY_PATH;

const char* const * DYLD_FALLBACK_LIBRARY_PATH;

const char* const * DYLD_INSERT_LIBRARIES;

const char* const * LD_LIBRARY_PATH; // for unix conformance

const char* const * DYLD_VERSIONED_LIBRARY_PATH;

const char* const * DYLD_VERSIONED_FRAMEWORK_PATH;

bool DYLD_PRINT_LIBRARIES_POST_LAUNCH;

bool DYLD_BIND_AT_LAUNCH;

bool DYLD_PRINT_STATISTICS; // Print time

bool DYLD_PRINT_STATISTICS_DETAILS;

bool DYLD_PRINT_OPTS;

bool DYLD_PRINT_ENV; // Prints all variables

bool DYLD_DISABLE_DOFS;

bool hasOverride;
Copy the code

tls_init();

void tls_init(void)

{

#if SUPPORT_DIRECT_THREAD_KEYS
    pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
#else
    _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);

#endif
}
Copy the code
  • Thread Key binding
  • Set the destructor_objc_pthread_destroyspecific

static_init();

  • calllibobjcAll of theC++Constructor, before dyLB calls the constructor
/ / such as
__attribute__((constructor))
static void defineLockOrder(a) {}Copy the code

runtime_init();

void runtime_init(void)
{
    objc::unattachedCategories.init(32);
    objc::allocatedClasses.init();
}
Copy the code
  • I initialized two of themtable
  • unattachedCategories: Unrecognized classification table
  • allocatedClasses: a list of all classes and metaclasses that have been opened up

exception_init();

static void _objc_terminate(void) { if (PrintExceptions) { _objc_inform("EXCEPTIONS: terminating"); } if (! __cxa_current_exception_type()) { // No current exception. (*old_terminate)(); } else { // There is a current exception. Check if it's an objc exception. @try { __cxa_rethrow(); } @catch (id e) {// It's an objc object. Call Foundation's handler, if any. (*old_terminate)(); } @catch (...) { // It's not an objc object. Continue to C++ terminate. (*old_terminate)(); }}}Copy the code
  • The followingarArray is out of bounds, we can useNSSetUncaughtExceptionHandler(&fn)To throw an exception, find useful information, and pass it to our server for analysis

  • uncaught_handlerIs in theobjc_setUncaughtExceptionHandlerThe assignment of
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *! [image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f1a876aa45b649a4b18f47d04d5fc891~tplv-k3u1fbpfcp-watermark .image) * objc_setUncaughtExceptionHandler * Set a handler for uncaught Objective-C exceptions. * Returns the previous handler. **********************************************************************/ objc_uncaught_exception_handler objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler fn) { objc_uncaught_exception_handler result = uncaught_handler; uncaught_handler = fn; return result; }Copy the code

  • objc_setUncaughtExceptionHandlerinCoreFoundtionCalled after initialization
  • This specific process still needs to be explored in detail, so far it has only been studied here

cache_t::init();

  • Related initialization of cache information
void cache_t::init(a)
{
#if HAVE_TASK_RESTARTABLE_RANGES
    mach_msg_type_number_t count = 0;
    kern_return_t kr;
    while (objc_restartableRanges[count].location) {

        count++;

    }
    kr = task_restartable_ranges_register(mach_task_self(),

                                          objc_restartableRanges, count);
    if (kr == KERN_SUCCESS) return;
    _objc_fatal("task_restartable_ranges_register failed (result 0x%x: %s)",

                kr, mach_error_string(kr));
#endif // HAVE_TASK_RESTARTABLE_RANGES
}
Copy the code
  • HAVE_TASK_RESTARTABLE_RANGES
#if TARGET_OS_SIMULATOR || defined(__i386__) || defined(__arm__) || ! TARGET_OS_MAC # define HAVE_TASK_RESTARTABLE_RANGES 0 #else # define HAVE_TASK_RESTARTABLE_RANGES 1 #endifCopy the code
  • iOSThis systeminitNothing

_imp_implementationWithBlock_init();

  • Generally no effect, not research

_dyld_objc_notify_register(&map_images, load_images, unmap_image);

  • todyldcallmao_images.load_images.unmap_image, depending on the application load