概述最近在看《程序员的自我修养》,学到了一些关于编译、linker、dyld等知识,当浏览一些大神的关于dyld的blog时,加上一些open source上源码,有了自己的理解,记录一下。 dyld 加载的宏观过程 系统加载dyld执行顺序: 1 2 3 4 5 6 7 8 9 dyld中c++部分: // In dyld we have to do this manually.
dyld中c++部分: // In dyld we have to do this manually. start(){ // others work... return _main();//而_main()返回的是主程序main()的地址 } dyld汇编中部分: __dyld_start: 会jumps 到start()返回的地址
@H_404_90@dyld中的_main()的内容
先看看 _main()注释??:
1 2 3 4 5 6
// // Entry point for dyld. The kernel loads dyld and jumps to __dyld_start which // sets up some registers and call this function. // // Returns address of main() in target program which __dyld_start jumps to //
??_main()的主要内容:??
1 2 3 4 5 6 7 8 9
1,// instantiate ImageLoader for main executable // load shared cache // Now that shared cache is loaded,setup an versioned dylib overrIDes 2,// load any inserted librarIEs 3,// link main executable 4,// link any inserted librarIEs -- do this after linking main executable so that any dylibs pulled in by inserted // dylibs (e.g. libSystem) will not be in front of dylibs the program uses 5,// run all initializers 6,// find entry point for main executable 7,// Returns address of main() in target program
ImageLoader简介
1 2 3 4 5 6 7 8 9 10 11 12
// // ImageLoader is an abstract base class. To support loading a particular executable // file format,you make a concrete subclass of ImageLoader. // // 每个.o文件都会生成一个ImageLoader子类实例 // For each executable file (dynamic shared object) in use,an ImageLoader is instantiated. // // The ImageLoader base class does the work of linking together images,but it kNows nothing // about any particular file format. // // class ImageLoader {...}
// The kernel maps in main executable before dyld gets control. // We need to make an ImageLoader* for the already mapped in main executable. static ImageLoader* instantiateFromloadedImage(...){ if ( isCompatibleMachO((const uint8_t*)mh,path) ) { //检查.o是否合法 //instantiateMainExecutable():得到主程序的image。省略不贴code了(影响美观,??) ImageLoader* image = ImageLoaderMachO::instantiateMainExecutable(mh,slIDe,path,glinkContext); addImage(image); return image; } }
addImage()
把image添加到images容器中,并更新内存分布
1 2 3 4 5 6 7 8
staticvoID addImage(ImageLoader* image){ //add to master List // update mapped ranges // other work… if ( sEnv.DYLD_PRINT_liBRARIES || ...) { dyld::log("dyld: loaded: %sn",image->getPath()); } }
// run all initializers 即调用 initializeMainExecutable();
注意下面的 两个run initialzers…
1 2 3 4 5 6 7 8
voID initializeMainExecutable(){ // run initialzers for any inserted dylibs // run initializers for main executable and everything it brings up // register cxa_atexit() handler to run static terminators in all loaded images when this process exits // dump info if requested if( sEnv.DYLD_PRINT_STATISTICS ){ ImageLoaderMachO::printStatistics((unsignedint)sAllimages.size(),initializerTimes[0]); }
Q: 在自己 Class 的 +load 方法时能不能替换系统 framework(比如 UIKit)中的某个类的方法实现 A: 可以,因为动态链接过程中,所有依赖库的类是先于自己的类加载的。
staticvoID libSystem_initializer(...){ // others init... libdispatch_init(); } voID libdispatch_init(voID){ // others init... _os_object_init(); } voID _os_object_init(voID){ _objc_init(); // others init work... } /*********************************************************************** * _objc_init * bootstrap initialization. Registers our image notifIEr with dyld. * old ABI: called by dyld as a library initializer * New ABI: called by libSystem BEFORE library initialization time **********************************************************************/ voID _objc_init(voID){ // other init work… // old objc-runtime.mm(??的主要用这种来介绍) dyld_register_image_state_change_handler(dyld_image_state_bound,1/*batch*/,&map_2_images); dyld_register_image_state_change_handler(dyld_image_state_dependents_initialized,0/*not batch*/,&load_images); // 在新的 objc-runtime.mm中是这样的,反正都差不多就不计较用法了。 // _dyld_objc_notify_register(&map_images,load_images,unmap_image); } // 关于 dyld_register_image_state_change_handler的介绍,其中第三个参数是callback!! // Register a handler to be called when any image changes to the requested state. externvoID dyld_register_image_state_change_handler(enum dyld_image_states state,bool batch,dyld_image_state_change_handler handler);
调用过程:map_2_images() -> map_images_nolock() -> _read_images() map_images_nolock注释: * Process the given images which are being mapped in by dyld. * All class registration and fixups are performed (or deferred pending discovery of missing superclasses etc),and +load methods are called. voID _read_images(header_info **hList,uint32_t hCount){ // 比较重要的部分: // Read classes from all images. // Read categorIEs from all images // Connect classes from all images.【 Connect the classes in the given image to their superclasses,or register them for later connection if any superclasses are missing.】 // Fix up class refs,selector refs,and protocol objects from all images. }
constchar*load_images(enum dyld_image_states state,uint32_t infoCount,const structdyld_image_info infoList[]){ // other work ... // Call +load methods (without runtimeLock - re-entrant) call_load_methods(); } /*********************************************************************** * call_load_methods * Call all pending class and category +load methods. * Class +load methods are called superclass-first. * category +load methods are not called until after the parent class's +load. ………… **********************************************************************/ voID call_load_methods(voID){ // other work... do{ // 1. Repeatedly call class +loads until there aren't any more while (loadable_classes_used > 0) { call_class_loads(); } // 2. Call category +loads ONCE more_categorIEs = call_category_loads(); // 3. Run more +loads if there are classes OR more untrIEd categorIEs }while (loadable_classes_used > 0 || more_categorIEs); }
(1) map_2_images:All class registration and fixups are performed (2) 至此,可执行文件中和动态库所有的符号(Class,Protocol,Selector,IMP,…)都已经按格式成功加载到内存中,在这之后,runtime 的那些方法(动态添加 Class、swizzle 等等)才能生效 (3) load_images:Call all pending class and category +load methods. 可以在 +load()中 进行swizzle *** 作…
走一遍流程
load main exe -> shared cache -> load inserted dylibs -> link main exe -> link dylibs -> init ( 先dylibs 后 main exe ) -> 返回main exe的入口地址。 其中的init dylibs -> objc register callback when image load-> execute callback-> call_load_methods()
评论列表(0条)