// appsMachHeader 即mach-o文件的header字段 // argc 即 argument count 即程序运行的参数个数 // argv[] 即 argument value 是一个字符串数组 用来存放指向你的字符串参数的指针数组,每一个元素指向一个参数 // slide 偏移量 uintptr_tstart(const struct macho_header* appsMachHeader, int argc, constchar* argv[], intptr_t slide, const struct macho_header* dyldsMachHeader, uintptr_t* startGlue) { // if kernel had to slide dyld, we need to fix up load sensitive locations // we have to do this before using any global variables // 如果slide dyld, 我们必须 fixeup dyly中的内容 if ( slide != 0 ) { // 重新设定dyld rebaseDyld(dyldsMachHeader, slide); }
// allow dyld to use mach messaging // 允许dyld使用mach消息传递 mach_init();
// kernel sets up env pointer to be just past end of agv array // 内核设置的env pointers, 也就是环境参数 // envp = environment pointer // 取出argv的第argc条数据 但是实际上argv 只有argc个参数 // 因此 envp 默认是紧挨着argv存储的 constchar** envp = &argv[argc+1];
// kernel sets up apple pointer to be just past end of envp array // kernel将apple指针设置为刚好超出envp数组的末尾 constchar** apple = envp; while(*apple != NULL) { ++apple; } ++apple;
// set up random value for stack canary // 栈溢出保护 __guard_setup(apple);
#if DYLD_INITIALIZER_SUPPORT // run all C++ initializers inside dyld // 在dyld中运行所有C初始化程序 runDyldInitializers(dyldsMachHeader, slide, argc, argv, envp, apple); #endif
// now that we are done bootstrapping dyld, call dyld's main // 调用dyld的main uintptr_t appsSlide = slideOfMainExecutable(appsMachHeader); return dyld::_main(appsMachHeader, appsSlide, argc, argv, envp, apple, startGlue); }
// install gdb notifier // 注册gdb的监听者, 用于调试 stateToHandlers(dyld_image_state_dependents_mapped, sBatchHandlers)->push_back(notifyGDB); stateToHandlers(dyld_image_state_mapped, sSingleHandlers)->push_back(updateAllImages); // make initial allocations large enough that it is unlikely to need to be re-alloced sAllImages.reserve(INITIAL_IMAGE_COUNT); sImageRoots.reserve(16); sAddImageCallbacks.reserve(4); sRemoveImageCallbacks.reserve(4); sImageFilesNeedingTermination.reserve(16); sImageFilesNeedingDOFUnregistration.reserve(8);
#ifdef WAIT_FOR_SYSTEM_ORDER_HANDSHAKE // <rdar://problem/6849505> Add gating mechanism to dyld support system order file generation process WAIT_FOR_SYSTEM_ORDER_HANDSHAKE(dyld::gProcessInfo->systemOrderFlag); #endif
//2 初始化主程序 try { // add dyld itself to UUID list // 将dyld添加到UUIDlist中 addDyldImageToUUIDList();
// Now that shared cache is loaded, setup an versioned dylib overrides #if SUPPORT_VERSIONED_PATHS checkVersionedPaths(); #endif
// load any inserted libraries // 4 加载插入的动态库 // 变量 `DYLD_INSERT_LIBRARIES` 环境变量, 调用`loadInsertedDylib`方法加载所有要插入的库, // 这些库都被加入到`sAllImages`数组中 if ( sEnv.DYLD_INSERT_LIBRARIES != NULL ) { for (constchar* const* lib = sEnv.DYLD_INSERT_LIBRARIES; *lib != NULL; ++lib) loadInsertedDylib(*lib); } // record count of inserted libraries so that a flat search will look at // inserted libraries, then main, then others. // 记录插入的库的数量,以便进行统一搜索插入的库,然后是main,然后是其他 sInsertedDylibCount = sAllImages.size()-1;
// link any inserted libraries // 6 链接插入的动态库 // 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 // 对 sAllimages (除了主程序的Image外)中的库调用link进行链接, // 然后调用 registerInterposing 注册符号插入, 例如是libSystem就是此时加入的 if ( sInsertedDylibCount > 0 ) { for(unsignedint i=0; i < sInsertedDylibCount; ++i) { ImageLoader* image = sAllImages[i+1]; // link link(image, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL)); image->setNeverUnloadRecursive(); } // only INSERTED libraries can interpose // register interposing info after all inserted libraries are bound so chaining works for(unsignedint i=0; i < sInsertedDylibCount; ++i) { ImageLoader* image = sAllImages[i+1]; // 注册符号插入,Interposition, 是通过编写与函数库同名的函数来取代函数库的行为. image->registerInterposing(); } }
// <rdar://problem/19315404> dyld should support interposition even without DYLD_INSERT_LIBRARIES for (int i=sInsertedDylibCount+1; i < sAllImages.size(); ++i) { ImageLoader* image = sAllImages[i]; if ( image->inSharedCache() ) continue; image->registerInterposing(); }
// apply interposing to initial set of images for(int i=0; i < sImageRoots.size(); ++i) { sImageRoots[i]->applyInterposing(gLinkContext); } gLinkContext.linkingMainExecutable = false;
// <rdar://problem/12186933> do weak binding only after all inserted images linked // 7 执行弱符号绑定 sMainExecutable->weakBind(gLinkContext);
CRSetCrashLogMessage("dyld: launch, running initializers"); #if SUPPORT_OLD_CRT_INITIALIZATION // Old way is to run initializers via a callback from crt1.o if ( ! gRunInitializersOldWay ) initializeMainExecutable(); #else // run all initializers // 8 执行初始化方法 // 执行初始化方法, 其中`+load` 和constructor方法就是在这里执行, // `initializeMainExecutable`方法先是内部调用动态库的初始化方法, 然后调用主程序的初始化方法 initializeMainExecutable(); #endif // find entry point for main executable // 9 查找APP入口点并返回 result = (uintptr_t)sMainExecutable->getThreadPC(); if ( result != 0 ) { // main executable uses LC_MAIN, needs to return to glue in libdyld.dylib if ( (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 9) ) *startGlue = (uintptr_t)gLibSystemHelpers->startGlueToCallExit; else halt("libdyld.dylib support not present for LC_MAIN"); } else { // main executable uses LC_UNIXTHREAD, dyld needs to let "start" in program set up for main() result = (uintptr_t)sMainExecutable->getMain(); *startGlue = 0; } } catch(constchar* message) { syncAllImages(); halt(message); } catch(...) { dyld::log("dyld: launch failed\n"); }
// 将info中的uuidArray添加到dyld::gProcessInfo中 voidaddNonSharedCacheImageUUID(const dyld_uuid_info& info) { // set uuidArray to NULL to denote it is in-use // 将uuidArray设置为NULL 表示这个字段正在使用中 dyld::gProcessInfo->uuidArray = NULL;
// append all new images // 追加外部传入的info到sImageUUIDs中 sImageUUIDs.push_back(info); // 重新设置追加后uuidArrayCount dyld::gProcessInfo->uuidArrayCount = sImageUUIDs.size();
// set uuidArray back to base address of vector (other process can now read) // 更新追加后的uuidArray dyld::gProcessInfo->uuidArray = &sImageUUIDs[0]; }
voidImageLoader::weakBind(const LinkContext& context) { ImageLoader* imagesNeedingCoalescing[fgImagesRequiringCoalescing]; // 将sAllImages中所有含有弱符号的映像合并成一个列表 int count = context.getCoalescedImages(imagesNeedingCoalescing); // don't need to do any coalescing if only one image has overrides, or all have already been done // 如果进行weakbind的镜像个数>0 if ( (countOfImagesWithWeakDefinitionsNotInSharedCache > 0) && (countNotYetWeakBound > 0) ) { // make symbol iterators for each ImageLoader::CoalIterator iterators[count]; ImageLoader::CoalIterator* sortedIts[count]; for(int i=0; i < count; ++i) { // 对镜像进行排序 imagesNeedingCoalescing[i]->initializeCoalIterator(iterators[i], i); sortedIts[i] = &iterators[i]; }
int doneCount = 0; while ( doneCount != count ) { // 收集需要进行绑定的弱符号 // 该函数读取映像动态链接信息的weak_bind_off与weak_bind_size来确定弱符号的数据偏移与大小,然后挨个计算它们的地址信息 if ( sortedIts[0]->image->incrementCoalIterator(*sortedIts[0]) ) ++doneCount; // process all matching symbols just before incrementing the lowest one that matches if ( sortedIts[0]->symbolMatches && !sortedIts[0]->done ) {
// run initializers for main executable and everything it brings up // 调用主程序的初始化方法 // 单独对 main executable调用ImageLoader::runInitializers进行初始化 sMainExecutable->runInitializers(gLinkContext, initializerTimes[0]);
// register cxa_atexit() handler to run static terminators in all loaded images when this process exits if ( gLibSystemHelpers != NULL ) (*gLibSystemHelpers->cxa_atexit)(&runAllStaticTerminators, NULL, NULL);
// dump info if requested if ( sEnv.DYLD_PRINT_STATISTICS ) ImageLoaderMachO::printStatistics((unsignedint)sAllImages.size(), initializerTimes[0]); }
voidImageLoaderMachO::doModInitFunctions(const LinkContext& context) { if ( fHasInitializers ) { // mach-o文件中指令的个数 constuint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; conststructload_command* constcmds = (structload_command*)&fMachOData[sizeof(macho_header)]; conststructload_command* cmd = cmds; // 遍历所有的指令 for (uint32_t i = 0; i < cmd_count; ++i) { // 如果指令是Mach-o中的LC_SEGMENT_COMMAND if ( cmd->cmd == LC_SEGMENT_COMMAND ) { conststructmacho_segment_command* seg = (structmacho_segment_command*)cmd; conststructmacho_section* constsectionsStart = (structmacho_section*)((char*)seg + sizeof(structmacho_segment_command)); conststructmacho_section* constsectionsEnd = §ionsStart[seg->nsects]; // 从sectionsStart到sectionsEnd遍历所有的macho_section for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { constuint8_t type = sect->flags & SECTION_TYPE; // if ( type == S_MOD_INIT_FUNC_POINTERS ) { Initializer* inits = (Initializer*)(sect->addr + fSlide); constsize_t count = sect->size / sizeof(uintptr_t); for (size_t i=0; i < count; ++i) { // 获取到Initializer方法 Initializer func = inits[i]; // <rdar://problem/8543820&9228031> verify initializers are in image if ( ! this->containsAddress((void*)func) ) { dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath()); } if ( context.verboseInit ) dyld::log("dyld: calling initializer function %p in %s\n", func, this->getPath()); // 执行initializer方法 func(context.argc, context.argv, context.envp, context.apple, &context.programVars); } } } } // 根据指令的地址+指令大小获取到下一个指令 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); } } }
9、查找APP入口点并返回
这一步也是最后一步主要功能为: 查找到main函数的地址,并返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// 9 查找APP入口点并返回 result = (uintptr_t)sMainExecutable->getThreadPC(); if ( result != 0 ) { // main executable uses LC_MAIN, needs to return to glue in libdyld.dylib if ( (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 9) ) *startGlue = (uintptr_t)gLibSystemHelpers->startGlueToCallExit; else halt("libdyld.dylib support not present for LC_MAIN"); } else { // main executable uses LC_UNIXTHREAD, dyld needs to let "start" in program set up for main() result = (uintptr_t)sMainExecutable->getMain(); *startGlue = 0; }