定义
MachO是一种文件格式,内部包换:可执行文件
,动态库
,静态库
,dyld
,目标文件
等。其中的可执行文件
是一个通用二进制文件(多种架构),
可以通过lipo
命令下的-thin
拆分架构,-create
合并架构。
lipo -thin xxx
lipo -create xxx
结构
MachO大致分为3个部分:
-
Header
:用户快速确认该文件(描述信息),如CPU类型,文件类型等; -
LoadCommands
: 告诉加载器如何设置并加载二进制数据; -
Data
: 存放数据,如代码,字符串常量,类,方法等;
DYLD
DYLD用于加载所有的库和可执行文件,在iOS中,APP启动时,libDyld
开始介入,在之前的类的加载中有详细说过。这里再简单的说一下:
APP启动时,进入dyld::start
->dyldbootstrap::start
->dyld::main()
,在dyld::main()
中主要做了以下动作:
- 配置环境变量
- 加载共享缓存库 (系统库)
- 实例化主程序
- 加载动态库
- 链接主程序
- 初始化主程序(
dyld::initializeMainExecutable()
) - 执行
main()
这里说一下比较核心的第6步:
内部会初始化libSystem
,然后初始化libdispatch
,之进入libObjc
,并执行_objc_init(void)
,在这个函数内部有一个核心的回调注册:
libObjc内部:
_objc_init(){
........
_dyld_objc_notify_register(&map_images,&load_images,&unmap_images);
........
}
map_images
是对OC类的加载,load_Images
是对OC中所有load
方法的调用。该回调会在libDyld
内部调用notifySingle()
后触发。
之后会执行doModInitFunctions()
,内部会调用项目内所有的全局C++对象的构造函数(带__attribute__((constructor))
的函数)。
这里同时也说明了为什么APP启动之后是load()
->C++
->main()
的执行顺序了。