Dyld的原理

dynamic load: 动态加载.它主要是用的实现库之间的动态链接,库不用被直接编译到可以执行文件中,而是在执行的时候才会去link,达到动态加载的效果.共享动态库就是利用这个原理进行的。

  • 如下通过otool -L 可执行文件可以看到它包含了如下信息,其中@rpath/xxx/usr/lib/就标示它的动态链接路径. shell xxx@xxx wwdcc % otool -L App
    App:
    @rpath/App.framework/App (compatibility version 0.0.0, current version 0.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.0.0)
    ## dyld环境变量速查
  • 通过man dyld可以查看他的帮助命令
    |Command|Description|
    |---|---|
    |DYLD_FRAMEWORK_PATH|动态库加载路径的集合,系统会按照这几个文件夹路径搜索动态库,XXX.framework/Versions/A/XXX or XXX.framework/XXX,根据所安装的库名字去查找|
    |DYLD_FALLBACK_FRAMEWORK_PATH|从默认的文件路径查找 /Library/Frameworks:/System/Library/Frameworks|
    |DYLD_VERSIONED_FRAMEWORK_PATH|优先使用新版本的framework|
    |DYLD_LIBRARY_PATH|搜索dylib库的文件路径集合|
    |DYLD_FALLBACK_LIBRARY_PATH|默认dylib库,如/usr/local/lib:/usr/lib.|
    |DYLD_VERSIONED_LIBRARY_PATH|优先使用新版本的dylib|
    |DYLD_PRINT_TO_FILE|日志输出的文件路径,通常用来记录错误|
    |DYLD_SHARED_REGION|avoid不使用共享缓存,private,删除共享区域的地址空间和mmap,拷贝到私有范围的dyld共享缓存区域|
    |DYLD_INSERT_LIBRARIES|在程序加载前动态的插入新的库|
    |DYLD_FORCE_FLAT_NAMESPACE|防止其他的共享库名字冲突覆盖,强制指定当前这个库|
    |DYLD_IMAGE_SUFFIX|为动态库设置统一后缀|
    |DYLD_PRINT_OPTS|设置打印的文件描述符为2,标准错误输出|
    |DYLD_PRINT_ENV|环境变量输出|
    |DYLD_PRINT_LIBRARIES|打印加载的库|
    |DYLD_BIND_AT_LAUNCH|在启动时绑定所有应用程序需要的符号,一般建议还是使用默认的懒加载|
    |DYLD_PRINT_STATISTICS|打印动态库的主要方法的时间,分析启动时间非常有用|
    |DYLD_DISABLE_DOFSDYLD_DISABLE_DOFS|不像kernel注册静态检测|
    |DYLD_PRINT_INITIALIZERS|打印构造初始化函数, C++ statically allocated objects, 标记为 attribute((constructor))的函数, and -init functions.|
    |DYLD_PRINT_APIS|打印 dyld api的调用|
    |DYLD_PRINT_SEGMENTS|打印dyld 加载时所map的mach-o segment|
    |DYLD_PRINT_BINDINGS|打印binding的符号信息|
    |DYLD_PRINT_DOFS|使dyld打印出关于已向内核注册的dtrace静态探测的信息。|
    |DYLD_PRINT_RPATHS|打印@rpath路径|
    |DYLD_SHARED_CACHE_DIR|打印共享文件路径,通常与DYLD_SHARED_REGION=private and DYLD_SHARED_CACHE_DONT_VALIDATE 结合使用|
    |DYLD_SHARED_CACHE_DONT_VALIDATE|不关系在不在,直接去加载它|
    | DYNAMIC LIBRARY LOADING|设置动态库加载路径,drawin使用完整路径加载,通过
    @executable_path/,@loader_path/,@rpath/来指定它的库文件加载前缀|

  • 关于DYNAMIC LIBRARY LOADINGXcode中会经常遇到

    • @executable_path: 这个变量表示可执行程序所在的目录,总是被解析为同一个路径(可执行程序所在目录)
    • @loader_path: 这个变量表示每一个被加载的 binary (包括可执行程序, dylib, framework 等) 所在的目录. 它INSTALL_PATH 可以设置为 @loader_path/../dylib, 这样设置的话, 不论这个库放到什么位置它都能正确加载
    • @rpath: 它只是一个保存着一个或多个路径的变量,增加查找的路径

