添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

前面我们介绍了Mach O的结构,App的启动,dyld的加载,以及通过dyld将镜像加载进来,经过rebase/Bind处理后,找到main入口,以及Runtime相关的数据结构,有了前面的一系列铺垫这里介绍Runtime初始化就显得相对轻松了,这篇博客我们从《iOS Runtime源码解析之dyld》结尾处接着介绍,《iOS Runtime源码解析之dyld》中介绍了从dyld入口__dyld_start作为起点,到找到并跳转到主函数入口期间的一系列工作:

1. 将主程序初始化为imageLoader
2. 加载共享库到内存
3. 加载插入的动态库
4. 链接主程序,链接插入库
5. 初始化主程序,插入库
6. 寻找主程序入口点

这篇博客和《iOS Runtime源码解析之dyld》的衔接点就在于第5步初始化主程序,插入库这一步,在这个阶段,会调用使用attribute((constructor) 进行修饰的方法,其中有个十分重要的动态库初始化方法, libSystem_initializer

static __attribute__((constructor)) 
void libSystem_initializer(int argc, const char* argv[], const char* envp[], const char* apple[], const struct ProgramVars* vars) {

//......

_libkernel_init(libkernel_funcs);

bootstrap_init();
mach_init();
pthread_init();
__libc_init(vars, libSystem_atfork_prepare, libSystem_atfork_parent, libSystem_atfork_child, apple);
__keymgr_initializer();
_dyld_initializer();
libdispatch_init();
_libxpc_initializer();

__stack_logging_early_finished();
//.......
errno = 0;
}

在libSystem.dylib的初始化方法libSystem_initializer中初始化了多了dylib库,比如:liblaunch.dylib,libc.a,libdispatch.a等等,这里最关键的是**** libdispatch_init ****:

void libdispatch_init(void) {
//......
_os_object_init();
}

在libdispatch_init的最后部分会调用****_os_object_init****:

void
_os_object_init(void)
{
return _objc_init();
}

_os_object_init 方法只有一行代码就是转调_objc_init,这就是我们十分关注的Runtime 初始化的入口。


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();
lock_init();
exception_init();

//_dyld_objc_notify_register(&map_2_images, load_images, unmap_image);
//向dyld注册了回调函数,当imagemap到内存中,当初始化完成image时和卸载image的时候都会回调注册者
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
}

_objc_init 向dyld注册了map_images,load_images,unmap_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_objc_notify_register****这个方法的注释,通过注释我们可以了解到,在runtime中可以通过这个方法可以向dyld注册用于处理镜像完成映射,取消映射和初始化之后的处理方法。

//
// Note: only for use by objc runtime
// Register handlers to be called when objc images are mapped, unmapped, and initialized.
// Dyld will call back the "mapped" function with an array of images that contain an objc-image-info section.
// Those images that are dylibs will have the ref-counts automatically bumped, so objc will no longer need to
// call dlopen() on them to keep them from being unloaded. During the call to _dyld_objc_notify_register(),
// dyld will call the "mapped" function with already loaded objc images. During any later dlopen() call,
// dyld will also call the "mapped" function. Dyld will call the "init" function when dyld would be called
// initializers in that image. This is when objc calls any +load methods in that image.
// 通过这个方法可以向dyld注册用于处理镜像完成映射,取消映射和初始化之后的处理方法。

void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,
_dyld_objc_notify_init init,
_dyld_objc_notify_unmapped unmapped);

