美文网首页底层
iOS-OC底层11:dyld和objc关联

iOS-OC底层11:dyld和objc关联

作者: MonKey_Money | 来源:发表于2020-10-14 12:08 被阅读0次

前沿

我们知道_objc_init是在dyld加载的流程中被调用的, _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();
    tls_init();
    static_init();
    runtime_init();
    exception_init();
    cache_init();
    _imp_implementationWithBlock_init();

    _dyld_objc_notify_register(&map_images, load_images, unmap_image);

}

environ_init() : 读取影响运行时的环境变量。如果需要,还可以打印环 境变量帮助。
tls_init() 关于线程key的绑定 - 比如每线程数据的析构函数
static_init() 运行C ++静态构造函数。在dyld调用我们的静态构造函数之前,libc 会调用 _objc_init(),因此我们必须自己做
lock_init(): 没有重写,采用C++ 的特性
exception_init () 初始化libobjc的异常处理系统
runtime_init() : runtime运行时环境初始化,里面主要:unattachedCategories,allocatedClasses 后面会分析
cache_init() 缓存条件初始化
_imp_implementationWithBlock_init :启动回调机制。通常这不会做什么,因为所有的初始化都是惰性的,但是对于某些进程,我们会迫不及待地加载trampolines dylib。

environ_init()

在源码environ_init方法中修改一下代码

 for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
        const option_t *opt = &Settings[I];
        _objc_inform("%s is set", opt->env);
    }
打印结果
objc[23909]: OBJC_PRINT_IMAGES is set
objc[23909]: OBJC_PRINT_IMAGE_TIMES is set
objc[23909]: OBJC_PRINT_LOAD_METHODS is set
objc[23909]: OBJC_PRINT_INITIALIZE_METHODS is set
objc[23909]: OBJC_PRINT_RESOLVED_METHODS is set
objc[23909]: OBJC_PRINT_CLASS_SETUP is set
objc[23909]: OBJC_PRINT_PROTOCOL_SETUP is set
objc[23909]: OBJC_PRINT_IVAR_SETUP is set
objc[23909]: OBJC_PRINT_VTABLE_SETUP is set
objc[23909]: OBJC_PRINT_VTABLE_IMAGES is set
objc[23909]: OBJC_PRINT_CACHE_SETUP is set
objc[23909]: OBJC_PRINT_FUTURE_CLASSES is set
objc[23909]: OBJC_PRINT_PREOPTIMIZATION is set
objc[23909]: OBJC_PRINT_CXX_CTORS is set
objc[23909]: OBJC_PRINT_EXCEPTIONS is set
objc[23909]: OBJC_PRINT_EXCEPTION_THROW is set
objc[23909]: OBJC_PRINT_ALT_HANDLERS is set
objc[23909]: OBJC_PRINT_REPLACED_METHODS is set
objc[23909]: OBJC_PRINT_DEPRECATION_WARNINGS is set
objc[23909]: OBJC_PRINT_POOL_HIGHWATER is set
objc[23909]: OBJC_PRINT_CUSTOM_CORE is set
objc[23909]: OBJC_PRINT_CUSTOM_RR is set
objc[23909]: OBJC_PRINT_CUSTOM_AWZ is set
objc[23909]: OBJC_PRINT_RAW_ISA is set
objc[23909]: OBJC_DEBUG_UNLOAD is set
objc[23909]: OBJC_DEBUG_FRAGILE_SUPERCLASSES is set
objc[23909]: OBJC_DEBUG_NIL_SYNC is set
objc[23909]: OBJC_DEBUG_NONFRAGILE_IVARS is set
objc[23909]: OBJC_DEBUG_ALT_HANDLERS is set
objc[23909]: OBJC_DEBUG_MISSING_POOLS is set
objc[23909]: OBJC_DEBUG_POOL_ALLOCATION is set
objc[23909]: OBJC_DEBUG_DUPLICATE_CLASSES is set
objc[23909]: OBJC_DEBUG_DONT_CRASH is set
objc[23909]: OBJC_DISABLE_VTABLES is set
objc[23909]: OBJC_DISABLE_PREOPTIMIZATION is set
objc[23909]: OBJC_DISABLE_TAGGED_POINTERS is set
objc[23909]: OBJC_DISABLE_TAG_OBFUSCATION is set
objc[23909]: OBJC_DISABLE_NONPOINTER_ISA is set
objc[23909]: OBJC_DISABLE_INITIALIZE_FORK_SAFETY is set

