7.DYLD

作者: JoyChenSeven | 来源:发表于2019-11-13 17:09 被阅读0次

    例:

    在main函数中打上断点和viewController中手写+(void)load 方法,在应用启动的时候,是viewController 中的load先断到

    bt 指令是查看函数调用栈的

    up 指令在函数调用栈中往上走

    可以看到 dyldbootstrap::start 函数

    查看 DYLD 源码

    全局搜索 dyldbootstrap  ,然后在 dyldbootstrap 中搜索start 函数,可以找到在468行,可以通过 command + shift + j 定位到这个文件

    const struct macho_header* appsMachHeader, (参数是machO header,是和宏定义,64位就是64位的header)

    int argc,

    const char* argv[],  

    intptr_t slide,(ASLR,随机值,machO加载到内存中是,随机加一个变量)

    const struct macho_header* dyldsMachHeader,

    uintptr_t* startGlue

    配置环境变量

    当我们配置了环境变量的值,可以看到打印信息,在load调用前就已经打印了环境变量的信息

    配置DYLD_PRINT_OPTS 后可以看到打印的是machO 的地址

    加载共享缓存

    //检查共享缓存是否为禁用状态 但是最后一句话告诉我们iOS设备不能禁用共享缓存

    主程序的实例化

    sniffLoadCommands 实例化的是抽象类,需要其他子类实力化为machO 的image 

    加载动态库

    连接三方库

    自己添加的库,会根据添加的顺序加载对应的库,+(void)load方法的调用顺序也是如此。

    在这里进行weak 的绑定

    run主程序

    有个回调方法,sNotifyObjCInit

    这个时候 (*sNotifyObjCInit)(image->getRealPath(), image->machHeader()); 就会调用objc 中的方法load_images

    在 _dyld_objc_notify_register  方法中调用 registerObjCNotifiers

    可以下一个符号断点来调试,可以发现在这个方法之前framework 的load 方法都还没有调用,所以之前的配置环境变量、加载共享缓存、实例化主程序、加载动态库、链接三方库 操作应该在 all Images 中。

    可以通过寄存器查看 参数 

    可以查看objc 源码,可以看到第二个参数就是 load_images

    可以查找load_images 方法,(函数名称就是函数指针)

    最后到 call_load_methods ,然后循环调用每一个类的loads

    context.notifySingle(dyld_image_state_dependents_initialized, this, &timingInfo); 执行完成后所有framework的load方法都已经执行完毕了,然后开始加载image

    doModInitFunctions 函数会执行 c++的构造函数 (module inti function ),framework代码注入都在这个构造函数之前

    __attribute__((constructor))voidfunc3(){ printf("func3来了 \n"); } //固定写法

    如果多个framework 中都有load 和 __attribute__ 构造方法,那么会根据添加的顺序,执行完每一个framework 的 load 和 __attribute__ 构造方法 才会执行下一个  framework 的  load 和 __attribute__ 构造方法 


    可以通过machO view 看到, _mod_init_func 中有所有的构造函数

    初始化函数执行完后,这时 main 函数还没有执行

    result = (uintptr_t)sMainExecutable->getEntryFromLC_MAIN();  这时才开始调用main 函数,最终将result 返回

    load  ->   构造函数 - > main 

    image 的加载过程 :加载共享缓存 ->  加载插入的库  -> 加载三方库  -> 加载主程序

    DYLD:

    - dyld加载所有的库和可执行文件

    - dyld加载流程

         - 程序执行从_dyld_start 开始

         - 进入 dyld:main 函数

              - 配置一些环境变量

              - 加载共享缓存库,一开始就判断是否禁用,iOS无法被禁用

              -  实例化主程序

              - 加载动态库 

             - 链接主程序

             - 最关键的地方:初始化方法

                     - 经过一些列初始化到 调用 notifySingle 函数

                            - 该函数会执行一个回调

                            - 通过断点调试:该回调是 _objc_init初始化的时候赋值的一个函数load_Images

                                  - load_images 里面执行的是 call_load_methods函数

                                        - call_load_methods 函数循环调用各个类的load方法

                    -  doModInitFunctions 函数

                                 - 内部会调用带 __attribute__((constructor)) 的c函数

                    -  返回主程序的入口函数,开始进入主程序的main函数

    相关文章

      网友评论

          本文标题:7.DYLD

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