App启动时间统计

  • 就App而言主要分为三种加载形式
    • 冷启动(Coding launch): App在第一次安装启动
    • 热启动(Warming launch): App关闭后立即启动(有共享缓存,暂时没销毁)
    • 正常启动: App相关的部分共享缓存释放
  • 在Xcode中通过设置环境变量DYLD_PRINT_STATISTICS_DETAILS=1可以看到dylib在linker的过程中所有关键阶段的时间d text total time: 4.0 seconds (100.0%)
    total images loaded: 691 (636 from dyld shared cache)
    total segments mapped: 178, into 23263 pages
    total images loading time: 3.0 seconds (74.5%)
    total load time in ObjC: 39.29 milliseconds (0.9%)
    total debugger pause time: 1.5 seconds (37.7%)
    total dtrace DOF registration time: 0.00 milliseconds (0.0%)
    total rebase fixups: 502,572
    total rebase fixups time: 70.65 milliseconds (1.7%)
    total binding fixups: 45,451
    total binding fixups time: 56.66 milliseconds (1.3%)
    total weak binding fixups time: 33.12 milliseconds (0.8%)
    total redo shared cached bindings time: 30.67 milliseconds (0.7%)
    total bindings lazily fixed up: 0 of 0
    total time in initializers and ObjC +load: 835.45 milliseconds (20.5%)
    libSystem.B.dylib : 9.45 milliseconds (0.2%)
    libBacktraceRecording.dylib : 6.27 milliseconds (0.1%)
    libMainThreadChecker.dylib : 39.86 milliseconds (0.9%)
    libglInterpose.dylib : 508.29 milliseconds (12.5%)
    libMTLCapture.dylib : 20.72 milliseconds (0.5%)
    RxSwift : 6.73 milliseconds (0.1%)
    RxCocoa : 8.46 milliseconds (0.2%)
    Flutter : 5.00 milliseconds (0.1%)
    Realm : 11.78 milliseconds (0.2%)
    SwiftProtobuf : 4.72 milliseconds (0.1%)
    xx_plugin : 9.50 milliseconds (0.2%)
    xxx3d : 12.38 milliseconds (0.3%)
    xxxApp : 313.05 milliseconds (7.6%)
    total symbol trie searches: 269548
    total symbol table binary searches: 0
    total images defining weak symbols: 71
    total images using weak symbols: 162

dyld主要功能

  • docs->dyld.codes包括了dyld的主要功能大纲 codes 0x1f070000 dyld.static_intializer
    0x1f070004 dyld.launch_executable
    0x1f070008 dyld.map_file
    0x1f07000c dyld.apply_fixups
    0x1f070010 dyld.attach_codesignature
    0x1f070014 dyld.build_closure
    0x1f070018 dyld.add_image_callback
    0x1f07001c dyld.remove_image_callback
    0x1f070020 dyld.objc_image_init
    0x1f070024 dyld.objc_images_map
    0x1f070028 dyld.apply_interposing
    0x1f07002c dyld.gdb_image_notifier
    0x1f070030 dyld.remote_image_notifier
    0x1f080000 dyld.dlopen
    0x1f080004 dyld.dlopen_preflight
    0x1f080008 dyld.dlclose
    0x1f08000c dyld.dlsym
    0x1f080010 dyld.dladdr
    0x1f090000 dyld.DEBUG.vm_remap
    0x1f090004 dyld.DEBUG.vm_dealloc
    0x1f090008 dyld.DEBUG.map_loop
    0x1f09000c dyld.DEBUG.marker
    ## dyld执行过程,以arm64为例
  • kernel内核做好相关的初始化工作之后,从汇编文件dyldStartup.s -> __dyld_start `` #if arm64 ...
    __dyld_start: ...
    // call dyldbootstrap::start(app_mh, argc, argv, dyld_mh, &startGlue)
    // LC_MAIN case, set up stack for call to main() ...
    b.ne Lapple // main param4 = apple
    ...

endif // arm64

2. dyldInitialization.cpp -> dyldbootstrap::start 
    -> rebaseDyld, 修改二进制位置,安全策略考虑 
       -> runDyldInitializers //初始化C++的函数,
            extern const Initializer  inits_start  __asm("section$start$__DATA$__mod_init_func");
extern const Initializer  inits_end    __asm("section$end$__DATA$__mod_init_func");
         -> dyld::_main
1. dyld2.cpp
    -> _main
## TODO:
posted @ 2020-10-16 01:55  阿甘左  阅读(771)  评论(0编辑  收藏  举报