探究APP启动流程

2021-07-09  本文已影响0人  Eli_app

从main函数探究

我们知道main()函数是入口函数,那么我们探究APP的启动流程就先从main函数开始,我们直接断点main函数尝试一下

image

我们可以看到从main函数入手看不到堆栈调用,说明main函数被其他调用,而且不处于APP启动的堆栈中。

根据经验,load()函数加载比较早,我们从load()函数入手是不是能有所收获呢

从load()函数探究

从load()函数下断点,开始调试

image

在这里可以发现很多堆栈信息_dyld_start我们准备了dyld源码,准备一探究竟

image

我们看到前面就是获取一些参数,然后调用dyldbootstrap::start(app_mh, argc, argv, dyld_mh, &startGlue)那么这个函数应该重要,我们跟进去看看

image

这个里面做一些dyld的启动引导,直接进入了dyld::_main()函数,继续跟进去看看

image

我们找到了这个函数,有点长,800+行,我们分块进行分析

1、配置环境

image

2、加载共享缓存

image

3、为可执行程序实例化ImageLoader

image

4、加载dyld插入的库文件

image

5、链接插入的库文件

image

6、镜像文件链接之后建立弱绑定

image

7、运行主程序

image

8、我们继续跟进去看initializeMainExecutable()的实现,我们发现里面最主要的代码就是runInitializers()方法

image

9、在runInitializers()里面我们看到processInitializers()方法,继续跟进

image

10、processInitializers()里面最主要就是对镜像文件进行递归调用,我们继续跟进recursiveInitialization()

image

我们发现,这个里面的代码,最主要的就是notifySingle()this->doInitialization(context);,先看notifySingle()方法有没有我们想找的

11、我们发现notifySingle()方法里面主要是设置macho的header和path等等一些信息,我们继续跟进sNotifyObjCInit()

image

12、我们全局搜索之后,发现在registerObjCNotifiers()方法里面被调用,那我们继续跟踪看看registerObjCNotifiers()被谁调用

image

13、此方法只有在一个地方被调用过就是_dyld_objc_notify_register(),这个函数太熟悉了,就是在我们在runtime里面objc_init里面的方法,一模一样,难道是巧合吗?我们找来runtime的源码继续探究

image

从libobjc.A.dylib库继续探究

我们找来libobjc.A.dylib库,在void _objc_init(void)方法后面下断点,直接运行,然后打印一下当前堆栈

image

我们发现调用_objc_init的方法来自于libdispatch.dylib库里面的_os_object_init方法,我们证实一下流程。

从libdispatch.dylib库证实调用流程

1、从苹果开源库中下载libdispatch.dylib,打开工程后全局搜_os_object_init

image

我们发现第一行代码就是_objc_init,证实了流程。我们继续寻找libdispatch_init方法,看看是否调用了_os_object_init方法

2、全局搜索之后,我们在倒数第三行发现了_os_object_init();方法

image

我们继续跟踪libdispatch_init方法的调用

从libSystem.B.dylib库证实调用流程

1、从苹果开源库找到libSystem.B.dylib的源码,全局搜索libSystem_initializer方法

image

我们在第239行的位置,找到了libdispatch_init();的调用

总结

整个流程分析下来,大概流程图如下所示

image
上一篇下一篇

猜你喜欢

热点阅读