iOS底层探索 之 应用程序加载原理

665 阅读3分钟

应用程序加载原理 库:可执行的二进制文件,加载到内存 文件类型: 静态库 .a 动态库 .so .dll 两者是链接的区别

编译过程

我们可以直接打开工程目录Products下的.app文件找到可执行文件拖到终端可以直接运行

加载过程

库- 映射到内存 images

//输出
+[ViewController load]
(lldb) image list
[  0] 404C4B96-E4D1-3501-BBDA-B6895DA2626A 0x000000010080c000
[  1] 1AC76561-4F9A-34B1-BA7C-4516CACEAED7 0x0000000101122000 /usr/lib/dyld 
[  2] 2A92FC99-72A9-38ED-8DDD-AF4C25080124 0x0000000100820000 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/dyld_sim 
[  3] C2A18288-4AA2-3189-A1C6-5963E370DE4C 0x00007fff2071f000 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/Foundation.framework/Foundation 

接下来看dyld 动态链接器

ViewController.m

bt

dyldbootstrap jump 查找start

//重点看返回
return dyld::_main((macho_header*)appsMachHeader, appsSlide, argc, argv, envp, apple, startGlue);

_main jump

getHostInfo jump

//instantiateFromLoadedImage   镜像文件加载器
CRSetCrashLogMessage(sLoadingCrashMessage);
		// instantiate ImageLoader for main executable
		sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, mainExecutableSlide, sExecPath);
		gLinkContext.mainExecutable = sMainExecutable;
		gLinkContext.mainExecutableCodeSigned = hasCodeSignatureLoadCommand(mainExecutableMH);

instantiateFromLoadedImage jump

addImage jump

instantiateMainExecutable jump

allImagesCount 拿到所有镜像文件个数

再执行runInitializers runInitializers jump

//重点代码
processInitializers(context, thisThread, timingInfo, up);
context.notifyBatch(dyld_image_state_initialized, false);

processInitializers jump

recursiveInitialization jump

//重点代码	
context.notifySingle(dyld_image_state_dependents_initialized, this, &timingInfo);			
// initialize this image		
bool hasInitializers = this->doInitialization(context);

notifySingle jump

void (*notifySingle)(dyld_image_states, const ImageLoader* image, InitializerTimingList*);

单一注册通知

notifyMonitoringDyld sNotifyObjCInit

registerObjCNotifiers jump sNotifyObjCInit = init;

单个镜像文件加载->_dyld_objc_notify_register

registerObjCNotifiers

_os_object_init jump

libdispatch_init jump

发现了_os_object_init();

libSystem_initializer jump

//重点代码 调用libdispatch_init
libdispatch_init();
_libSystem_ktrace_init_func(LIBDISPATCH);

doModInitFunctions jump

//重点代码 libSystemInitialized
if ( ! dyld::gProcessInfo->libSystemInitialized ) {
// <rdar://problem/17973316> libSystem initializer must run first
	const char* installPath = getInstallPath();
	if ( (installPath == NULL) || (strcmp(installPath, libSystemPath(context)) != 0) )							
            dyld::throwf("initializer in image (%s) that does not link with libSystem.dylib\n", this->getPath());
	}
							
func(context.argc, context.argv, context.envp, context.apple, &context.programVars);

ImageLoaderMachO 里调用了 doModInitFunctions 初始化镜像文件 调用doModInitFunctions

流程梳理

_os_object_init (libdispatch) -> _objc_init (libobjc)

_objc_init jump

_dyld_objc_notify_register jump

registerObjCNotifiers jump

//赋值代码
// record functions to call
sNotifyObjCMapped	= mapped;
sNotifyObjCInit		= init;
sNotifyObjCUnmapped   = unmapped;

调用 doModInitFunctions

doInitialization 调用

// initialize this image		
bool hasInitializers = this->doInitialization(context);

sNotifyObjCMapped 调用

static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image_state_change_handler onlyHandler, bool preflightOnly, bool onlyObjCMappedNotification) 方法里调用sNotifyObjCMapped
if ( objcImageCount != 0 ) {					
  dyld3::ScopedTimer timer(DBG_DYLD_TIMING_OBJC_MAP, 0, 0, 0);					
  uint64_t t0 = mach_absolute_time();				
  (*sNotifyObjCMapped)(objcImageCount, paths, mhs);				
  uint64_t t1 = mach_absolute_time();				
  ImageLoader::fgTotalObjCSetupTime += (t1-t0);			
}

notifyBatchPartial jump

registerObjCNotifiers 注册 调用 notifyBatchPartial

sNotifyObjCInit notifySingle 调用 sNotifyObjCInit

ImageLoader 递归循环流程 调用 notifySingle

//重点代码 先进行赋值再进行初始化	
context.notifySingle(dyld_image_state_dependents_initialized, this, &timingInfo);

// initialize this image - 初始化所有images- load_images 赋值	 
bool hasInitializers = this->doInitialization(context);
		
// let anyone know we finished initializing this image			
fState = dyld_image_state_initialized;		
oldState = fState;		
context.notifySingle(dyld_image_state_initialized, this, NULL);

run 起来 bt 首先调用的是 +[ViewController load] ,再调用doModInitFunctions,表面上看跟上面写的代码是恰好相反的

所有镜像文件内部初始化 -> load方法 -> hl_objc

load_images jump

prepare_load_methods jump

realizeClassWithoutSwift 实现分类

schedule_class_load jump

schedule_class_load(cls->getSuperclass());

add_class_to_loadable_list jump

添加到loadable_classes,就是相当 数组,里面装模型,数组的相应下标得到字典,字典相应下标得到值。loadable_classes收集所有的load方法(包括class方法、分类方法)

loadable_classes[loadable_classes_used].cls = cls;
 loadable_classes[loadable_classes_used].method = method;
 loadable_classes_used++;

> getLoadMethod jump

 if (0 == strcmp(name, "load")) {           
   return meth.imp(false);    
  }

add_category_to_loadable_list jump

_category_getLoadMethod jump

mlist = ISA()->data()->ro()->baseMethods() //递归所有的baseMethods
return meth.imp(false); //返回过去

call_load_methods jump

call_class_loads jump 在call_load_methods被调用 (*load_method)(cls, @selector(load));

call_category_loads jump 在call_load_methods被调用 (*load_method)(cls, @selector(load));

未完待续......