App加载
背景
- 我们一直在用手机玩App但App启动都做了什么呢?App启动到main函数中间都做了什么?
- 我们一直写代码,代码又是如何写入内存中的呢?
- 我们导入的动/静态库怎么加载到内存的?
- objc_init怎么来的?我们前面探索了那么多objc源码它怎么启动的呢?
- dyld到主程序main的过程做了什么?
- dyld2 和 dyld3的区别?
准备
- 可编译的
objc4
工程 dyld
源码libdispatch、libsystem
源码
App加载原理
库
库:可执行的二进制文件能够被加载到内存中
- 静态库:(.a/.lib) 静态链接 优点:编译速度快 缺点:包体积变大
- 动态库:(.so/.dll/.framwork)动态链接 优点:共享相同库,优化内存空间和包大小。缺点:编译速度慢
- 可执行文件:放在终端能够运行起来
动静态库区别主要在链接方式不一样,以空间换时间和以时间换空间的区别,没有好与坏选择合适的方式保持动态平衡
动态链接器(dyld)
dyld流程源码分析:
我们从程序运行汇编调试看到dyld_start是dyld的方法
下面我们来分析dyld动态链接器源码程序执行过程:
call dyldbootstrap::start(app_mh, argc, argv, dyld_mh, &startGlue)
然后找里面有个_main函数,此为dyld内部函数跟工程的main不同,_main函数里面通过返回result跟sMainExecutable有关
而sMainExecutable是instantiateFromLoadedImage的函数调用
instantiateMainExecutable初始化主程序并执行:
经过探索到单个镜像文件加载_dyld_objc_notify_register:
跟libobjc.dylib的objc_init走的同一个方法:
dyld到主程序main过程
lldb到objc源码中的objc_init,使用bt,逆向推导
:
doinitialization-> doModInitFunctions(dyld) -> libSystem.B.dylib
libSystem_initializer:->libdispatch.dylib
libdispatch_init:->_os_object_init(libdispatch.dylib) -> _objc_init(libobjc)
- 小节汇总-> 首先要libSystem系统库先加载,然后libdispatch线程库加载
doinitialization和context.notifySingle关系
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
map_images:关联重要内容数据
然后进入_dyld_objc_notify_register:
找到setObjCNotifiers函数并进入:
里面有三个重要参数:
mapped,init,unmapped
doInitialization初始化赋值
然后赋值_dyld_objc_notify_register-> registerObjCNotifiers:
map_images 和 load_images:
map_images和load_images是dyld和objc沟通的过程
map load - map()
notifySingle : load()
objc的load_images会在dyld的registerObjCNotifiers:开始调用
dyld流程分析图示:
我们可了解dyld流程的App加载过程
总结分析
- 感受:有时候内容不重要,分析问题和内容的能力很重要
- 通过符号断点dyld3是iOS使用的框架(WWDC2017)
- 我们通过探索发现objc_init做程序初始化,而且里面有很多函数初始化,那它里面都做了什么?若感兴趣请移步:iOS底层-类的加载原理