应用的加载流程dyld

169 阅读2分钟

1、Mach-O

  • Mach-O是一种文件格式,包括iOS的可执行文件(Executable是 App 中的主要二进制文件)、动态库(Dylib)、目标文件、静态库、dyld(动态链接器)等都是Mach-O文件格式; iOS可执行文件Mach-O生成的过程
  1. 预编译:
  • 展开头文件,在写有#import的文件中,将文件filename展开,通俗来说就是将fiename文件中的代码写入到当前文件中;
  • 替换代码宏定义
  • 删除注释
  • 条件编译#if的处理
  1. 编译
  • 词法分析、语法分析、语义分析
  1. 汇编
  • 生成机器指令如.o文件
  1. 链接
  • 动态链接、静态链接

2、app启动流程

系统调用exec()将app对用的二进制文件加载进内存,再讲dyld加载进内存,dyld进行动态链接。dyld具体的工作:

  • 递归加载可执行文件所依赖的动态库;
  • 进行rebase和binding操作
  • 调起main函数

3、动态库加载

load方法是在main函数运行前加载,在某个类中load方法断点,打印堆栈信息如下: image.png dyld源码,调用的函数如下

  1. dyld中start
  2. dyld4::prepare
  3. dyld4::APIs::runAllInitializersForMain()
  4. dyld4::Loader::runInitializersBottomUpPlusUpwardLinks
  5. dyld4::Loader::runInitializersBottomUp
  6. dyld4::RuntimeState::notifyObjCInit
  7. libobjc.A.dylib`load_images

可以看到最终调用到load_images方法,在dyld4中最终调用到notifyObjCInit方法中,在找到setObjCNotifiers中,最终是在_dyld_objc_notify_register方法中,但是在dyld4源码中没有找到此方法的调用;我们在工程中用符号断点_dyld_objc_notify_register如下: image.png 最终在objc源码中找到调用此方法, 可以从上面的堆栈信息调用可以看到,libSystem会在第一个初始化、然后调用libdispatch初始化,在调用os_object_init,最后调用_objc_init;

总结

在libobjc进⾏初始化的时候,会调⽤⼀个_dyld_objc_notify_register函数,这个函数会给dyld传递三个回调函数。

  1. map_images: dyld将image镜像⽂件加载进内存时,会触发该函数;
  2. load_images: dyld初始化image会触发该函数;
  3. unmap_image: dyld将image移除时会触发该函数; 然后,dyld会调⽤ map_images 和 load_images 来对image进⾏初始化的操作。