前言
代码如何加载到内存的 我们探究一下
代码准备
1.应用程序的加载原理
库:可执行的二进制文件-> 能够被操作系统加载到内存->静态库 和 动态库
编译过程
可执行文件是什么呢
打开工程 command+b
入下图操作 最后得到的就是可执行文件
验证一下 可执行文件 执行了main
函数里面的代码
可执行文件通过动态链接器dyld
加载到内存的加载过程入下图
Runtime
向注册回调函数是
加载新的image
是指把库映射了一份到内存 通过代码 我们打印一下 image list
看加载了哪些dyld
通过地址找到CoreFoundation
这个库 库的路径:对应dyld
源码DYLD_ROOT_PATH
通过执行map_images
和 Load_images
(这两个函数下篇在分析)之后 调用main
函数
2.dyld
引出
我们怎么找到dyld
首先打开工程 断点main
函数
我们发现左边是0 main
1 start
在main
之前走了这个1 start
1 start
做了什么呢
欢迎来到 libdyld.dylib
的世界 添加系统断点start
走一波 发现没断点住 但是[ViewController load]
在main
函数之前打印的 如果我们在这打印断点 看是否有发现呢 如下图
通过bt
打印栈的信息 先进后出 所以最开始的是 dyld``_dyld_start
我们打开dyld
源码(最新版本 dyld-852
下载链接在最上面)
应用加载流程如下
- dyld`_dyld_start ->
- dyld`dyldbootstrap::start ->
- dyld`dyld::_main ->
- dyld`dyld::useSimulatorDyld ->
- dyld_sim`dyld::_main ->
- dyld_sim`dyld::initializeMainExecutable() ->
- dyld_sim`ImageLoader::runInitializers ->
- dyld_sim`ImageLoader::processInitializers ->
- dyld_sim`ImageLoader::recursiveInitialization ->
- dyld_sim`dyld::notifySingle ->
- libobjc.A.dylib`load_images
3.dyld
流程上
通过dyld
源码搜索_dyld_start
我们进入汇编
发现会进入这个函数 call dyldbootstrap::start(app_mh, argc, argv, dyld_mh, &startGlue)
我们全局搜索一下
该函数返回一个 dyld::_main((macho_header*)appsMachHeader, appsSlide, argc, argv, envp, apple, startGlue);
我们进入看一下
4.dyld
流程中的main
函数主流程
因为main
函数的代码比较长main
函数最后返回result
通过反推 发现会执行 sMainExecutable
这个函数
发现sMainExecutable = instantiateFromLoadedImage
这个函数实例化主程序
通过这个函数添加镜像文件
通过这个函数添加machO
一些格式 machO
的格式如下图:
通过sniffLoadCommands
这个函数添加具体格式例如load_command
下一步加载插入的动态库
下一步 link
主程序
下一步 link
插入动态库
下一步 weakBind弱引用绑定
下一步 初始化initializeMainExecutable
跑起来
下一步通知dyld
可以进入main()
函数了
5.dyld流程-主程序运行
我们主要分析initializeMainExecutable
images
开始初始化
进入 runInitializers
-> processInitializers
初始化准备
进入processInitializers
->recursiveInitialization
递归初始化
进入recursiveInitialization
->context.notifySingle
单个通知注入
-> doInitialization
调用init
方法 -> context.notifySingle
通知初始化完成
进入notifySingle
->找到sNotifyObjCInit
通过sNotifyObjCInit
->registerObjCNotifiers
通过registerObjCNotifiers
->_dyld_objc_notify_register
而 _dyld_objc_notify_register
就是runtime
注册回调函数
6.dyld
流程-images
初始化流程
我们通过objc4-818.2
源码 断点_objc_init
libdispatch.dylib``_os_object_init
_os_object_init
->调用了_objc_init
libdispatch.dylib``libdispatch_init
->_os_object_init
libSystem.B.dylib``libSystem_initializer
->libdispatch_init
dyld``ImageLoaderMachO::doModInitFunctions:
->初始化libSystem_initializer
(通过 strcmp(installPath, libSystemPath(context)
)
ImageLoaderMachO::doInitialization
->doModInitFunctions
回到递归recursiveInitialization
-> doInitialization