应用加载过程初探 (三)

251 阅读2分钟

其他文章请点击下方:

  1. Objective-C对象底层初探 (一)
  2. Objective-C类和方法底层初探 (二)

应用程序加载都会依赖底层库,库就是可执行代码(二进制) 库分为静态库和动态库。

静态库、动态库

静态库主要是扩展名.a和.lib 动态库主要是扩展名.so

编译过程

  1. 源文件.h、.m、.cpp
  2. 预编译(宏)
  3. 编译(高级代码)
  4. 汇编
  5. 链接(静态库和动态库)
  6. 可执行文件

静态库

在链接阶段,会将目标文件.o所引用的库一起打包生成可执行文件、静态链接。

动态库

在程序运行的时候,才会加进来,会多次使用,共享内存,减少打包的体积,支持热更新(不稳定、不安全) 如:我们常用UIKit就是动态库。

app加载

应用启动后,会交给动态链接器dyld去做下面的工作。

  1. 加载libSystem
  2. 通过运行时Runtime注册回调函数
/***********************************************************************
* _objc_init
* Bootstrap initialization. Registers our image notifier with dyld.
* Called by libSystem BEFORE library initialization time
**********************************************************************/

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_images, load_images, unmap_image);
}

dyld提供一个非常重要的函数_dyld_objc_notify_register

  1. 加载镜像文件image
  2. 执行map_images和Load_images
  3. 调用Main函数

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);
}


/***********************************************************************
* _read_images
* Perform initial processing of the headers in the linked 
* list beginning with headerList. 
*
* Called by: map_images_nolock
*
* Locking: runtimeLock acquired by map_images
**********************************************************************/
void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses)

执行map_images用到一个函数_read_images,主要处理类哈希表gdb_objc_realized_classes、方法哈希表nameSelectors、协议哈希表protocol_map

主要功能:初始化我们相应的类通过realizeClass,进行相应rw\ro操作,接下来处理分类,把分类中的属性、方法、协议加到我们相应的哈希表

load_images分析

void
load_images(const char *path __unused, const struct mach_header *mh)
{
    // Return without taking locks if there are no +load methods here.
    if (!hasLoadMethods((const headerType *)mh)) return;

    recursive_mutex_locker_t lock(loadMethodLock);

    // Discover load methods
    {
        mutex_locker_t lock2(runtimeLock);
        prepare_load_methods((const headerType *)mh);
    }

    // Call +load methods (without runtimeLock - re-entrant)
    call_load_methods();
}

第一步通过prepare_load_methods加载我们所有的load的方法,包括类和分类。

//通过哈希表取出类的列表
classref_t *classlist =  _getObjc2NonlazyClassList(mhdr, &count);

//遍历
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
    schedule_class_load(cls->superclass);//递归父类

    add_class_to_loadable_list(cls);//类中的load加入到list中
    cls->setInfo(RW_LOADED); 
}

加入到list中,利用kvc
loadble_classes[loadable_classse_used].cls = cls;
loadble_classes[loadable_classes_used].method = method;

//通过哈希表取出分类的列表 
category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);

//分类不需要递归
realizeClass(cls);如果没有实现

//加载分类的load到list中
add_category_to_loadable_list(cat);

//加入到list中
loadable_categories[loadable_categories_used].cat = catl;
loadable_categories[loadable_categories_used].method = method;

加载完数据后,进行第二步开始进行调用call_load_methods

    objc_autoreleasePoolPush() 压栈自动释放池
    call_class_loads()通过指针进行方法调用
    call_category_loads()
    objc_autoreleasePoolPop(pool) 出栈