7.DYLD

例:

在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)