我们重点关注下****_dyld_objc_notify_mapped 以及 _dyld_objc_notify_init****,

  • _dyld_objc_notify_mapped
  • map_images 会在主程序以及其他库加载进来后调用 ImageLoader::setMapped 发出通知,调用map_images:

    void ImageLoader::setMapped(const LinkContext& context)
    {
    fState = dyld_image_state_mapped;
    context.notifySingle(dyld_image_state_mapped, this); // note: can throw exception
    }

    ImageLoader::setMapped 会在instantiateMainExecutable实例话主程序,instantiateFromFile实例化镜像的时候被调用:

  • _dyld_objc_notify_init
  • 会在 ImageLoader::runInitializers 方法中被调用,而 ImageLoader::runInitializers 则会在 initializeMainExecutable 中调用。

    也即是说在实例化主程序或者其他dylib库的时候都会发出_dyld_objc_notify_mapped通知,这时候会调用runtime 的 map_images方法进行后续处理,在这些初始化完成的时候会发出_dyld_objc_notify_init通知调用load_images方法进行后续处理。

    我们紧接着来看下 map_images 以及 load_images 的处理,其实在介绍分类的时候已经介绍过了map_images这里为保证整个文章的完整性再过一遍这部分内容:

  • map_images
  • void
    map_images(unsigned count, const char * const paths[],
    const struct mach_header * const mhdrs[])
    {
    mutex_locker_t lock(runtimeLock);
    return map_images_nolock(count, paths, mhdrs);
    }

    void 
    map_images_nolock(unsigned mhCount, const char * const mhPaths[],
    const struct mach_header * const mhdrs[])
    {
    //......
    if (hCount > 0) {
    //读取镜像信息
    _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
    }
    firstTime = NO;
    }

    void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses)
    {
    //......

    // =================================查找classes=================================
    // Discover classes. Fix up unresolved future classes. Mark bundle classes.
    for (EACH_HEADER) {
    //从Mach-O的 __DATA区 __objc_classlist 获取所有类,并加入gdb_objc_realized_classes list中
    classref_t *classlist = _getObjc2ClassList(hi, &count);
    //.......
    for (i = 0; i < count; i++) {
    Class cls = (Class)classlist[i];
    Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);

    if (newCls != cls && newCls) {
    // 类被移动了但是没有被删除的情况
    // Class was moved but not deleted. Currently this occurs
    // only when the new class resolved a future class.
    // Non-lazily realize the class below.
    resolvedFutureClasses = (Class *)realloc(resolvedFutureClasses, (resolvedFutureClassCount+1) * sizeof(Class));
    resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
    }
    }
    }

    ts.log("IMAGE TIMES: discover classes");

    // 修复重新映射的类
    // Fix up remapped classes
    // Class list and nonlazy class list remain unremapped.
    // Class refs and super refs are remapped for message dispatching.

    if (!noClassesRemapped()) {
    for (EACH_HEADER) {
    Class *classrefs = _getObjc2ClassRefs(hi, &count);
    for (i = 0; i < count; i++) {
    remapClassRef(&classrefs[i]);
    }
    // fixme why doesn't test future1 catch the absence of this?
    classrefs = _getObjc2SuperRefs(hi, &count);
    for (i = 0; i < count; i++) {
    remapClassRef(&classrefs[i]);
    }
    }
    }

    // 重新映射类
    ts.log("IMAGE TIMES: remap classes");

    // Fix up @selector references
    static size_t UnfixedSelectors;
    {
    mutex_locker_t lock(selLock);
    for (EACH_HEADER) {
    if (hi->isPreoptimized()) continue;

    bool isBundle = hi->isBundle();
    SEL *sels = _getObjc2SelectorRefs(hi, &count);
    UnfixedSelectors += count;
    for (i = 0; i < count; i++) {
    const char *name = sel_cname(sels[i]);
    // 3. 注册Sel,并存储到全局变量namedSelectors的list中
    sels[i] = sel_registerNameNoLock(name, isBundle);
    }
    }
    }

    ts.log("IMAGE TIMES: fix up selector references");

    //.....

    // Discover protocols. Fix up protocol refs.
    for (EACH_HEADER) {
    extern objc_class OBJC_CLASS_$_Protocol;
    Class cls = (Class)&OBJC_CLASS_$_Protocol;
    assert(cls);
    NXMapTable *protocol_map = protocols();
    bool isPreoptimized = hi->isPreoptimized();
    bool isBundle = hi->isBundle();
    //找到所有Protocol并处理引用
    protocol_t **protolist = _getObjc2ProtocolList(hi, &count);
    for (i = 0; i < count; i++) {
    readProtocol(protolist[i], cls, protocol_map,
    isPreoptimized, isBundle);
    }
    }

    ts.log("IMAGE TIMES: discover protocols");

    // Fix up @protocol references
    // Preoptimized images may have the right
    // answer already but we don't know for sure.
    for (EACH_HEADER) {
    protocol_t **protolist = _getObjc2ProtocolRefs(hi, &count);
    for (i = 0; i < count; i++) {
    remapProtocolRef(&protolist[i]);
    }
    }

    ts.log("IMAGE TIMES: fix up @protocol references");

    // Realize non-lazy classes (for +load methods and static instances)
    for (EACH_HEADER) {
    classref_t *classlist =
    _getObjc2NonlazyClassList(hi, &count);
    for (i = 0; i < count; i++) {
    Class cls = remapClass(classlist[i]);
    if (!cls) continue;
    addClassTableEntry(cls);
    realizeClass(cls);
    }
    }

    ts.log("IMAGE TIMES: realize non-lazy classes");

    // Realize newly-resolved future classes, in case CF manipulates them
    if (resolvedFutureClasses) {
    for (i = 0; i < resolvedFutureClassCount; i++) {
    realizeClass(resolvedFutureClasses[i]);
    resolvedFutureClasses[i]->setInstancesRequireRawIsa(false/*inherited*/);
    }
    free(resolvedFutureClasses);
    }

    ts.log("IMAGE TIMES: realize future classes");

    // Discover categories.
    for (EACH_HEADER) {
    category_t **catlist =
    _getObjc2CategoryList(hi, &count);
    //查看是否包含属性
    bool hasClassProperties = hi->info()->hasCategoryClassProperties();

    for (i = 0; i < count; i++) {
    category_t *cat = catlist[i];
    //获取到所属的类
    Class cls = remapClass(cat->cls);

    if (!cls) {
    // Category's target class is missing (probably weak-linked).
    // Disavow any knowledge of this category.
    catlist[i] = nil;
    if (PrintConnecting) {
    _objc_inform("CLASS: IGNORING category \?\?\?(%s) %p with "
    "missing weak-linked target class",
    cat->name, cat);
    }
    continue;
    }

    // Process this category.
    // First, register the category with its target class.
    // Then, rebuild the class's method lists (etc) if
    // the class is realized.
    bool classExists = NO;
    //如果有实例方法,协议或者实例属性
    if (cat->instanceMethods || cat->protocols
    || cat->instanceProperties)
    {
    addUnattachedCategoryForClass(cat, cls, hi);
    if (cls->isRealized()) {
    //将分类添到属性,方法,协议添加到对应的类中
    remethodizeClass(cls);
    classExists = YES;
    }
    if (PrintConnecting) {
    _objc_inform("CLASS: found category -%s(%s) %s",
    cls->nameForLogging(), cat->name,
    classExists ? "on existing class" : "");
    }
    }
    //如果有类方法,协议或者类属性
    if (cat->classMethods || cat->protocols
    || (hasClassProperties && cat->_classProperties))
    {
    addUnattachedCategoryForClass(cat, cls->ISA(), hi);
    if (cls->ISA()->isRealized()) {
    remethodizeClass(cls->ISA());
    }
    if (PrintConnecting) {
    _objc_inform("CLASS: found category +%s(%s)",
    cls->nameForLogging(), cat->name);
    }
    }
    }
    }

    ts.log("IMAGE TIMES: discover categories");

    // Category discovery MUST BE LAST to avoid potential races
    // when other threads call the new category code before
    // this thread finishes its fixups.

    // +load handled by prepare_load_methods()

    if (DebugNonFragileIvars) {
    realizeAllClasses();
    }
    //......
    }

    map_images 最关键的代码在_read_images方法中,****_read_images 故名思议就是读取镜像,在这个方法中会从镜像的_DATA区域通过 _getObjc2XXXX****将该镜像的类列表,分类列表,协议列表读取出来,对应的方法以及读取的session部分可以查看如下声明,这里需要提一下_DATA区域中的这些session数据是由编译器写入的。

    //      function name                 content type     section name
    GETSECT(_getObjc2SelectorRefs, SEL, "__objc_selrefs");
    GETSECT(_getObjc2MessageRefs, message_ref_t, "__objc_msgrefs");
    GETSECT(_getObjc2ClassRefs, Class, "__objc_classrefs");
    GETSECT(_getObjc2SuperRefs, Class, "__objc_superrefs");
    GETSECT(_getObjc2ClassList, classref_t, "__objc_classlist");
    GETSECT(_getObjc2NonlazyClassList, classref_t, "__objc_nlclslist");
    GETSECT(_getObjc2CategoryList, category_t *, "__objc_catlist");
    GETSECT(_getObjc2NonlazyCategoryList, category_t *, "__objc_nlcatlist");
    GETSECT(_getObjc2ProtocolList, protocol_t *, "__objc_protolist");
    GETSECT(_getObjc2ProtocolRefs, protocol_t *, "__objc_protorefs");
    GETSECT(getLibobjcInitializers, UnsignedInitializer, "__objc_init_func");

    这个方法的每个阶段结束都会调用ts.log(“IMAGE TIMES:XXXXXX)来提示每个阶段结束,在这些阶段中有我们之前分析过的Catogies 加载,以及协议加载。我们重点看下最末尾的realizeAllClasses方法:

    static void realizeAllClasses(void)
    {
    runtimeLock.assertLocked();
    header_info *hi;
    for (hi = FirstHeader; hi; hi = hi->getNext()) {
    realizeAllClassesInImage(hi);
    }
    }
    static void realizeAllClassesInImage(header_info *hi) {

    runtimeLock.assertLocked();

    size_t count, i;
    classref_t *classlist;

    if (hi->areAllClassesRealized()) return;

    classlist = _getObjc2ClassList(hi, &count);

    for (i = 0; i < count; i++) {
    realizeClass(remapClass(classlist[i]));
    }

    hi->setAllClassesRealized(YES);
    }

    realizeAllClasses会对镜像中的所有class调用realizeClass方法。

    static Class realizeClass(Class cls) {

    //.....
    const class_ro_t *ro;
    class_rw_t *rw;
    Class supercls;
    Class metacls;
    bool isMeta;

    if (!cls) return nil; //cls 不能为空
    if (cls->isRealized()) return cls; //cls 如果已经初始化直接返回
    assert(cls == remapClass(cls)); //cls 没有重新分配,remapClass 返回指向cls的实时指针
    // 【✨】获取只读结构体
    ro = (const class_ro_t *)cls->data();

    // Normal class. Allocate writeable class data.
    rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1); //分配读写数据
    rw->ro = ro; //只写数据
    rw->flags = RW_REALIZED|RW_REALIZING; //设置已经初始化标志
    cls->setData(rw); //为cls设置data数据

    isMeta = ro->flags & RO_META; //判断是否是元类
    rw->version = isMeta ? 7 : 0; // old runtime went up to 6 //版本信息,旧版本的版本信息为6

    //.....
    // Realize superclass and metaclass, if they aren't already.
    // This needs to be done after RW_REALIZED is set above, for root classes.
    // This needs to be done after class index is chosen, for root metaclasses.
    // 【✨】为supercls,metacls 分配空间
    supercls = realizeClass(remapClass(cls->superclass));
    metacls = realizeClass(remapClass(cls->ISA()));

    //......

    // 【✨】 Update superclass and metaclass in case of remapping
    cls->superclass = supercls; //将supercls赋给 cls->superclass
    //将上面分配的metacls赋给cls
    cls->initClassIsa(metacls);

    // 调整实例变量的偏移和布局,这个将会重新分配class_ro_t
    // Reconcile instance variable offsets / layout.
    // This may reallocate class_ro_t, updating our ro variable.
    if (supercls && !isMeta) reconcileInstanceVariables(cls, supercls, ro);

    //设置对象尺寸
    // Set fastInstanceSize if it wasn't set already.
    cls->setInstanceSize(ro->instanceSize);

    //【✨】从ro中拷贝部分标志位到rw 字段
    // Copy some flags from ro to rw
    if (ro->flags & RO_HAS_CXX_STRUCTORS) {
    cls->setHasCxxDtor();
    if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
    cls->setHasCxxCtor();
    }
    }

    // 【✨】 Connect this class to its superclass's subclass lists
    // 将当前class与父类相关连
    if (supercls) {
    //将当前类作为supercls的子类添加到父类的子类列表
    addSubclass(supercls, cls);
    } else {
    //将当前类作为根类
    addRootClass(cls);
    }

    //【✨】实例化类结构
    // Attach categories
    // 使得类有条理
    methodizeClass(cls);

    return cls;
    }

    realizeClass 方法实际上是为类的class_rw_t,superclass,metacls等分配空间,并初始化。在最后的时候会调用methodizeClass进行进一步的初始化:

    static void methodizeClass(Class cls)
    {
    //检查锁
    runtimeLock.assertLocked();
    //是否是元类
    bool isMeta = cls->isMetaClass();
    //获取可读写字段
    auto rw = cls->data();
    //获取只读字段
    auto ro = rw->ro;

    // Install methods and properties that the class implements itself.
    // 加载类自身实现的方法和属性
    method_list_t *list = ro->baseMethods();
    if (list) {
    prepareMethodLists(cls, &list/*自身实现的方法列表*/, 1, YES, isBundleClass(cls));
    //将ro->baseMethods方法添加到rw->methods
    rw->methods.attachLists(&list, 1);
    }

    property_list_t *proplist = ro->baseProperties;
    if (proplist) {
    //将ro->baseProperties方法添加到rw->properties
    rw->properties.attachLists(&proplist, 1);
    }

    protocol_list_t *protolist = ro->baseProtocols;
    if (protolist) {
    //将ro->baseProtocols方法添加到rw->protocols
    rw->protocols.attachLists(&protolist, 1);
    }

    // Root classes get bonus method implementations if they don't have
    // them already. These apply before category replacements.
    if (cls->isRootMetaclass()) {
    // root metaclass
    addMethod(cls, SEL_initialize, (IMP)&objc_noop_imp, "", NO);
    }

    // Attach categories.
    // 获取未添加的分类
    category_list *cats = unattachedCategoriesForClass(cls, true /*realizing*/);
    // 添加分类
    attachCategories(cls, cats, false /*don't flush caches*/);

    //.....

    if (cats) free(cats);
    //.....
    }

    methodizeClass方法则进一步初始化rw,这一步将ro中的属性,协议,方法拷贝到rw,以及将分类中对应的属性,协议,方法也拷贝到class中的rw对应字段。

    回顾整个map_image阶段就是在镜像实例话结束后,通过读取_DATA中的指定session数据,来读出整个镜像中各个class的关键数据,并构建objc_class数据结构对象,通过从_DATA中读取的数据来填充objc_class来完成整个类的实例化。

  • load_images
  • load方法是我们在日常开发中可以接触到的调用时间最靠前的方法,它的调用不是惰性的,在主函数运行之前,load 方法就会调用,并且它只会在程序调用期间调用一次,最重要的是,如果在类与分类中都实现了 load 方法,它们都会被调用,
    不像其它的在分类中实现的方法会被覆盖,但是在使用load方法的时候需要注意,由于load方法的运行时间过早,所以可能不是一个理想的环境,因为它不能保证某些类可能需要在在其它类之前加载,但是在这个时间点,所有的 framework 都已经加载到了运行时中,所以调用 framework 中的方法都是安全的,同时需要注意的是重载Class 的 +load 方法时不能调父类super,我们来看下这部分逻辑:

    void
    load_images(const char *path __unused, const struct mach_header *mh)
    {
    //......
    // Discover load methods
    {
    mutex_locker_t lock2(runtimeLock);
    //prepare_load_methods方法中对load方法进行了前期准备
    prepare_load_methods((const headerType *)mh);
    }
    // 调用+load方法
    // Call +load methods (without runtimeLock - re-entrant)
    call_load_methods();
    }

    load_images 方法中主要调用了prepare_load_methods 以及 call_load_methods

    void prepare_load_methods(const headerType *mhdr)
    {
    //....
    //获取类
    classref_t *classlist =
    _getObjc2NonlazyClassList(mhdr, &count);
    for (i = 0; i < count; i++) {
    schedule_class_load(remapClass(classlist[i]));
    }

    //添加分类
    category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
    for (i = 0; i < count; i++) {
    category_t *cat = categorylist[i];
    Class cls = remapClass(cat->cls);
    if (!cls) continue; // category for ignored weak-linked class
    realizeClass(cls);
    assert(cls->ISA()->isRealized());
    add_category_to_loadable_list(cat);
    }
    }
    static void schedule_class_load(Class cls)
    {
    if (!cls) return;
    assert(cls->isRealized()); // _read_images should realize

    if (cls->data()->flags & RW_LOADED) return;

    //先加载父类
    // Ensure superclass-first ordering
    //分析这段代码,可以知道,在将子类添加到加载列表之前,其父类一定会优先加载到列表中。
    //这也是为何父类的+load方法在子类的+load方法之前调用的根本原因。
    schedule_class_load(cls->superclass);
    //将类添加到可加载列表
    add_class_to_loadable_list(cls);
    cls->setInfo(RW_LOADED);
    }

    prepare_load_methods 以及 schedule_class_load方法会按照父类,子类,分类的顺序将需要调用load方法的class添加到loadable_list中去

    void add_class_to_loadable_list(Class cls)
    {
    IMP method;

    loadMethodLock.assertLocked();

    //该类是否有load方法
    method = cls->getLoadMethod();
    if (!method) return; // Don't bother if cls has no +load method

    //........
    if (loadable_classes_used == loadable_classes_allocated) {
    loadable_classes_allocated = loadable_classes_allocated*2 + 16;
    loadable_classes = (struct loadable_class *)
    realloc(loadable_classes,
    loadable_classes_allocated *
    sizeof(struct loadable_class));
    }

    loadable_classes[loadable_classes_used].cls = cls;
    loadable_classes[loadable_classes_used].method = method;
    loadable_classes_used++;
    }
    void add_category_to_loadable_list(Category cat)
    {
    IMP method;

    loadMethodLock.assertLocked();

    //该分类是否有load方法
    method = _category_getLoadMethod(cat);

    if (!method) return;

    if (loadable_categories_used == loadable_categories_allocated) {
    loadable_categories_allocated = loadable_categories_allocated*2 + 16;
    loadable_categories = (struct loadable_category *)
    realloc(loadable_categories,
    loadable_categories_allocated *
    sizeof(struct loadable_category));
    }

    loadable_categories[loadable_categories_used].cat = cat;
    loadable_categories[loadable_categories_used].method = method;
    loadable_categories_used++;
    }

    调用类以及分类中的load方法

    /***********************************************************************
    * call_load_methods
    * Call all pending class and category +load methods.
    * Class +load methods are called superclass-first.
    * Category +load methods are not called until after the parent class's +load.
    *
    * This method must be RE-ENTRANT, because a +load could trigger
    * more image mapping. In addition, the superclass-first ordering
    * must be preserved in the face of re-entrant calls. Therefore,
    * only the OUTERMOST call of this function will do anything, and
    * that call will handle all loadable classes, even those generated
    * while it was running.
    *
    * The sequence below preserves +load ordering in the face of
    * image loading during a +load, and make sure that no
    * +load method is forgotten because it was added during
    * a +load call.
    * Sequence:
    * 1. Repeatedly call class +loads until there aren't any more
    * 2. Call category +loads ONCE.
    * 3. Run more +loads if:
    * (a) there are more classes to load, OR
    * (b) there are some potential category +loads that have
    * still never been attempted.
    * Category +loads are only run once to ensure "parent class first"
    * ordering, even if a category +load triggers a new loadable class
    * and a new loadable category attached to that class.
    *
    * Locking: loadMethodLock must be held by the caller
    * All other locks must not be held.
    **********************************************************************/
    void call_load_methods(void)
    {
    static bool loading = NO;
    bool more_categories;

    loadMethodLock.assertLocked();

    // Re-entrant calls do nothing; the outermost call will finish the job.
    if (loading) return;
    loading = YES;

    void *pool = objc_autoreleasePoolPush();

    do {
    // 1. Repeatedly call class +loads until there aren't any more
    while (loadable_classes_used > 0) {
    //调用类的load方法
    call_class_loads();
    }

    // 2. Call category +loads ONCE
    //调用分类的load方法
    more_categories = call_category_loads();

    // 3. Run more +loads if there are classes OR more untried categories
    } while (loadable_classes_used > 0 || more_categories);

    objc_autoreleasePoolPop(pool);

    loading = NO;
    }
    static void call_class_loads(void)
    {
    // Detach current loadable list.
    struct loadable_class *classes = loadable_classes;/*这是preppare阶段构造的*/
    int used = loadable_classes_used;
    loadable_classes = nil;
    loadable_classes_allocated = 0;
    loadable_classes_used = 0;

    // Call all +loads for the detached list.
    for (i = 0; i < used; i++) {
    Class cls = classes[i].cls;

    load_method_t load_method = (load_method_t)classes[i].method;
    if (!cls) continue;

    if (PrintLoading) {
    _objc_inform("LOAD: +[%s load]\n", cls->nameForLogging());
    }
    //调用+load方法
    (*load_method)(cls, SEL_load);
    }

    // Destroy the detached list.
    if (classes) free(classes);
    }
    static bool call_category_loads(void)
    {
    int i, shift;
    bool new_categories_added = NO;

    // Detach current loadable list.
    struct loadable_category *cats = loadable_categories;/*数据来源 在prepare阶段构建*/
    int used = loadable_categories_used;
    int allocated = loadable_categories_allocated;
    loadable_categories = nil;
    loadable_categories_allocated = 0;
    loadable_categories_used = 0;

    // Call all +loads for the detached list.
    for (i = 0; i < used; i++) {
    Category cat = cats[i].cat;
    load_method_t load_method = (load_method_t)cats[i].method;
    Class cls;
    if (!cat) continue;

    cls = _category_getClass(cat);
    if (cls && cls->isLoadable()) {
    if (PrintLoading) {
    _objc_inform("LOAD: +[%s(%s) load]\n",
    cls->nameForLogging(),
    _category_getName(cat));
    }
    (*load_method)(cls, SEL_load);
    cats[i].cat = nil;
    }
    }

    // Compact detached list (order-preserving)
    shift = 0;
    for (i = 0; i < used; i++) {
    if (cats[i].cat) {
    cats[i-shift] = cats[i];
    } else {
    shift++;
    }
    }
    used -= shift;

    // Copy any new +load candidates from the new list to the detached list.
    new_categories_added = (loadable_categories_used > 0);
    for (i = 0; i < loadable_categories_used; i++) {
    if (used == allocated) {
    allocated = allocated*2 + 16;
    cats = (struct loadable_category *)
    realloc(cats, allocated *
    sizeof(struct loadable_category));
    }
    cats[used++] = loadable_categories[i];
    }

    // Destroy the new list.
    if (loadable_categories) free(loadable_categories);

    // Reattach the (now augmented) detached list.
    // But if there's nothing left to load, destroy the list.
    if (used) {
    loadable_categories = cats;
    loadable_categories_used = used;
    loadable_categories_allocated = allocated;
    } else {
    if (cats) free(cats);
    loadable_categories = nil;
    loadable_categories_used = 0;
    loadable_categories_allocated = 0;
    }

    if (PrintLoading) {
    if (loadable_categories_used != 0) {
    _objc_inform("LOAD: %d categories still waiting for +load\n",
    loadable_categories_used);
    }
    }

    return new_categories_added;
    }

    我们在这篇博客的最后对整个过程进行一个简单的总结:

    在应用启动的时候会从镜像中查找dyld的地址,而后将dyld加载进来,找到dyld的入口地址__dyld_start,并将后续工作交给 dyld 负责:

  • dyld 开始将程序二进制文件实例化为一个ImageLoader
  • 交由 ImageLoader 读取 image 其中包含了我们的类、方法等各种符号,以及根据Mach-O的Load Commands段加载所有依赖的动态库并完成链接,初始化工作。在主程序初始化阶段,runtime会向dyld绑定回调。
  • 当image加载到内存后,dyld 会通知 runtime 进行处理,runtime 接手后调用 map_images 做解析和处理,接下来 load_images 中调用 call_load_methods 方法,
    遍历所有加载进来的 Class,按继承层级依次调用 Class 的 +load 方法和其 Category 的 +load 方法
  • 当map_images以及load_images执行完毕之后可执行文件中和动态库所有的符号(Class,Protocol,Selector,IMP,…)都已经按格式成功加载到内存中,被 runtime 所管理。
  • 所有初始化工作结束后,dyld 调用真正的 main 函数,紧接着dyld 会清理现场,将调用栈回归,只剩下main函数。
  • Tag Cloud

    AOSP 源码 Android APK 签名 Android JNI Android 事件处理进阶 Android 动画进阶 Android 多线程开发 Android 小经验 Android 常用第三方库 Android 开发流程 Android 开源源码 Android 绘图进阶 Android 自动化测试 Android 自定义View进阶 Android 设计模式 Android其他 Android基础 Android开发流程 Android性能优化 Android混淆技术 Android质量管理工具 Android逆向工程 Git && github Hexo 使用 JavaScript Linux 使用 Objective C 相关 OpenCV ROS iOS 工具使用 iOS 开源库分析 iOS 理论基础 iOS 进阶 代码规范 博客分类目录 叨叨系列 工具的使用 开源代码分析 开源库分析 杂类 树莓派 直播 编程技巧 网站收藏 重要控件