iOS安全

dyld加载流程

2021-03-21  本文已影响0人  木扬音

本文主要是分析main函数之前,底层做了什么 -- dyld的加载流程

例子

根据打印结果,我们来探索程序在mian函数之前做了什么

编译过程

静态库 和 动态库

静态库

静态库:在链接阶段,会将汇编生成的目标程序与引用的库一起链接打包到可执行文件当中。打包后的静态库就不会在改变,因为它是在编译时直接拷贝一份,复制到目标程序中

动态库

动态库:程序在编译时并不会链接到目标程序,目标程序只会动态存储指向动态库的引用,在程序运行时才被载入

静态库和动态库图示

dyld加载流程分析

什么是dyld

dyld(the dynamic link editor)是苹果的动态链接器,是苹果操作系统的重要组成部分,在app被编译打包成可执行文件(Mach-o)后,交由dlyd负责链接,加载程序

App启动流程


App启动流程

dyld::_main函数源码分析

下面主要分析下【第三步】和【第八步】

【第三步:主程序初始化】

第八步:执行初始化方法

在这里我们分为两部分探索:notifySingle函数 和 doInitialization函数

notifySingle函数

load函数加载

下面我们进入load_images的源码,来证明load_images中调用了所有的+laod函数

【总结】load的源码调用链:_dyld_start --> dyldbootstrap::start --> dyld::_main --> dyld::initializeMainExecutable --> ImageLoader::runInitializers --> ImageLoader::processInitializers --> ImageLoader::recursiveInitialization --> dyld::notifySingle(是一个回调处理) --> sNotifyObjCInit --> load_images(libobjc.A.dylib)

这时候我们发现没有找到_objc_init的调用,那是因为忽略一个函数doInitialization

doInitialization函数

这里也需要分成两部分,一部分是doImageInit函数,一部分是doModInitFunctions函数

可以通过测试程序的堆栈信息来验证,在C++方法处加一个断点


C++断点堆栈信息

`
走到这里,还是没有找到_objc_init的调用?怎么办呢?放弃吗?当然不行,我们还可以通过_objc_init加一个符号断点来查看调用_objc_init前的堆栈信息,

所以可以简单的理解为sNotifySingle在这里添加通知即addObserver_objc_init中调用_dyld_objc_notify_register相当于发送通知,即push,而sNotifySingle相当于通知的处理函数,即selector

【总结】:_objc_init的源码链:_dyld_start --> dyldbootstrap::start --> dyld::_main --> dyld::initializeMainExecutable --> ImageLoader::runInitializers --> ImageLoader::processInitializers --> ImageLoader::recursiveInitialization --> doInitialization --> libSystem_initializer(libSystem.B.dylib) --> _os_object_init(libdispatch.dylib)--> _objc_init(libobjc.A.dylib)

第九步:寻找主入口函数

dyld汇编源码实现

dyld中main部分的汇编源码实现

注意:main是写定的函数,写入内存,读取到dyld,如果修改了main函数的名称,会报错

报错信息

所以,综上所述,最终dyld加载流程,如下图所示,图中也诠释了前文中的问题:为什么是load-->Cxx-->main的调用顺序

dyld加载流程
上一篇 下一篇

猜你喜欢

热点阅读