热点新闻
iOS 分析dyld工作过程 dyld-941.5源码
2023-07-06 21:26  浏览:2577  搜索引擎搜索“混灰机械网”
温馨提示:信息一旦丢失不一定找得到,请务必收藏信息以备急用!本站所有信息均是注册会员发布如遇到侵权请联系文章中的联系方式或客服删除!
联系我时,请说明是在混灰机械网看到的信息,谢谢。
展会发布 展会网站大全 报名观展合作 软文发布

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()函数作为关键点分割成两块




main()函数启动分块.png

t1阶段main()之前的处理所需时间,称为pre-main




t1阶段.png

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 CommandsectionOther 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工作流程




dyld流程

新建一个工程,在ViewController.m里重写+(void)load方法,在load方法上打个断点调试,运行app后在断点处输出其函数调用的堆栈:




dyld4模拟器 入口




dyld4真机 入口

新版本dyld: start开始接下来走 dyld4中prepare方法, 源码入口需要在start中开始探索。
(旧版本dyld: _dyld_start开始, 接下来走dyldbootstrap, 源码入口需要在dyld_start开始。)




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 chainsrebase 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::Platform basePlatform; dyld3::Platform 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::Platform 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::Platform 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::objc_opt_t* objCCacheInfo; const SwiftOptimizationHeader* swiftCacheInfo; dyld3::Platform 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::Platform 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::Platform, 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::Platform platform, bool disableCustom, void (^handler)(const char* fallbackDir, Type type, bool& stop)) const; void forEachframeworkFallback(dyld3::Platform 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::Platform 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<PermanentRanges*> _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; 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; bool libSystemInitialized; const struct mach_header* dyldImageLoadAddress; void* jitInfo; const char* dyldVersion; const char* errorMessage; uintptr_t terminationFlags; void* coreSymbolicationShmPage; uintptr_t systemOrderFlag; uintptr_t uuidArrayCount; const struct dyld_uuid_info* uuidArray; struct dyld_all_image_infos* dyldAllImageInfosAddress; uintptr_t initialImageCount; uintptr_t errorKind; const char* errorClientOfDylibPath; const char* errorTargetDylibPath; const char* errorSymbol; uintptr_t sharedCacheSlide; uint8_t sharedCacheUUID[16]; 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; 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. 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镜像装载器



mainLoader






  • 创建just-in-time
    dyld4一个新特性, dyld4在保留了dyld3mach-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 则可以根据缓存是否有效去选择合适的模式进行解析。

  • 装载uuid、动态库、可执行文件










记录插入信息, 遍历所有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[i]; 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[i]; 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; } }

  • 运行libSystem的初始化器





  • 告诉objclibSystem的子dylibs上运行所有的+load方法
    (可执行文件、动态库等等上面的load)





notifyObjCInit 这个工作在第4部分介绍

  • link 动态库和主程序: runInitializersBottomUpPlusUpwardlinks





runInitializersBottomUpPlusUpwardlinks 这个工作在第5部分介绍

4.notifyObjCInit

libSystem的初始化时,在其子dylibs上需要通知objc运行所有的+load方法






notifyObjCInit的定义是在RuntimeState类的声明里:






_dyld_objc_notify_initsetObjCNotifiers被赋值的:






setObjCNotifiers是在_dyld_objc_notify_register被调用的




image.png

_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




prepare最后返回主程序入口

start函数里调用了主程序入口






最后给个总结图

dyld4应用程序加载流程图




dyld4应用程序加载流程图

dyld3应用程序加载流程图:






发布人:7dcb****    IP:117.173.23.***     举报/删稿
展会推荐
让朕来说2句
评论
收藏
点赞
转发