dyld源码
苹果官方资源opensource
objc4-838可编译联调源码
一、相识相干概念
1.静态库、动态库
通常步伐都会依靠体系一些库, 库是什么呢? 着实库就是一些可实行的二进制文件, 能被操纵体系加载到内存内里中。库分为两种:静态库 / 动态库
- 静态库:是一堆.o文件的聚集。格式.a, .lib等。链接阶段时静态库会被完备地复制, 一起打包在可实行文件中,被多次利用就有多份冗余拷贝。
- 优点: 编译完成之后, 链接到目标步伐中, 同时打包到可实行文件内里, 不会有外部依靠。
- 缺点: 静态库会有两份, 以是会导致目标步伐体积增大, 对内存, 性能, 速率斲丧很大。而且类似静态库每个app中都会拷贝一份。
- 动态库:是一个已经完全链接后的镜像。格式.framework等。步伐编译时并不会链接到目标步伐中,目标步伐只会存储指向动态库的引用,在步伐运行时才被载入。苹果大部门都是动态库。
- 优点: 不必要拷贝到目标步伐, 镌汰App包的体积;多个App可以利用同一个动态库, 共享内存, 节省资源;由于运行时才会去加载, 那么可以在App不利用时随时对库举行更换或更新, 更新机动。
- 缺点: 动态载入会带来一部门性能丧失, 同时动态库也会使得步伐依靠于外部情况。一旦动态库没有或消散, 步伐会出现标题。
1.Xcode编译command + B产生可实行文件的过程:
- a.预编译
处置惩罚源代码文件中以#开头的预编译的下令(#import/#include等等);把包罗的文件插入到指定的位置;更换代码中的宏界说;删除代码里的表明等等。产生.i文件。
- b.编译
词法分析;语法分析;语义分析;生成相应的汇编代码文件。 产生.s文件(汇编文件)
- c.汇编
将汇编代码文件翻译成呆板指令,呆板指令会生成.o文件。
- d.链接
把之前全部操纵的文件链接到步伐内里来, 对.o文件中引用其他库的地方举行引用, 生成末了的 可实行文件。动态库与静态库区别着实就是链接的区别。
- 静态链接: 链接器对.o文件举行符号网络、剖析和重定位;把全部的.o粘合在一起从而形成可实行文件。(在静态链接之后就不会再有静态库了)
- 动态链接: dyld动态链接(下面有介绍)
2.点击App启动的过程:
- a.体系调用 exec() 分配内存、开辟历程
- b.app对应的可实行文件加载到内存
- c.dyld动态链接器加载到内存:load dyld
- d.dyld动态链接器进办法态链接:rebase->bing->Objc->initalizers
- e.调起main()函数
启动时间的划分可以把main()函数作为关键点分割成两块
t1阶段,main()之前的处置惩罚所需时间,称为pre-main
t2阶段,main()及main()之后处置惩罚所需时间
t2阶段耗时的重要是业务代码
3.Mach-O是什么?
Mach-O: Mach Object文件格式的缩写,它是一种用于可实行文件,目标文件.o,动态库,内核转储的文件格式。作为a.out格式的替换,Mach-O提供了更强的扩展性,并提拔了符号表中信息的访问速率。
三种Mach-O格式的文件:可实行文件、dylib动态库、Bundle资源文件包
Mach-O由四部门构成:Mach-O头部、Load Command、section、Other Data,可以通过MachOView可检察可实行文件信息。
二、什么是dyld
本文重要介绍dyld源码实行流程。
在app启动加载过程中类和分类加载都不可制止的触及dyld,以是相识dyld源码可以让我们更好的明白app的工作原理。
什么是dyld?
dyld(the dynamic link editor 动态链接器):是苹果操纵体系的一个紧张的构成部门。在iOS/Mac OSX体系中,仅有很少量的历程只必要内核就能完成加载,根本上全部的历程都是动态链接的,以是Mach-O镜像文件中会有许多对外部的库和符号的引用,但是这些引用并不能直接用,在启动时还必须要通过这些引用举行内容的弥补,这个弥补工作就是由动态链接器dyld来完成的,也就是符号绑定。
在app被编译打包成可实行文件格式的Mach-O文件后,在步伐启动时交由dyld负责链接加载步伐。
dyld是开源的,可以通过苹果官网下载它的dyld源码,本文的对应的版本是941.5。dyld4是iOS15发布的。
- dyld3: 相比dyld2新增预构建/闭包, 目标是将一些启动数据创建为闭包存到当地,下次启动将不再重新剖析数据,而是直接读取闭包内容
- dyld4: 采取pre-build + just-in-time 预构建/闭包+及时剖析的双剖析模式, 将根据缓存有用与否选择符合的模式举行剖析, 同时也处置惩罚了闭包失效时候必要重修闭包的性能标题。
三、dyld工作流程
新建一个工程,在ViewController.m里重写+(void)load方法,在load方法上打个断点调试,运行app后在断点处输出其函数调用的堆栈:
新版本dyld: start开始接下来走 dyld4中prepare方法, 源码入口必要在start中开始探索。
(旧版本dyld: _dyld_start开始, 接下来走dyldbootstrap, 源码入口必要在dyld_start开始。)
1.start函数是dyld的开始
// dyld的入口点。内核加载dyld并跳转到__dyld_start,它设置一些寄存器并调用这个函数。// 注意:这个函数永久不会返回,它调用exit()。因此,堆栈掩护步伐是无用的,由于永久不会实行epilog。标志函数no-return禁用堆栈掩护。堆栈掩护器也会导致armv7k代码生成的标题,由于它通过prolog中的GOT槽访问随机值,但dyld还没有rebased。void start(const KernelArgs* kernArgs) __attribute__((noreturn)) __asm("start");void start(const KernelArgs* kernArgs){ // 发出kdebug跟踪点来指示dyld引导步伐已经启动 <rdar://46878536> // 注意:这是在dyld rebased之前调用的,以是kdebug_trace_dyld_marker()不能利用任何全局变量 dyld3::kdebug_trace_dyld_marker(DBG_DYLD_TIMING_BOOTSTRAP_START, 0, 0, 0, 0); // 走全部的fixups chains 和 rebase dyld // 注意:withChainStarts()和fixupAllChainedFixups()不能利用任何静态数据指针,由于它们还没有rebased const MachOAnalyzer* dyldMA = getDyldMH(); // 获取Mach-O分析器 assert(dyldMA->hasChainedFixups()); uintptr_t slide = (long)dyldMA; // 全部基于修复链的图像的基址为0,因此slide == load address __block Diagnostics diag; dyldMA->withChainStarts(diag, 0, ^(const dyld_chained_starts_in_image* starts) { dyldMA->fixupAllChainedFixups(diag, starts, slide, dyld3::Array<const void*>(), nullptr); }); diag.assertNoError(); // 现在,我们可以调用利用DATA的函数 mach_init(); // mach消息初始化 // 为stack canary设置随机值 __guard_setup(kernArgs->findApple()); // 栈溢出掩护 // 设置以便open_with_subsystem()工作 _subsystem_init(kernArgs->findApple()); // 在__DATA_CONST中将ProcessConfig对象变为只读之前,利用placement new来构造它 ProcessConfig& config = *new ((ProcessConfig*)sConfigBuffer) ProcessConfig(kernArgs, sSyscallDelegate); // 使__DATA_CONST只读(内核映射为r/w) dyldMA->forEachSegment(^(const MachOAnalyzer::SegmentInfo& segInfo, bool& stop) { if ( segInfo.readOnlyData ) { const uint8_t* start = (uint8_t*)(segInfo.vmAddr + slide); size_t size = (size_t)segInfo.vmSize; sSyscallDelegate.mprotect((void*)start, size, PROT_READ); } });#if !SUPPPORT_PRE_LC_MAIN // 堆栈分配RuntimeLocks。它们不能位于通常是只读的Allocator池中 RuntimeLocks sLocks;#endif // 创建Allocator和APIs/RuntimeState对象 APIs& state = APIs::bootstrap(config, sLocks); // 加载步伐的全部依靠项并将它们绑定在一起 MainFunc appMain = prepare(state, dyldMA); // 现在使全部的dyld分配的数据结构只读 state.decWritable(); // 调用main(),假如它返回,调用exit()并返回结果 // 注意:这是颠末构造的,以便在步伐的主线程中回溯时只在“main”下面体现“start”。 int result = appMain(state.config.process.argc, state.config.process.argv, state.config.process.envp, state.config.process.apple); // 假如我们到达这里,main()返回(而不是步伐调用exit())#if TARGET_OS_OSX // <rdar://74518676> libSystemHelpers不是为模仿器设置的,因此直接调用_exit() if ( MachOFile::isSimulatorPlatform(state.config.process.platform) ) _exit(result);#endif state.libSystemHelpers->exit(result);}
- 走全部的 fixups chains 和 rebase dyld
- mach消息初始化:mach_init()
- 栈溢出掩护:__guard_setup(kernArgs->findApple());
- 构建历程设置:config = ProcessConfig(kernArgs, sSyscallDelegate);
class VIS_HIDDEN ProcessConfig{public: // used in unit tests to config and test ProcessConfig objects ProcessConfig(const KernelArgs* kernArgs, SyscallDelegate&);#if !BUILDING_DYLD void reset(const MachOAnalyzer* mainExe, const char* mainPath, const DyldSharedCache* cache);#endif // // Contains config info derived from Kernel arguments // class Process { public: Process(const KernelArgs* kernArgs, SyscallDelegate&); const MachOAnalyzer* mainExecutable; const char* mainExecutablePath; const char* mainUnrealPath; // raw path used to launch uint32_t mainExecutableSDKVersion; uint32_t mainExecutableSDKVersionSet; uint32_t mainExecutableMinOSVersion; uint32_t mainExecutableMinOSVersionSet; dyld3:latform basePlatform; dyld3:latform platform; const char* dyldPath; int argc; const char* const* argv; const char* const* envp; const char* const* apple; const char* progname; DyldCommPage commPage; const GradedArchs* archs; int pid; bool isTranslated; bool catalystRuntime; // Mac Catalyst app or iOS-on-mac app bool enableDataConst; // Temporarily allow disabling __DATA_CONST for bringup bool proactivelyUseWeakDefMap; const char* appleParam(const char* key) const; const char* environ(const char* key) const; const char* strdup(const char*) const; // allocates into read-only region void* roalloc(size_t) const; // allocates into read-only region private: friend class ProcessConfig; uint32_t findVersionSetEquivalent(dyld3:latform versionPlatform, uint32_t version) const; const char* pathFromFileHexStrings(SyscallDelegate& sys, const char* encodedFileInfo); const char* getDyldPath(SyscallDelegate& sys); const char* getMainPath(SyscallDelegate& syscall); const char* getMainUnrealPath(SyscallDelegate& syscall); dyld3:latform getMainPlatform(); const GradedArchs* getMainArchs(SyscallDelegate& osDelegate); bool usesCatalyst(); }; // // Contains security related config info // class Security { public: Security(Process& process, SyscallDelegate&); bool internalInstall; bool allowAtPaths; bool allowEnvVarsPrint; bool allowEnvVarsPath; bool allowEnvVarsSharedCache; bool allowClassicFallbackPaths; bool allowInsertFailures; bool allowInterposing; bool skipMain; private: uint64_t getAMFI(const Process& process, SyscallDelegate& syscall); void pruneEnvVars(Process& process); }; // // Contains logging related config info // class Logging { public: Logging(const Process& process, const Security& security, SyscallDelegate&); bool libraries; bool segments; bool fixups; bool initializers; bool apis; bool notifications; bool interposing; bool loaders; bool searching; bool env; int descriptor; bool useStderr; bool useFile; private: }; // // Contains dyld cache related config info // class DyldCache { public: DyldCache(Process&, const Security&, const Logging&, SyscallDelegate&); const DyldSharedCache* addr; uintptr_t slide; const char* path; const objc_opt:bjc_opt_t* objCCacheInfo; const SwiftOptimizationHeader* swiftCacheInfo; dyld3:latform platform; uint32_t osVersion; uint32_t dylibCount; bool indexOfPath(const char* dylibPath, uint32_t& dylibIndex) const; void makeDataConstWritable(const Logging&, const SyscallDelegate&, bool writable) const; private: friend class ProcessConfig; bool uuidOfFileMatchesDyldCache(const Process& process, const SyscallDelegate& syscall, const char* path) const; void setPlatformOSVersion(const Process& proc); void setupDyldCommPage(Process& process, const Security& security, SyscallDelegate& syscall); }; // // Contains path searching config info // class PathOverrides { public: PathOverrides(const Process&, const Security&, const Logging&, const DyldCache&, SyscallDelegate&); enum Type { pathDirOverride, versionedOverride, suffixOverride, catalystPrefix, simulatorPrefix, rawPath, rpathExpansion, loaderPathExpansion, executablePathExpansion, implictRpathExpansion, customFallback, standardFallback }; void forEachPathVariant(const char* requestedPath, dyld3:latform platform, bool disableCustomFallbacks, bool& stop, void (^handler)(const char* possiblePath, Type type, bool& stop)) const; void forEachInsertedDylib(void (^handler)(const char* dylibPath, bool &stop)) const; bool dontUsePrebuiltForApp() const; bool hasInsertedDylibs() const { return (_insertedDylibCount != 0); } uint32_t insertedDylibCount() const { return _insertedDylibCount; } const char* simRootPath() const { return _simRootPath; } static const char* getLibraryLeafName(const char* path); static const char* typeName(Type); private: void setEnvVars(const char* envp[], const char* mainExePath); void addEnvVar(const Process& process, const Security& security, const char* keyEqualsValue, bool isLC_DYLD_ENV, char* crashMsg); void processVersionedPaths(const Process& proc, SyscallDelegate&, const DyldCache&, dyld3:latform, const GradedArchs&); void forEachEnvVar(void (^handler)(const char* envVar)) const; void forEachExecutableEnvVar(void (^handler)(const char* envVar)) const; void setString(const Process& process, const char*& var, const char* value); static void forEachInColonList(const char* list1, const char* list2, void (^callback)(const char* path, bool& stop)); const char* getFrameworkPartialPath(const char* path) const; void handleListEnvVar(const char* key, const char** list, void (^handler)(const char* envVar)) const; void handleEnvVar(const char* key, const char* value, void (^handler)(const char* envVar)) const; void forEachDylibFallback(dyld3:latform platform, bool disableCustom, void (^handler)(const char* fallbackDir, Type type, bool& stop)) const; void forEachFrameworkFallback(dyld3:latform platform, bool disableCustom, void (^handler)(const char* fallbackDir, Type type, bool& stop)) const; void forEachImageSuffix(const char* path, Type type, bool& stop, void (^handler)(const char* possiblePath, Type type, bool& stop)) const; void addSuffix(const char* path, const char* suffix, char* result) const; void checkVersionedPath(const Process&, const char* path, SyscallDelegate& delegate, const DyldCache&, dyld3:latform platform, const GradedArchs& archs); void addPathOverride(const Process&, const char* installName, const char* overridePath); enum class FallbackPathMode { classic, restricted, none }; struct DylibOverride { DylibOverride* next; const char* installName; const char* overridePath; }; const char* _dylibPathOverridesEnv = nullptr; const char* _frameworkPathOverridesEnv = nullptr; const char* _dylibPathFallbacksEnv = nullptr; const char* _frameworkPathFallbacksEnv = nullptr; const char* _versionedDylibPathsEnv = nullptr; const char* _versionedFrameworkPathsEnv = nullptr; const char* _dylibPathOverridesExeLC = nullptr; const char* _frameworkPathOverridesExeLC = nullptr; const char* _dylibPathFallbacksExeLC = nullptr; const char* _frameworkPathFallbacksExeLC = nullptr; const char* _versionedFrameworkPathExeLC = nullptr; const char* _versionedDylibPathExeLC = nullptr; const char* _insertedDylibs = nullptr; const char* _imageSuffix = nullptr; const char* _simRootPath = nullptr; // simulator only DylibOverride* _versionedOverrides = nullptr; // linked list of VERSIONED overrides FallbackPathMode _fallbackPathMode = FallbackPathMode::classic; uint32_t _insertedDylibCount = 0; }; // wrappers for macOS that causes special three libsystem dylibs to not exist if they match what is in dyld cache bool simulatorFileMatchesDyldCache(const char* path) const; bool fileExists(const char* path, FileID* fileID=nullptr, bool* notAFile=nullptr) const; // if there is a dyld cache and the supplied path is in the dyld cache at that path or a symlink, return canonical path const char* canonicalDylibPathInCache(const char* dylibPath) const; // all instance variables are organized into groups SyscallDelegate syscall; Process process; Security security; Logging log; DyldCache dyldCache; PathOverrides pathOverrides;};
- 创建Allocator和APIs/RuntimeState对象: APIs& state = APIs::bootstrap(config, sLocks);
APIs继承自RuntimeState
class VIS_HIDDEN APIs : public RuntimeState{public:#if BUILDING_DYLD static APIs& bootstrap(const ProcessConfig& c, RuntimeLocks& locks);#else static APIs& bootstrap(const ProcessConfig& c);#endif // // private call from libdyld.dylib into dyld to tell that libSystem.dylib is initialized // virtual void _libdyld_initialize(const LibSystemHelpers* helpers); // // APIs from macOS 10.2 // virtual uint32_t _dyld_image_count(); virtual const mach_header* _dyld_get_image_header(uint32_t index); virtual intptr_t _dyld_get_image_vmaddr_slide(uint32_t index); virtual const char* _dyld_get_image_name(uint32_t index); virtual void _dyld_register_func_for_add_image(void (*func)(const mach_header* mh, intptr_t vmaddr_slide)); virtual void _dyld_register_func_for_remove_image(void (*func)(const mach_header* mh, intptr_t vmaddr_slide)); virtual int32_t NSVersionOfLinkTimeLibrary(const char* libraryName); virtual int32_t NSVersionOfRunTimeLibrary(const char* libraryName); virtual int _NSGetExecutablePath(char* buf, uint32_t* bufsize); virtual void _dyld_fork_child(); // // APIs from macOS 10.4 // virtual int dladdr(const void*, Dl_info* result); virtual void* dlopen(const char* path, int mode); virtual int dlclose(void* handle); virtual char* dlerror(); virtual void* dlsym(void* handle, const char* symbol); virtual bool dlopen_preflight(const char* path); // // APIs deprecated in macOS 10.5 and not on any other platform // virtual NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* pathName, NSObjectFileImage* objectFileImage); virtual NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void* address, size_t size, NSObjectFileImage* objectFileImage); virtual bool NSDestroyObjectFileImage(NSObjectFileImage objectFileImage); virtual bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage objectFileImage, const char* symbolName); virtual void* NSGetSectionDataInObjectFileImage(NSObjectFileImage objectFileImage, const char* segmentName, const char* sectionName, size_t* size); virtual const char* NSNameOfModule(NSModule m); virtual const char* NSLibraryNameForModule(NSModule m); virtual NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName, uint32_t options); virtual bool NSUnLinkModule(NSModule module, uint32_t options); virtual bool NSIsSymbolNameDefined(const char* symbolName); virtual bool NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNameHint); virtual bool NSIsSymbolNameDefinedInImage(const mach_header* image, const char* symbolName); virtual NSSymbol NSLookupAndBindSymbol(const char* symbolName); virtual NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libraryNameHint); virtual NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName); virtual NSSymbol NSLookupSymbolInImage(const mach_header* image, const char* symbolName, uint32_t options); virtual void* NSAddressOfSymbol(NSSymbol symbol); virtual NSModule NSModuleForSymbol(NSSymbol symbol); virtual void NSLinkEditError(NSLinkEditErrors* c, int* errorNumber, const char** fileName, const char** errorString); virtual bool NSAddLibrary(const char* pathName); virtual bool NSAddLibraryWithSearching(const char* pathName); virtual const mach_header* NSAddImage(const char* image_name, uint32_t options); virtual bool _dyld_image_containing_address(const void* address); virtual void _dyld_lookup_and_bind(const char* symbol_name, void** address, NSModule* module); virtual void _dyld_lookup_and_bind_with_hint(const char* symbol_name, const char* library_name_hint, void** address, NSModule* module); virtual void _dyld_lookup_and_bind_fully(const char* symbol_name, void** address, NSModule* module); // // Added macOS 10.6 // virtual intptr_t _dyld_get_image_slide(const mach_header* mh); virtual const char* dyld_image_path_containing_address(const void* addr);#if !__USING_SJLJ_EXCEPTIONS__ virtual bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info);#endif // // Added iOS 6, macOS 10.8 // virtual uint32_t dyld_get_sdk_version(const mach_header* mh); virtual uint32_t dyld_get_min_os_version(const mach_header* mh); virtual uint32_t dyld_get_program_sdk_version(); virtual uint32_t dyld_get_program_min_os_version(); // // Added iOS 7, macOS 10.9 // virtual bool dyld_process_is_restricted(); // // Added iOS 8, macOS 10.10 // virtual bool dyld_shared_cache_some_image_overridden(); virtual void _tlv_atexit(void (*termFunc)(void* objAddr), void* objAddr); virtual void _tlv_bootstrap(); virtual void _tlv_exit(); // // Added iOS 9, macOS 10.11, watchOS 2.0 // virtual int dyld_shared_cache_iterate_text(const uuid_t cacheUuid, void (^callback)(const dyld_shared_cache_dylib_text_info* info)); virtual const mach_header* dyld_image_header_containing_address(const void* addr); virtual const char* dyld_shared_cache_file_path(); virtual uint32_t dyld_get_program_sdk_watch_os_version(); virtual uint32_t dyld_get_program_min_watch_os_version(); // // Added iOS 10, macOS 10.12, watchOS 3.0 // virtual void _dyld_objc_notify_register(_dyld_objc_notify_mapped, _dyld_objc_notify_init, _dyld_objc_notify_unmapped); virtual bool _dyld_get_image_uuid(const mach_header* mh, uuid_t uuid); virtual bool _dyld_get_shared_cache_uuid(uuid_t uuid); virtual bool _dyld_is_memory_immutable(const void* addr, size_t length); virtual int dyld_shared_cache_find_iterate_text(const uuid_t cacheUuid, const char* extraSearchDirs[], void (^callback)(const dyld_shared_cache_dylib_text_info* info)); // // Added iOS 11, macOS 10.13, bridgeOS 2.0 // virtual const void* _dyld_get_shared_cache_range(size_t* length); virtual uint32_t dyld_get_program_sdk_bridge_os_version(); virtual uint32_t dyld_get_program_min_bridge_os_version(); // // Added iOS 12, macOS 10.14 // virtual dyld_platform_t dyld_get_active_platform(); virtual dyld_platform_t dyld_get_base_platform(dyld_platform_t platform); virtual bool dyld_is_simulator_platform(dyld_platform_t platform); virtual bool dyld_sdk_at_least(const mach_header* mh, dyld_build_version_t version); virtual bool dyld_minos_at_least(const mach_header* mh, dyld_build_version_t version); virtual bool dyld_program_sdk_at_least(dyld_build_version_t version); virtual bool dyld_program_minos_at_least(dyld_build_version_t version); virtual void dyld_get_image_versions(const mach_header* mh, void (^callback)(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version)); virtual void _dyld_images_for_addresses(unsigned count, const void* addresses[], dyld_image_uuid_offset infos[]); virtual void _dyld_register_for_image_loads(void (*func)(const mach_header* mh, const char* path, bool unloadable)); // // Added iOS 13, macOS 10.15 // virtual void _dyld_atfork_prepare(); virtual void _dyld_atfork_parent(); virtual bool dyld_need_closure(const char* execPath, const char* dataContainerRootDir); virtual bool dyld_has_inserted_or_interposing_libraries(void); virtual bool _dyld_shared_cache_optimized(void); virtual bool _dyld_shared_cache_is_locally_built(void); virtual void _dyld_register_for_bulk_image_loads(void (*func)(unsigned imageCount, const mach_header* mhs[], const char* paths[])); virtual void _dyld_register_driverkit_main(void (*mainFunc)(void)); virtual void _dyld_missing_symbol_abort(); virtual const char* _dyld_get_objc_selector(const char* selName); virtual void _dyld_for_each_objc_class(const char* className, void (^)(void* classPtr, bool isLoaded, bool* stop)); virtual void _dyld_for_each_objc_protocol(const char* protocolName, void (^)(void* protocolPtr, bool isLoaded, bool* stop)); // // Added iOS 14, macOS 11 // virtual uint32_t _dyld_launch_mode(); virtual bool _dyld_is_objc_constant(DyldObjCConstantKind kind, const void* addr); virtual bool _dyld_has_fix_for_radar(const char* rdar); virtual const char* _dyld_shared_cache_real_path(const char* path); virtual bool _dyld_shared_cache_contains_path(const char* path); virtual void* dlopen_from(const char* path, int mode, void* addressInCaller);#if !__i386__ virtual void * dlopen_audited(const char * path, int mode);#endif virtual const struct mach_header* _dyld_get_prog_image_header(); // // Added iOS 15, macOS 12 // virtual void obsolete() __attribute__((noreturn)); virtual void _dyld_visit_objc_classes(void (^callback)(const void* classPtr)); virtual uint32_t _dyld_objc_class_count(void); virtual bool _dyld_objc_uses_large_shared_cache(void); virtual _dyld_protocol_conformance_result _dyld_find_protocol_conformance(const void *protocolDescriptor, const void *metadataType, const void *typeDescriptor) const; virtual _dyld_protocol_conformance_result _dyld_find_foreign_type_protocol_conformance(const void *protocol, const char *foreignTypeIdentityStart, size_t foreignTypeIdentityLength) const; virtual uint32_t _dyld_swift_optimizations_version() const; virtual void runAllInitializersForMain(); virtual void _dyld_before_fork_dlopen(); virtual void _dyld_after_fork_dlopen_parent(); virtual void _dyld_after_fork_dlopen_child();private:#if BUILDING_DYLD APIs(const ProcessConfig& c, RuntimeLocks& locks, Allocator* alloc) : RuntimeState(c, locks, *alloc) {}#else APIs(const ProcessConfig& c, Allocator* alloc) : RuntimeState(c, *alloc) {}#endif // internal helpers uint32_t getSdkVersion(const mach_header* mh); dyld_build_version_t mapFromVersionSet(dyld_build_version_t version); uint32_t linkedDylibVersion(const dyld3::MachOFile* mf, const char* installname); uint32_t deriveVersionFromDylibs(const dyld3::MachOFile* mf); void forEachPlatform(const dyld3::MachOFile* mf, void (^callback)(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version)); uint32_t basePlaform(uint32_t reqPlatform) const; bool findImageMappedAt(const void* addr, const MachOLoaded** ml, bool* neverUnloads = nullptr, const char** path = nullptr, const void** segAddr = nullptr, uint64_t* segSize = nullptr, uint8_t* segPerms = nullptr); void clearErrorString(); void setErrorString(const char* format, ...) __attribute__((format(printf, 2, 3))); const Loader* findImageContaining(void* addr); bool flatFindSymbol(const char* symbolName, void** symbolAddress, const mach_header** foundInImageAtLoadAddress); bool validLoader(const Loader* maybeLoader); void forEachImageVersion(const mach_header* mh, void (^callback)(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version));};//// Note: need to force vtable ptr auth so that libdyld.dylib from base OS and driverkit use same ABI//class [[clang::ptrauth_vtable_pointer(process_independent, address_discrimination, type_discrimination)]] RuntimeState{public: const ProcessConfig& config; Allocator& longTermAllocator; const Loader* mainExecutableLoader = nullptr; Vector<ConstAuthLoader> loaded; const Loader* libSystemLoader = nullptr; const Loader* libdyldLoader = nullptr; const void* libdyldMissingSymbol = 0;#if BUILDING_DYLD RuntimeLocks& _locks;#endif dyld4::ProgramVars* vars = nullptr; const LibSystemHelpers* libSystemHelpers = nullptr; Vector<InterposeTupleAll> interposingTuplesAll; Vector<InterposeTupleSpecific> interposingTuplesSpecific; uint64_t weakDefResolveSymbolCount = 0; WeakDefMap* weakDefMap = nullptr;#if BUILDING_DYLD RuntimeState(const ProcessConfig& c, RuntimeLocks& locks, Allocator& alloc)#else RuntimeState(const ProcessConfig& c, Allocator& alloc = *Allocator::bootstrap())#endif : config(c), longTermAllocator(alloc), loaded(&alloc),#if BUILDING_DYLD _locks(locks),#endif interposingTuplesAll(&alloc), interposingTuplesSpecific(&alloc), _notifyAddImage(&alloc), _notifyRemoveImage(&alloc), _notifyLoadImage(&alloc), _notifyBulkLoadImage(&alloc), _tlvInfos(&alloc), _loadersNeedingDOFUnregistration(&alloc), _missingFlatLazySymbols(&alloc), _dynamicReferences(&alloc), _dlopenRefCounts(&alloc), _dynamicNeverUnloads(&alloc) {} void setMainLoader(const Loader*); void add(const Loader*); MainFunc mainFunc() { return _driverKitMain; } void setMainFunc(MainFunc func) { _driverKitMain = func; } void setDyldLoader(const Loader* ldr); uint8_t* appState(uint16_t index); uint8_t* cachedDylibState(uint16_t index); const MachOLoaded* appLoadAddress(uint16_t index); void setAppLoadAddress(uint16_t index, const MachOLoaded* ml); const MachOLoaded* cachedDylibLoadAddress(uint16_t index); void log(const char* format, ...) const __attribute__((format(printf, 2, 3))) ; void vlog(const char* format, va_list list); void setObjCNotifiers(_dyld_objc_notify_mapped, _dyld_objc_notify_init, _dyld_objc_notify_unmapped); void addNotifyAddFunc(const Loader* callbackLoader, NotifyFunc); void addNotifyRemoveFunc(const Loader* callbackLoader, NotifyFunc); void addNotifyLoadImage(const Loader* callbackLoader, LoadNotifyFunc); void addNotifyBulkLoadImage(const Loader* callbackLoader, BulkLoadNotifier); void notifyObjCInit(const Loader* ldr); void buildInterposingTables(); void withNotifiersReadLock(void (^work)()); void withNotifiersWriteLock(void (^work)()); void addPermanentRanges(const Array<const Loader*>& neverUnloadLoaders); bool inPermanentRange(uintptr_t start, uintptr_t end, uint8_t* perms, const Loader** loader); void notifyLoad(const dyld3::Array<const Loader*>& newLoaders); void notifyUnload(const dyld3::Array<const Loader*>& removeLoaders); void notifyDebuggerLoad(const Loader* oneLoader); void notifyDebuggerLoad(const dyld3::Array<const Loader*>& newLoaders); void notifyDebuggerUnload(const dyld3::Array<const Loader*>& removingLoaders); void notifyDtrace(const dyld3::Array<const Loader*>& newLoaders); void incDlRefCount(const Loader* ldr); // used by dlopen void decDlRefCount(const Loader* ldr); // used by dlclose void setLaunchMissingDylib(const char* missingDylibPath, const char* clientUsingDylib); void setLaunchMissingSymbol(const char* missingSymbolName, const char* dylibThatShouldHaveSymbol, const char* clientUsingSymbol); void addMissingFlatLazySymbol(const Loader* ldr, const char* symbolName, uintptr_t* bindLoc); void rebindMissingFlatLazySymbols(const dyld3::Array<const Loader*>& newLoaders); void removeMissingFlatLazySymbols(const dyld3::Array<const Loader*>& removingLoaders); bool hasMissingFlatLazySymbols() const; void addDynamicReference(const Loader* from, const Loader* to); void removeDynamicDependencies(const Loader* removee); void setSavedPrebuiltLoaderSet() { _wrotePrebuiltLoaderSet = true; } bool didSavePrebuiltLoaderSet() const { return _wrotePrebuiltLoaderSet; } void setVMAccountingSuspending(bool mode); bool hasOverriddenCachedDylib() { return _hasOverriddenCachedDylib; } void setHasOverriddenCachedDylib() { _hasOverriddenCachedDylib = true; } pthread_key_t dlerrorPthreadKey() { return _dlerrorPthreadKey; } typedef void (*TLV_TermFunc)(void* objAddr); void initialize(); void setUpTLVs(const MachOAnalyzer* ma); void addTLVTerminationFunc(TLV_TermFunc func, void* objAddr); void exitTLV(); void withLoadersReadLock(void (^work)()); void withLoadersWriteLock(void (^work)()); void incWritable(); void decWritable(); void initializeClosureMode(); const PrebuiltLoaderSet* processPrebuiltLoaderSet() const { return _processPrebuiltLoaderSet; } const PrebuiltLoaderSet* cachedDylibsPrebuiltLoaderSet() const { return _cachedDylibsPrebuiltLoaderSet; } uint8_t* prebuiltStateArray(bool app) const { return (app ? _processDylibStateArray : _cachedDylibsStateArray); } const PrebuiltLoader* findPrebuiltLoader(const char* loadPath) const; bool saveAppClosureFile() const { return _saveAppClosureFile; } bool failIfCouldBuildAppClosureFile() const { return _failIfCouldBuildAppClosureFile; } bool saveAppPrebuiltLoaderSet(const PrebuiltLoaderSet* pblset) const; bool inPrebuiltLoader(const void* p, size_t len) const;#if !BUILDING_DYLD void resetCachedDylibs(const PrebuiltLoaderSet* dylibs, uint8_t* stateArray); void setProcessPrebuiltLoaderSet(const PrebuiltLoaderSet* appPBLS); void resetCachedDylibsArrays();#endif // this need to be virtual to be callable from libdyld.dylb virtual void _finalizeListTLV(void* l); virtual void* _instantiateTLVs(pthread_key_t key);protected: // Helpers to reset locks across fork() void takeLockBeforeFork(); void releaseLockInForkParent(); void resetLockInForkChild(); void takeDlopenLockBeforeFork(); void releaseDlopenLockInForkParent(); void resetDlopenLockInForkChild();private: // // The PermanentRanges structure is used to make dyld_is_memory_immutable() // fast and lock free. The table contains just ranges of memory that are in // images that will never be unloaded. Dylibs in the dyld shared cache are // never in this table. A PermanentRanges struct is allocated at launch for // app and its non-cached dylibs, because they can never be unloaded. Later // if a dlopen() brings in non-cached dylibs which can never be unloaded, // another PermanentRanges is allocated with the ranges brought in by that // dlopen. The PermanentRanges struct are chained together in a linked list // with state._permanentRanges pointing to the start of the list. // Because these structs never change, they can be read without taking a lock. // That makes finding immutable ranges lock-less. // class PermanentRanges { public: static PermanentRanges* make(RuntimeState& state, const Array<const Loader*>& neverUnloadLoaders); bool contains(uintptr_t start, uintptr_t end, uint8_t* perms, const Loader** loader) const; PermanentRanges* next() const; void append(PermanentRanges*); private: void addPermanentRange(uintptr_t start, uintptr_t end, bool immutable, const Loader* loader); void add(const Loader*); struct Range { uintptr_t start; uintptr_t end; const Loader* loader; uintptr_t permissions; }; // FIXME: we could pack this structure better to reduce memory usage std::atomic<ermanentRanges*> _next = nullptr; uintptr_t _rangeCount = 0; Range _ranges[1]; }; // keep dlopen counts in a side table because it is rarely used, so it would waste space for each Loader object to have its own count field friend class Reaper; friend class RecursiveAutoLock; struct DlopenCount { const Loader* loader; uintptr_t refCount; }; // when a thread_local is first accessed on a thread, the thunk calls into dyld // to allocate the variables. The pthread_key is the index used to find the // TLV_Info which then describes how much to allocate and how to initalize that memory. struct TLV_Info { const MachOAnalyzer* ma; pthread_key_t key; uint32_t initialContentOffset; uint32_t initialContentSize; }; // used to record _tlv_atexit() entries to clean up on thread exit struct TLV_Terminator { TLV_TermFunc termFunc; void* objAddr; }; struct TLV_TerminatorList { TLV_TerminatorList* next = nullptr; uintptr_t count = 0; TLV_Terminator elements[7]; void reverseWalkChain(void (^work)(TLV_TerminatorList*)); }; struct RegisteredDOF { const Loader* ldr; int registrationID; }; struct MissingFlatSymbol { const Loader* ldr; const char* symbolName; uintptr_t* bindLoc; }; struct DynamicReference { const Loader* from; const Loader* to; }; struct HiddenCacheAddr { const void* cacheAddr; const void* replacementAddr; }; enum { kMaxBootTokenSize = 128 }; void appendInterposingTuples(const Loader* ldr, const uint8_t* dylibTuples, uint32_t tupleCount); void garbageCollectImages(); void garbageCollectInner(); void removeLoaders(const dyld3::Array<const Loader*>& loadersToRemove); void withTLVLock(void (^work)()); void setUpLogging(); void buildAppPrebuiltLoaderSetPath(bool createDirs); bool fileAlreadyHasBootToken(const char* path, const Array<uint8_t>& bootToken) const; bool buildBootToken(dyld3::Array<uint8_t>& bootToken) const; void loadAppPrebuiltLoaderSet(); bool allowOsProgramsToSaveUpdatedClosures() const; bool allowNonOsProgramsToSaveUpdatedClosures() const; void allocateProcessArrays(uintptr_t count); void checkHiddenCacheAddr(const Loader* t, const void* targetAddr, const char* symbolName, dyld3::OverflowSafeArray<HiddenCacheAddr>& hiddenCacheAddrs) const; _dyld_objc_notify_mapped _notifyObjCMapped = nullptr; _dyld_objc_notify_init _notifyObjCInit = nullptr; _dyld_objc_notify_unmapped _notifyObjCUnmapped = nullptr; Vector<NotifyFunc> _notifyAddImage; Vector<NotifyFunc> _notifyRemoveImage; Vector<LoadNotifyFunc> _notifyLoadImage; Vector<BulkLoadNotifier> _notifyBulkLoadImage; Vector<TLV_Info> _tlvInfos; Vector<RegisteredDOF> _loadersNeedingDOFUnregistration; Vector<MissingFlatSymbol> _missingFlatLazySymbols; Vector<DynamicReference> _dynamicReferences; const PrebuiltLoaderSet* _cachedDylibsPrebuiltLoaderSet = nullptr; uint8_t* _cachedDylibsStateArray = nullptr; const char* _processPrebuiltLoaderSetPath = nullptr; const PrebuiltLoaderSet* _processPrebuiltLoaderSet = nullptr; uint8_t* _processDylibStateArray = nullptr; const MachOLoaded** _processLoadedAddressArray = nullptr; bool _saveAppClosureFile; bool _failIfCouldBuildAppClosureFile; PermanentRanges* _permanentRanges = nullptr; MainFunc _driverKitMain = nullptr; Vector<DlopenCount> _dlopenRefCounts; Vector<const Loader*> _dynamicNeverUnloads; std::atomic<int32_t> _gcCount = 0; pthread_key_t _tlvTerminatorsKey = 0; pthread_key_t _dlerrorPthreadKey = 0; int _logDescriptor = -1; bool _logToSyslog = false; bool _logSetUp = false; bool _hasOverriddenCachedDylib = false; bool _wrotePrebuiltLoaderSet = false;#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR bool _vmAccountingSuspended = false;#endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR};
- 加载步伐的全部依靠项并将state绑定在一起:prepare(state, dyldMA);
- 调用main(): appMain
2.prepare:加载步伐的全部依靠项
- gProcessInfo 是存储dyld全部镜像信息的结构体:,生存着mach_header, dyld_uuid_info, dyldVersion等等信息。
gProcessInfo的声明:
struct dyld_all_image_infos* gProcessInfo = &dyld_all_image_infos;
struct dyld_all_image_infos { uint32_t version; /* 1 in Mac OS X 10.4 and 10.5 */ uint32_t infoArrayCount;#if defined(__cplusplus) && (BUILDING_LIBDYLD || BUILDING_DYLD) std::atomic<const struct dyld_image_info*> infoArray;#else const struct dyld_image_info* infoArray;#endif dyld_image_notifier notification; bool processDetachedFromSharedRegion; /* the following fields are only in version 2 (Mac OS X 10.6, iPhoneOS 2.0) and later */ bool libSystemInitialized; const struct mach_header* dyldImageLoadAddress; /* the following field is only in version 3 (Mac OS X 10.6, iPhoneOS 3.0) and later */ void* jitInfo; /* the following fields are only in version 5 (Mac OS X 10.6, iPhoneOS 3.0) and later */ const char* dyldVersion; const char* errorMessage; uintptr_t terminationFlags; /* the following field is only in version 6 (Mac OS X 10.6, iPhoneOS 3.1) and later */ void* coreSymbolicationShmPage; /* the following field is only in version 7 (Mac OS X 10.6, iPhoneOS 3.1) and later */ uintptr_t systemOrderFlag; /* the following field is only in version 8 (Mac OS X 10.7, iPhoneOS 3.1) and later */ uintptr_t uuidArrayCount; const struct dyld_uuid_info* uuidArray; /* only images not in dyld shared cache */ /* the following field is only in version 9 (Mac OS X 10.7, iOS 4.0) and later */ struct dyld_all_image_infos* dyldAllImageInfosAddress; /* the following field is only in version 10 (Mac OS X 10.7, iOS 4.2) and later */ uintptr_t initialImageCount; /* the following field is only in version 11 (Mac OS X 10.7, iOS 4.2) and later */ uintptr_t errorKind; const char* errorClientOfDylibPath; const char* errorTargetDylibPath; const char* errorSymbol; /* the following field is only in version 12 (Mac OS X 10.7, iOS 4.3) and later */ uintptr_t sharedCacheSlide; /* the following field is only in version 13 (Mac OS X 10.9, iOS 7.0) and later */ uint8_t sharedCacheUUID[16]; /* the following field is only in version 15 (macOS 10.12, iOS 10.0) and later */ uintptr_t sharedCacheBaseAddress;#if defined(__cplusplus) && (BUILDING_LIBDYLD || BUILDING_DYLD) // We want this to be atomic in libdyld so that we can see updates when we map it shared std::atomic<uint64_t> infoArrayChangeTimestamp;#else uint64_t infoArrayChangeTimestamp;#endif const char* dyldPath; mach_port_t notifyPorts[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT];#if __LP64__ uintptr_t reserved[11-(DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT/2)];#else uintptr_t reserved[9-DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT];#endif // The following fields were added in version 18 (previously they were reserved padding fields) uint64_t sharedCacheFSID; uint64_t sharedCacheFSObjID; /* the following field is only in version 16 (macOS 10.13, iOS 11.0) and later */ uintptr_t compact_dyld_image_info_addr; size_t compact_dyld_image_info_size; uint32_t platform; // FIXME: really a dyld_platform_t, but those aren't exposed here. /* the following field is only in version 17 (macOS 10.16) and later */ uint32_t aotInfoCount; const struct dyld_aot_image_info* aotInfoArray; uint64_t aotInfoArrayChangeTimestamp; uintptr_t aotSharedCacheBaseAddress; uint8_t aotSharedCacheUUID[16];};
- 举行pre-build, 创建 mainLoader镜像装载器
ps : 假如熟悉dyld3的小搭档知道, 旧版本是创建一个ImageLoader镜像装载器
- 创建just-in-time
是dyld4一个新特性, dyld4在生存了dyld3的 mach-o 剖析器根本上,同时也引入了 just-in-time 的加载器来优化。
dyld3 出于对启动速率的优化的目标, 增长了预构建(闭包)。App第一次启动大概App发生厘革时会将部门启动数据创建为闭包存到当地,那么App下次启动将不再重新剖析数据,而是直接读取闭包内容。当然条件是应用步伐和体系应很少发生厘革,但假如这两者经常厘革等, 就会导闭包丢失或失效。
dyld4 采取了 pre-build + just-in-time 的双剖析模式,预构建 pre-build 对应的就是 dyld3 中的闭包,just-in-time 可以明白为及时剖析。当然just-in-time 也是可以利用 pre-build 的缓存的,以是性能可控。有了just-in-time, 目前应用初次启动、体系版本更新、平凡启动,dyld4 则可以根据缓存是否有用去选择符合的模式举行剖析。
记录插入信息, 遍历全部dylibs, 一些记录查抄操纵继承往下走
Loader::applyInterposingToDyldCache的实现:
void Loader::applyInterposingToDyldCache(RuntimeState& state){ const DyldSharedCache* dyldCache = state.config.dyldCache.addr; if ( dyldCache == nullptr ) return; // no dyld cache to interpose if ( state.interposingTuplesAll.empty() ) return; // no interposing tuples // make the cache writable for this block DyldCacheDataConstScopedWriter patcher(state); state.setVMAccountingSuspending(true); for ( const InterposeTupleAll& tuple : state.interposingTuplesAll ) { uint32_t imageIndex; uintptr_t cacheOffsetOfReplacee = tuple.replacee - (uintptr_t)dyldCache; if ( !dyldCache->addressInText(cacheOffsetOfReplacee, &imageIndex) ) continue; // Convert from a cache offset to an image offset uint64_t mTime; uint64_t inode; const dyld3::MachOAnalyzer* imageMA = (dyld3::MachOAnalyzer*)(dyldCache->getIndexedImageEntry(imageIndex, mTime, inode)); if ( imageMA == nullptr ) continue; uint32_t dylibOffsetOfReplacee = (uint32_t)((dyldCache->unslidLoadAddress() + cacheOffsetOfReplacee) - imageMA->preferredLoadAddress()); dyldCache->forEachPatchableExport(imageIndex, ^(uint32_t dylibVMOffsetOfImpl, const char* exportName) { // Skip patching anything other than this symbol if ( dylibVMOffsetOfImpl != dylibOffsetOfReplacee ) return; uintptr_t newLoc = tuple.replacement; dyldCache->forEachPatchableUseOfExport(imageIndex, dylibVMOffsetOfImpl, ^(uint64_t cacheVMOffset, MachOLoaded::PointerMetaData pmd, uint64_t addend) { uintptr_t* loc = (uintptr_t*)((uintptr_t)dyldCache + cacheVMOffset); uintptr_t newValue = newLoc + (uintptr_t)addend; #if __has_feature(ptrauth_calls) if ( pmd.authenticated ) { newValue = dyld3::MachOLoaded::ChainedFixupPointerOnDisk::Arm64e::signPointer(newValue, loc, pmd.usesAddrDiversity, pmd.diversity, pmd.key); *loc = newValue; if ( state.config.log.interposing ) state.log("interpose: *%p = %p (JOP: diversity 0x%04X, addr-div=%d, key=%s)\n", loc, (void*)newValue, pmd.diversity, pmd.usesAddrDiversity, MachOLoaded::ChainedFixupPointerOnDisk::Arm64e::keyName(pmd.key)); return; } #endif if ( state.config.log.interposing ) state.log("interpose: *%p = 0x%0llX (dyld cache patch) to %s\n", loc, newLoc + addend, exportName); *loc = newValue; }); }); } state.setVMAccountingSuspending(false);}接下来的工作是一些其他关照和写入操纵。
// 运行全部的初始化 state.runAllInitializersForMain();3.runAllInitializersForMain:运行初始化方法
// 这是从dyldMain.cpp中提取出来的,以支持利用crt1.o的旧macOS应用步伐void APIs::runAllInitializersForMain(){ // 起首运行libSystem的初始化器 const_cast<Loader*>(this->libSystemLoader)->beginInitializers(*this); this->libSystemLoader->runInitializers(*this); gProcessInfo->libSystemInitialized = true; // 在运行libSystem的初始化器后,告诉objc在libSystem的子dylibs上运行任何+load方法 this->notifyObjCInit(this->libSystemLoader); // <rdar://problem/32209809> 调用'init'函数对全部已经init'ed的图像 (below libSystem) // 利用下标举行迭代,以便在+加载dloopen时数组不会在我们下面增长 for ( uint32_t i = 0; i != this->loaded.size(); ++i ) { const Loader* ldr = this->loaded; if ( ldr->analyzer(*this)->isDylib() && (strncmp(ldr->analyzer(*this)->installName(), "/usr/lib/system/lib", 19) == 0) ) { // 查抄安装名称而不是路径,以处置惩罚libsystem子dylibs的DYLD_LIBRARY_PATH覆盖 const_cast<Loader*>(ldr)->beginInitializers(*this); this->notifyObjCInit(ldr); } } // 自底向上运行全部其他初始化器,起首运行插入的dylib初始化器 // 利用下标举行迭代,以便在初始化式dloopen时数组不会在下面增长 for ( uint32_t i = 0; i != this->loaded.size(); ++i ) { const Loader* ldr = this->loaded; ldr->runInitializersBottomUpPlusUpwardLinks(*this); // stop as soon as we did main executable // normally this is first image, but if there are inserted N dylibs, it is Nth in the list if ( ldr->analyzer(*this)->isMainExecutable() ) break; }}
- 告诉objc在libSystem的子dylibs上运行全部的+load方法
(可实行文件、动态库等等上面的load)
notifyObjCInit 这个工作在第4部门介绍
- link 动态库和主步伐: runInitializersBottomUpPlusUpwardLinks
runInitializersBottomUpPlusUpwardLinks 这个工作在第5部门介绍
4.notifyObjCInit
在libSystem的初始化时,在其子dylibs上必要关照objc运行全部的+load方法
notifyObjCInit的界说是在RuntimeState类的声明里:
_dyld_objc_notify_init 在setObjCNotifiers被赋值的:
那setObjCNotifiers是在_dyld_objc_notify_register被调用的
而_dyld_objc_notify_register是在objc4源码里的 objc_init()里被调用的
末了objc_init()在库初始化时间之前由libSystem调用。
ps: load_images的内容在下章节,知道它是用来举行加载和调用+load方法就够了。
5.link 动态库和主步伐: runInitializersBottomUpPlusUpwardLinks
void Loader::runInitializersBottomUpPlusUpwardLinks(RuntimeState& state) const{ //state.log("runInitializersBottomUpPlusUpwardLinks() %s\n", this->path()); state.incWritable(); // 递归地运行全部初始化器 initializers STACK_ALLOC_ARRAY(const Loader*, danglingUpwards, state.loaded.size()); this->runInitializersBottomUp(state, danglingUpwards); //state.log("runInitializersBottomUpPlusUpwardLinks(%s), found %d dangling upwards\n", this->path(), danglingUpwards.count()); // 返回全部向上链接的image,并查抄它们是否已初始化 (might be danglers) STACK_ALLOC_ARRAY(const Loader*, extraDanglingUpwards, state.loaded.size()); for ( const Loader* ldr : danglingUpwards ) { //state.log("running initializers for dangling upward link %s\n", ldr->path()); ldr->runInitializersBottomUp(state, extraDanglingUpwards); } if ( !extraDanglingUpwards.empty() ) { // 假如有两个向上悬空的image,请再次查抄初始化器initializers danglingUpwards.resize(0); for ( const Loader* ldr : extraDanglingUpwards ) { //state.log("running initializers for dangling upward link %s\n", ldr->path()); ldr->runInitializersBottomUp(state, danglingUpwards); } } state.decWritable();}runInitializersBottomUp
void Loader::runInitializersBottomUp(RuntimeState& state, Array<const Loader*>& danglingUpwards) const{ // 假如已经初始化器已经运行就什么都不做 if ( (const_cast<Loader*>(this))->beginInitializers(state) ) return; //state.log("runInitializersBottomUp(%s)\n", this->path()); // 在运行我的初始化器之前,确保这个image下面的全部东西都已初始化 const uint32_t depCount = this->dependentCount(); for ( uint32_t i = 0; i < depCount; ++i ) { DependentKind childKind; if ( Loader* child = this->dependent(state, i, &childKind) ) { if ( childKind == DependentKind::upward ) { // 向上添加到列表稍后处置惩罚 if ( !danglingUpwards.contains(child) ) danglingUpwards.push_back(child); } else { child->runInitializersBottomUp(state, danglingUpwards); } } } // tell objc to run any +load methods in this image (done before C++ initializers) state.notifyObjCInit(this); // run initializers for this image this->runInitializers(state);}6.调起主步伐入口
在 prepare 函数调用末了返回的就是主步伐入口 MainFunc
在start函数里调用了主步伐入口
末了给个总结图
dyld4应用步伐加载流程图
dyld3应用步伐加载流程图:
|