我们可以在Edit Scheme->Run->Arguments->Enviroment Variables 增加OBJC_PRINT_LOAD_METHODS为YES
打印结果

objc[25298]: LOAD: category 'CIFilter(Interposer)' scheduled for +load
objc[25298]: LOAD: +[CIFilter(Interposer) load]
objc[25298]: LOAD: class 'NSApplication' scheduled for +load
objc[25298]: LOAD: class 'NSBinder' scheduled for +load
objc[25298]: LOAD: class 'NSColorSpaceColor' scheduled for +load
objc[25298]: LOAD: class 'NSNextStepFrame' scheduled for +load
objc[25298]: LOAD: category 'NSColor(NSUIKitSupport)' scheduled for +load
objc[25298]: LOAD: +[NSApplication load]
objc[25298]: LOAD: +[NSBinder load]
objc[25298]: LOAD: +[NSColorSpaceColor load]
objc[25298]: LOAD: +[NSNextStepFrame load]
objc[25298]: LOAD: +[NSColor(NSUIKitSupport) load]
objc[25298]: LOAD: category 'NSError(FPAdditions)' scheduled for +load

我们可以通过设置环境变量来让xcode打印我们想要的内容
// xcode-select -p 在控制台上查看环境变量
// export OBJC_HELP=1自测的貌似没打印出来,但是xcode-select -p能打印出来环境变量

runtime_init

void runtime_init(void)
{
    objc::unattachedCategories.init(32);
    objc::allocatedClasses.init();
}

unattachedCategories:分类处理的初始化
allocatedClasses,A table of all classes (and metaclasses) which have been allocated with objc_allocateClassPair. 一个已用objc_allocateClassPair分配的所有类(和元类)的表。

exception_init

void exception_init(void)
{
    old_terminate = std::set_terminate(&_objc_terminate);
}
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)();
        }
    }
}
static objc_uncaught_exception_handler uncaught_handler = _objc_default_uncaught_exception_handler;
objc_uncaught_exception_handler 
objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler fn)
{
    objc_uncaught_exception_handler result = uncaught_handler;
    uncaught_handler = fn;
    return result;
}

我们可以使用NSSetUncaughtExceptionHandler来设置

    NSSetUncaughtExceptionHandler(&MyUncaughtExceptionHandler);

接下来我们来分析我们的重头戏_dyld_objc_notify_register,_dyld_objc_notify_register内有两个回调函数,两个回调在dyld的加载调用,在dyld加载流程中我们知道load_images的调用点,现在我们看一下map_images什么时候调用的,
link========>notifyBatch=======>notifyBatchPartial=====>sNotifyObjCMapped
可知map_images是在load_images之前就调用了

map_images

map_images.png

map_images_nolock中有一个函数arr_init();

void arr_init(void) 
{
    AutoreleasePoolPage::init();
    SideTablesMap.init();
    _objc_associations_init();
}
  1. AutoreleasePoolPage::init();对自动释放池的初始化
  2. SideTablesMap.init对管理引用计算map初始化
  3. _objc_associations_init(),对关联对象的散列表进行初始化

read_images

1: 条件控制进行一次的加载if (!doneOnce)
2: 修复预编译阶段的 @selector 的混乱问题 UnfixedSelectors
3: 错误混乱的类处理readClass
4:修复重映射一些没有被镜像文件加载进来的类 remapClassRef
5: 修复一些消息!fixupMessageRef
6: 当我们类里面有协议的时候 : readProtocol
7: 修复没有被加载的协议 remapProtocolRef
8: 分类处理load_categories_nolock
9: 类的加载处理remapClass addClassTableEntry
10 : 没有被处理的类 优化那些被侵犯的类 realizeClassWithoutSwift

相关文章

网友评论

    本文标题:iOS-OC底层11:dyld和objc关联

    本文链接:https://www.haomeiwen.com/subject/tfsipktx.html