1、Mach-O
Mach-O是一种文件格式,包括iOS的可执行文件(Executable是 App 中的主要二进制文件)、动态库(Dylib)、目标文件、静态库、dyld(动态链接器)等都是Mach-O文件格式; iOS可执行文件Mach-O生成的过程
- 预编译:
- 展开头文件,在写有#import的文件中,将文件filename展开,通俗来说就是将fiename文件中的代码写入到当前文件中;
- 替换代码宏定义
- 删除注释
- 条件编译#if的处理
- 编译
- 词法分析、语法分析、语义分析
- 汇编
- 生成机器指令如.o文件
- 链接
- 动态链接、静态链接
2、app启动流程
系统调用exec()将app对用的二进制文件加载进内存,再讲dyld加载进内存,dyld进行动态链接。dyld具体的工作:
- 递归加载可执行文件所依赖的动态库;
- 进行rebase和binding操作
- 调起main函数
3、动态库加载
load方法是在main函数运行前加载,在某个类中load方法断点,打印堆栈信息如下:
dyld源码,调用的函数如下
- dyld中start
- dyld4::prepare
- dyld4::APIs::runAllInitializersForMain()
- dyld4::Loader::runInitializersBottomUpPlusUpwardLinks
- dyld4::Loader::runInitializersBottomUp
- dyld4::RuntimeState::notifyObjCInit
- libobjc.A.dylib`load_images
可以看到最终调用到load_images方法,在dyld4中最终调用到notifyObjCInit方法中,在找到setObjCNotifiers中,最终是在_dyld_objc_notify_register方法中,但是在dyld4源码中没有找到此方法的调用;我们在工程中用符号断点_dyld_objc_notify_register如下:
最终在objc源码中找到调用此方法,
可以从上面的堆栈信息调用可以看到,libSystem会在第一个初始化、然后调用libdispatch初始化,在调用os_object_init,最后调用_objc_init;
总结
在libobjc进⾏初始化的时候,会调⽤⼀个_dyld_objc_notify_register函数,这个函数会给dyld传递三个回调函数。
- map_images: dyld将image镜像⽂件加载进内存时,会触发该函数;
- load_images: dyld初始化image会触发该函数;
- unmap_image: dyld将image移除时会触发该函数; 然后,dyld会调⽤ map_images 和 load_images 来对image进⾏初始化的操作。