• _objc_init Source code parsing

    Look at the sourceThis is basically an initialization of a list of things:

    1. environ_init

      Read environment variables that affect the runtime. You can also print environment variable help if desired. Export OBJC_HELP = 1Flush source code can be found through configurationOBJC_HELPandOBJC_PRINT_OPTIONSTwo environment variables to print all environment variables. A method to configure environment variablestarget -- Edit Scheme -- Run --Arguments -- Environment Variables

      The second way to print environment variables is through the terminal directive export OBJC_hrlp = 1
    2. tls_init

      Bindings for thread keys, such as destructors for per-thread data.
    3. static_init

      Libc will call _objc_init before dyld calls our static constructor, so we have to do it ourselves, and this will only initialize the built-in C++ static constructor, not the ones we wrote in our own code.So the system’s c++ functions are executed before the custom c++ functions
    4. runtime_init

      It is mainly run-time initialization, which is divided into two parts: class initialization and class table initialization
    5. exception_init

      Initialize libobJC’s exception handling systemThe discovery will go to_objc_terminateMethod toTake a look atuncaught_handlerMethod finds that the default is an empty implementationGlobal searchuncaught_handlerFound that callobjc_setUncaughtExceptionHandlerYou can set theuncaught_handlerMethod so application remember crash interception can be setuncaught_handlerMethod interception is also calledobjc_setUncaughtExceptionHandlermethods
    6. cache_init

      Cache initialization
      void cache_init()
      {
      #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
    7. _imp_implementationWithBlock_init

      This method basically starts the callback mechanism, which usually doesn’t do much because all initialization is lazy, but for some processes we can’t wait to load libobjc-trampolines.dylib, whose source code is as follows
      /// Initialize the trampoline machinery. Normally this does nothing, as
      /// everything is initialized lazily, but for certain processes we eagerly load
      /// the trampolines dylib.
      void
      _imp_implementationWithBlock_init(void)
      {
      #if TARGET_OS_OSX
          // Eagerly load libobjc-trampolines.dylib in certain processes. Some
          // programs (most notably QtWebEngineProcess used by older versions of
          // embedded Chromium) enable a highly restrictive sandbox profile which
          // blocks access to that dylib. If anything calls
          // imp_implementationWithBlock (as AppKit has started doing) then we'll
          // crash trying to load it. Loading it here sets it up before the sandbox
          // profile is enabled and blocks it.
          //
          // This fixes EA Origin (rdar://problem/50813789)
          // and Steam (rdar://problem/55286131)
          if (__progname &&
              (strcmp(__progname, "QtWebEngineProcess") == 0 ||
               strcmp(__progname, "Steam Helper") == 0)) {
              Trampolines.Initialize();
          }
      #endif
      }
      Copy the code
    8. _dyld_objc_notify_register

      Dyld registration, specific source code in dyLD source code
      void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped, _dyld_objc_notify_init init, _dyld_objc_notify_unmapped unmapped) { dyld::registerObjCNotifiers(mapped, init, unmapped); } void cnotiFIERS (_dyLD_OBJC_notify_notification, _dyLD_OBJC_notify_init) _dyld_objc_notify_unmapped unmapped) { // record functions to call sNotifyObjCMapped = mapped; sNotifyObjCInit = init; sNotifyObjCUnmapped = unmapped; // call 'mapped' function with all images mapped so far try { notifyBatchPartial(dyld_image_state_bound, true, NULL, false, true); } catch (const char* msg) { // ignore request to abort during registration } // <rdar://problem/32209809> call 'init' function on all images already init'ed (below libSystem) for (std::vector<ImageLoader*>::iterator it=sAllImages.begin();  it ! = sAllImages.end(); it++) { ImageLoader* image = *it; if ( (image->getState() == dyld_image_state_initialized) && image->notifyObjC() ) { dyld3::ScopedTimer timer(DBG_DYLD_TIMING_OBJC_INIT, (uint64_t)image->machHeader(), 0, 0); (*sNotifyObjCInit)(image->getRealPath(), image->machHeader()); }}}Copy the code
  • The association between DYLD and OBJC

    Objc initialization methods are registered with dyLD, which is passed in

    map_imagesThis function is triggered when dyld loads an image into memory

    load_imagesThis function is triggered when dyLD initializes the image

    unmap_imageThis function is triggered when dyld removes the image

    And in dyLD source code inregisterObjCNotifiersMethod source code found that Dyld assigns three methods tosNotifyObjCMapped = mapped; sNotifyObjCInit = init; sNotifyObjCUnmapped = unmapped;The equivalent of

    sNotifyObjCMapped = mapped = map_images

    sNotifyObjCInit = init = load_images

    sNotifyObjCUnmapped = unmapped = unmap_image

    • load_imagesThe loading process of DYLD is analyzed aboveJuejin. Cn/post / 691870…When you knowload_imagesMethod calls in DYLD are just thatsNotifyObjCInitcallsNotifyObjCInitThe call to the notifySingle function is executed in turnnotifySingleThis function is called when the image file is initialized in dyld::main
    • map_imagesThe departure time of the method is known from the above analysismap_imagesFunction calls in dyLD correspond tosNotifyObjCMappedSo global search in dyLD source codesNotifyObjCMappedFound to be innotifyBatchPartialFunction is calledAnd then global searchnotifyBatchPartialWhere the call is foundIs in theregisterObjCNotifiersIt is called when registering the notification, so it is also known heremap_imagesThe delta function is actually_objc_initFunction is called, and also validatedmap_imagesThe execution of theload_imagesPre-function

    Finally, the association between DYLD and OBJC is summarized as follows:

    Registering callback functions in dyLD can be interpreted as adding an observer

    Dyld registration in objC can be understood as sending notifications

    Trigger a callback, which you can think of as executing a notification selector