iOS程序启动时,在调用dyld之前做了什么?
进程是可执行文件在内存中加载得到的结果。这种文件必须使用操作系统能够理解的格式,这样操作系统才能解析这个文件,建立所需的依赖(例如库),初始化运行环境并且开始执行。
OS X目前支持的可执行文件格式:解释器脚本格式<magic值: #!>、通用二进制格式<magic值:0xcafebabe little-end, 0xbebafeca big-end>、Mach-O格式(平台原生二进制文件)<0xfeedface 32位, 0xfeedfacf64位>
1、解释器脚本格式实际上只是一种特殊形式的二进制文件格式,它指向“真正”二进制的脚本,这些被指向的文件才是真正得到执行的文件。
2、“通用”二进制文件格式是其支持的各种架构的二进制文件的打包文件:这种格式的文件包含了一个非常简单的头文件,文件头后面依次拷贝了每一种支持架构的二进制文件。
3、Mach-O(Mach-Object的简写)格式具有一个固定的文件头,
1)加载过程在内核的部分负责新进程的基本设置:分配虚拟内存,创建主线程,以及处理任何可能的代码签名/加密的工作。
其中:LC_SEGMENT(LC_SEGMENT_64)命令是最主要的加载命令,这条命令指导内核如何设置新运行的进程的内存空间,并且对应segment直接从Mach-O二进制文件加载到内存中。
2)控制权交给动态链接器(dyld)在用户态完成工作:动态链接可执行文件,库加载和符号解析。
总结:内核读取Mach-O文件,读取文件头,通过fork(或者posix_spawn)创建子进程;LC_SEGMENT命令进行新进程基本的设置;dyld加载动态库、依赖库、符号解析及库的初始化;进入Main函数。
注:在Unix中exec和system的不同在于,system是用shell来调用程序,相当于fork+exec+waitpid,fork 函数创建子进程后通常都会调用 exec 函数来执行一个新程序;而exec是直接让你的程序代替原来的程序运行。
参考书籍:《深入解析Mac OSX & iOS操作系统》