dyld 的全称是 the dynamic link editor(动态链接器)。它是 macOS 和 iOS 操作系统中的一个核心组件,负责准备一个可执行文件(Mach-O 文件)及其所需的库,以便它能够运行。
你可以把 dyld 想象成一个非常专业的“舞台经理”,而你的程序是“主演”。在“主演”上台表演之前,“舞台经理”需要完成以下工作:
dyld 的具体职责:
1. 加载程序本身:首先,dyld 会读取 Mach-O 文件,分析其结构,为程序的代码和数据段在内存中分配空间。
2. 递归加载依赖的动态库(dylibs):
· 你的程序几乎肯定会使用系统库(如 Foundation, UIKit, AppKit)或第三方库。
· dyld 会查看 Mach-O 文件中的“加载命令”(Load Commands),找到所有它依赖的动态库的路径(例如 /usr/lib/libSystem.B.dylib)。
· 然后,dyld 会去这些路径(首先在缓存中查找)加载每一个动态库。
· 但每个动态库本身也可能依赖其他库,所以 dyld 需要递归地加载所有这些依赖项,直到整个“依赖树”都被加载到内存中。
3. 符号绑定(Binding):
· 你的程序中调用 printf 函数时,在编译后,这条指令只是一个对“printf”这个符号的引用,并不知道 printf 函数在内存中的具体地址。
· dyld 的工作就是找到 printf 函数在哪个库(比如 libSystem.B.dylib)中,以及它被加载到内存中的哪个地址,然后将你程序中的那个引用替换成真实的内存地址。这个过程就是符号绑定。
4. 运行初始化例程:
· 在所有库加载和符号绑定完成后,dyld 会开始执行一些初始化代码。例如,C++ 的全局静态对象构造函数就是在这一步被调用的。
5. 跳转到主程序入口:
· 当所有准备工作就绪后,dyld 的最后一项任务就是跳转到程序的入口点,通常是 main 函数,这时你的程序代码才真正开始执行。
总结一下你描述的启动流程:
1. 内核操作:你双击程序图标,内核(操作系统核心)将程序的 Mach-O 文件映射到内存中。
2. 启动 dyld:内核检查 Mach-O 文件,找到其中记录的 dyld 的路径(例如 /usr/lib/dyld)。
3. dyld 接管:内核将控制权交给 dyld。
4. dyld 进行“舞台准备”:dyld 开始上述的加载、链接、初始化等一系列复杂工作。
5. 程序开始执行:dyld 完成所有工作后,调用 main 函数,程序启动完成。
所以,dyld 是连接你的静态程序和运行时动态环境的桥梁,是保证你的应用能够顺利运行不可或缺的组件。现代 dyld 还有很多优化,比如共享缓存,可以极大地加快应用的启动速度。