OC底层探索(十八):_objc_init

885 阅读3分钟

前言

  • _objc_initruntime初始化的函数,在os_objec_init之后调用 image.png
  • _objc_init里的具体实现
void _objc_init(void)

{
    static bool initialized = false;

    if (initialized) return;

    initialized = true;

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

    // 环境变量初始化

    environ_init();

    //线程key的绑定

    tls_init();

    //调用 libc 中 C++ 构造函数,在 dylb调用构造函数之前

    static_init();

    //运行时环境初始化

    runtime_init();

    // 异常处理

    exception_init();

#if __OBJC2__

    //缓存初始化

    cache_t::init();

#endif

    //执行回调

    _imp_implementationWithBlock_init();

    // dyld 注册通知, dyld 调用 registerObjCNotifiers

    // 注册时,马上调用了 map_images()

    /* image 的几种状态

     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 只发送一次

        dyld_image_state_rebased                = 30,

        dyld_image_state_bound                    = 40,

        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 导入不是共享缓存 image 的 UUID

    // _dyld_start -> main(...) -> link(...) -> ImageLoader::Link(...) -> ImageLoader:: recursiveLoadLibraries -> fState = dyld_image_state_dependents_mapped  image依赖加载,然后注册到内核中

    // _dyld_start -> main(...) -> link(...) -> ImageLoader::Link(...) -> ImageLoader::recursiveRebaseWithAccounting -> ImageLoader::recursiveRebase -> fState = dyld_image_state_rebased; 对image的依赖及image进行Rebase

    // _dyld_start -> main(...) -> ImageLoader::recursiveBind ->  fState = dyld_image_state_bound; 对image的依赖及image进行绑定

    //  _dyld_start -> main(...) -> initializeMainExecutable() -> ImageLoader::runInitializers -> ImageLoader::processInitializers -> ImageLoader::recursiveInitialization() -> fState = dyld_image_state_dependents_initialized(开始初始化 image) -> doInitialization(初始化image) -> libSystem是否初始化 -
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
#if __OBJC2__

    didCallDyldNotifyRegister = true;

#endif
}

分析

static bool initialized = false;

if (initialized) return;

initialized = true;
  • 这个很好理解,用一个静态变量标记有没初始化过,已经初始化了的话,直接return

environ_init();

  • 环境变量初始化,这个可以配置在xcode里,根据自己的需求在lldb打印出自己需要调试的变量
  • 在终端输入 export OBJC_HELP=1export OBJC_PRINT_OPTIONS=1,可以打印出环境变量和对应的描述

Screen Shot 2021-07-18 at 12.59.24 PM.png

Screen Shot 2021-07-18 at 12.59.55 PM.png

  • 然后可以在xcode配置, 下面配置了打印所有调用load方法的地方

Screen Shot 2021-07-18 at 1.12.09 PM.png

Screen Shot 2021-07-18 at 1.13.11 PM.png

dyld 环境变量

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; // 打印时间

bool DYLD_PRINT_STATISTICS_DETAILS;

bool DYLD_PRINT_OPTS;

bool DYLD_PRINT_ENV; // 打印所有变量

bool DYLD_DISABLE_DOFS;

bool hasOverride;

Screen Shot 2021-07-18 at 1.38.14 PM.png

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
}
  • 线程Key的绑定
  • 设置析构函数 _objc_pthread_destroyspecific

static_init();

  • 调用 libobjc 中的所有 C++ 构造函数,在 dylb调用构造函数之前
// 例如
__attribute__((constructor))
static void defineLockOrder() {
}

runtime_init();

void runtime_init(void)
{
    objc::unattachedCategories.init(32);
    objc::allocatedClasses.init();
}
  • 初始化了两张
  • unattachedCategories: 未被识别的分类表
  • allocatedClasses: 已经开辟的所有类和元类的表

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.
            // 这里会抛出异常
            (*uncaught_handler)((id)e);
            (*old_terminate)();

        } @catch (...) {
            // It's not an objc object. Continue to C++ terminate.
            (*old_terminate)();
        }
    }
}
  • 下面的ar数组是越界,我们可以用NSSetUncaughtExceptionHandler(&fn)来抛出异常,找到有用的信息,传给我们的服务器,以便分析 image.png

image.png

  • uncaught_handler是在objc_setUncaughtExceptionHandler赋值的
/***********************************************************************

![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;
}

image.png

  • objc_setUncaughtExceptionHandlerCoreFoundtion初始化之后就调用了
  • 这个具体的流程还需要在具体探索一下,目前只研究到这了

cache_t::init();

  • 缓存信息的相关初始化
void cache_t::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
}
  • 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
#endif
  • iOS系统这个init什么都没做

_imp_implementationWithBlock_init();

  • 一般没什么作用,不研究

_dyld_objc_notify_register(&map_images, load_images, unmap_image);

  • 交给dyld 调用 mao_images, load_images, unmap_image, 具体可以看应用程序加载