iOS App 启动原理(一)—— mian之前

一款 iOS App 的启动时长对于用户体验来说是至关重要的因素,也是各大公司努力优化的点。最近看了2016年WWDC的一篇视频,怕日后忘记,做一些小总结。

启动过程:

一、加载dyld到App进程

什么是dyld?
dyld的全称是dynamic loader,它的作用是加载一个进程所需要的image。这里提到的image并不是我们认知的意思,指的是Executable,Dylib或者Bundle的一种。

此时内核对dyld都做了哪些事?
首先内核将App的执行文件加载到随机地址空间,之后内核将dyld的执行文件加载到随机地址空间,最后内核去执行执行dyld文件。

二、加载动态链接库

dyld拿到App的执行文件——mach-o文件后,首先从文件的header中解析出App依赖的dylib列表,找到每一个依赖的dylib。之后打开并读取dylib文件的起始位置,验证签名,确保dylib没有被篡改。验证签名后,对dylib中的每个segment调用mmap()。加载完一个dylib后,接着检查这个dylib所依赖的dylib,就这样的递归加载,直到所有的dylib加载完毕。通常一个App所依赖的动态库在100-400个左右,其中大多数都是系统的动态库,它们会被缓存到dyld shared cache,这样读取的效率会很高。

三、Rebase && Bind

首先先讲解一个概念——ASLR

ASLR:全称是Address space layout randomization,翻译过来就是“地址空间布局随机化”。

App被启动的时候,程序会被影射到逻辑的地址空间,这个逻辑的地址空间有一个起始地址,而ASLR技术使得这个起始地址是随机的。如果是固定的,那么黑客很容易就可以由起始地址+偏移量找到函数的地址。

为什么需要Rebase 和 Bind?

是因为刚刚提到的ASLR使得地址随机化,导致起始地址不固定,App和每个dylib加载到的都是随机地址空间,代码中原来的函数地址跟真实的函数地址会有差异。修复这个差异的过程就是rebasing和binding。

Rebase:Rebasing过程就是从__LINKEDIT取出函数指针,根据偏移量修改函数指针,存入__DATA中,Rebase解决了内部的符号引用问题。

Binding:当引用动态库其他的函数或者变量时,当前mach-o文件会指向其他dylib。这时候就需要Binding操作,dyld会根据符号表去找到相应函数和变量地址,Binding解决了修正外部指针指向的问题。

三、Objc Setup

Objective C是动态语言,为了维持它的动态性,在启动时,所以在执行main函数之前,需要把类的信息注册到一个全局的Table中。同时,Objective C支持Category,基于runtime的特性,在初始化的时候,也会把Category中的方法插入类结构体的方法列表中。

四、Initializers

完成objc的相关工作之后,需要完成动态库一些初始化工作:包括了执行 +load() 方法、attribute((constructor)) 修饰的函数的调用、创建 C++ 静态全局变量。运行“自下而上”,这样每个初始化器都可以调用它下面的dylibs,最后,Dyld在可执行文件中调用main()。

结语:至此iOS App只mian函数执行之前所做的事情就简单的介绍完了,如有错误的地方,欢迎大家踊跃提出。

参考:
iOS启动原理
iOS 优化App启动时间-启动详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值