Mach-O文件结构
-
Header部分:描述文件基本信息(如CPU、架构、文件类型、加载命令个数)
-
loadCommands部分:描述各个Data部分的内存分布,对系统内核加载器和动态连接器起指导作用
-
Data部分:存放代码与数据
- __PAGEZERO段:空指针陷阱段,映射到虚拟内存空间的第一页,用于捕捉对NULL指针的引用
- __TEXT 段: 包含了执行代码以及其他只读数据的,当这个段被映射到内存后,可以被所有进程共享。(这主要用在frameworks, bundles和共享库等程序中,也可以为同一个可执行文件的多个进程拷贝使用)
section 描述 __text 代码实现 __stubs 符号桩,本质上就是段会直接跳入到lazybinding的表的对应项指针指向的地址的代码 __stubs_helper 辅助函数,上述lazybinding表中没有找到符号地址都指向这 __cstring C string字符串常量 __ustring Unicode string中文常量 __objc_methname OC方法名称 __objc_classname OC类名 __objc_methtype OC方法类型 __entitlements 签名证书 __unwid_info 用于存储异常情况信息 __const 初始化的常量 - __DATA段: 包含了程序数据,该段可写;
section 描述 __const 未始化的常量 __bss 没有初始化和初始化为0 的全局变量 __nl_symbol_prt / __got 非lazy-binding的指针表 __la_symbol_prt lazy-binding的指针表,每个表项中的指针一开始指向stub_helper __cfstring CoreFoundation string __objc_classlist OC类列表 __objc_catlist OC分类列表 __objc_protollist OC协议列表 __objc_imageinfo OC镜像信息 __objc_const OC类信息、方法列表、属性列表、变量列表 __objc_selfrefs OC类实例自引用(self) __objc_classfrefs OC类类自引用 __objc_superrefs OC类超类引用(super) __objc_ivar OC属性 __objc_data OC类ISA - __LINKEDIT段: 含有为动态链接库使用的原始数据,比如符号,字符串,重定位表条目等等。
App启动流程
- 将Mach-O中Segment与符号表等数据映射到内存中
- 调用dyld(the dynamic link editor)程序,动态链接器
- 加载UUID与构建二进制是的的源码版本等信息
- 设置程序主线程的
main
函数入口地址和栈大小 - 设置依赖的动态库
- 加载代码开始地址、代码段内的非指令的表、代码签名
- 系统kernel做好启动程序的初始准备后,动态链接依赖库,并由runtime负责加载成objc定义的结构,所有初始化工作结束后,dyld调用真正的main函数
从kernel留下的原始调用栈引导和启动自己
-
将程序依赖的动态链接库递归加载进内存,系统有缓存机制
- 交由imageLoader读取image,其中包含了我们的类,方法等各种符号
- 由于runtime向dyld绑定了回调,当image加载到内存后,dyld会通知runtime进行处理
- runtime接手后调用map_images做解析和处理,接下来load_images中调用call_load_methods方法,遍历所有加载进来的Class,按继承层级依次调用Class的+load方法和Category的+load方法
non-lazy符号立即link到可执行文件,lazy的存表里
找到可执行文件的main函数,准备参数并调用
程序执行中负责绑定lazy符号、提供runtime dynamic loading services、提供调试器接口。
程序main函数return后执行static terminator
某些场景下main函数结束后调libSystem的_exit函数。