前语: iOS底层原理根究是本人在往常的开发和学习中不断堆集的一段进阶之
路的。 记载我的不断根究之旅,期望能有帮忙到各位读者朋友。

目录如下:

  1. iOS 底层原理根究 之 alloc
  2. iOS 底层原理根究 之 结构体内存对齐
  3. iOS 底层原理根究 之 目标的本质 & isa的底层结束
  4. iOS 底层原理根究 之 isa – 类的底apple官网层原理结构(上)
  5. iOS 底层原理根究 之 isa – 类的底层原理结构(中)
  6. iOS 底层原ios14.4.1更新了什么理根究 之 isa – 类的底层原理结构(下)
  7. iOS 底层原理根究 之 Runtime运行时&amp源码本钱;办法的本质
  8. iOS 底层原理探数组去重求 之 objc_msgSend
  9. iOS 底层原理根究 之 Runtime运行时慢速查找流程apple tv
  10. iOS 底层原理根究 之 动态办法选择
  11. iOS 底层原理根究 之 音讯转发流程
  12. iOS 底层原理根究 之 应用程序加载原理dylapp下载d (上)

前语

接着上一篇的内容咱们从 _dyld_objc_notify_register(&map_imappetiteages, load_images, unmap_image)开始:

_dyld_objc_notify_register(&map_images, load_appreciateimages, un源码网站mapios14.7晋级新提示_image)

  1. 这个办法中的 map_images是在什么时分调用的呢?
  2. load_images办法实施的时分其内部的一个流程是什么样的?
  3. 毕竟,咱们现在地点的 dyld 阶段是怎样进入到 main 函数主程序的呢?

带着这些疑问ios是什么意思开始咱们今日的内容。

接受上节课的内容 在 doModInitFunctions 之后 咱们加载 libSystemapproach.B.dylib libSystem_initializer源码本钱libsidpatch.dylib libdispatch_initlibsidpatch.dylib _os_object_init 接着实施到 _objc源码编辑器_init。 在 _objc_init 中,咱们调用 了 _dyld_objc_notify_register

_dyld_obios是什么意思jc_notify_register

void _dyld_objc_notify_register(_dyld_objc_notify_mapped    mapped,
_dyld_objc_n源码是什么意思otify_init      init,
_dyld_objc_notify_unmapped  unmapped)
{
dapple payyld::registerObjCNotifiers(mapped, init, unmapped);
}

registerObjCNotifiers

// _dyld_objc_notify_i源码之家nit
void registerObjCNotifiers(_dyld_objc_notify_mapped mapped, _dyld_源码网站objc_notify_init init, _dyld_objc_notify_unmapped unmapped)
{
// 记载要调用的approach函数,结束赋值
sNotifyObjCMapped	= m数组apped;
sNotifyObjCInit		= init;
sNotifyObjCUnmapped = unmapped;
// 调用“映射”函数与悉数APP镜像映射到目前为止
try {
notifyBatchPartial(dyld_image_state_bound, tr数组词ue, NULL, false, true);
}
...
}

notifyBatchPartial

此函数中 经过 (*sNotifyObjCMapped)(objcImageCount, paths, mhs); 结束了对 map_images 的调用。

static voidApple notifyBapple id暗码重置atchPartial(dyld_image_states state, bool orLater, dyld_image_stat数组初始化e_change_handler onlyHandler, bool preflightOnly, bool onlyObjCMappedNotification)
{
...
// 告诉objc关于数组新的镜像
if ( (onlyHandler == NULL) &&源码交易网站源码 ((state == dyld_iapple tvmage_state_bound) || (orLater &&amappetitep; (dylAPPd_image_state_bound > state))) &aapple paymp;& (sNotifyObjCMapped != NULL) ) {
const chappearar* paths[imageCount];
const mach_header* mhs[imageCount];
unsigned objcImageCount = 0;源码本钱
for (int i=0; i < imageCount; ++i) { ... }
if ( o源码本钱bjcImageCount != 0 ) {
dyld3::ScopedTimer timer(DBG_DYAPPLD_TIMING_OBJC_MAP, 0, 0, 0);
uint64_t t0 = mach_absappstoreolute_time();
(*sNotifyObjCMapped)(objcImageCount, paths, mhs);
uint64_t t1 = mach_absolute_time();			ImageLoader::fgTotalObjCSetupTime += (t1-t0);
}
}
}
allImagesUnlock();
if ( dontLoadReason != NULL )
throw dontLoadReas数组排序on;
if ( !preflightOnly && (state == dyld_image_state_dependents_mappeappstored) ) {
const struct mach_header* loadAddresses[imageCount];
const char源码怎样做成app软件* loadPaths[imageCount];
for(数组词uint32_t i = 0; i<imag源码年代eCount; ++i) {
loadAddresses[i] = infos[i].imageLoadAddress;
loadPaths[i] = infos[i].imageFilePath;
}
n源码编辑器otifyMonito数组去重ringDyld(false, imageCountios下载, loadAddresses, loadPaths);
}
}
}

也便是 _appetitedyld_objc_notify_registeapple官网r办法进来之后,体系记载下要调用的函数后 就 try map_images 结束调用, 下面看下 load_images

在上一篇的 recursiveInitialization 环节,

ImageLoaappetiteder::recursiveInitialization

void ImageLoader源码之家::recursiveInitialization(const LinkContext& context, maios14.7正式版ch_porios是什么意思t_t this_thread, consapproacht char* pathToInitialize,
InitializerTimin源码网站gList& timingInfo, UninitedUpwards& uninitUps)
{
recursive_lock lock_i数组c语言nfoappetite(this_thread);
recursiveSpinLock(lock_info);
if ( fState < dyld_image_state_dependents_initialized-1 ) {
uint8_t oldState = fState;
// bapple官网reak cycles
fState = dyld_image_state_dependents_initialized-1;
try {
// initiali数组ze lower levelapple watch libraries firstapp下载
for(unsigned int i=0; i < li数组指针braryCount(); +源码是什么意思+i) {... }
// 记载中止订单
if ( this->needsTermination() )				coios是什么意思ntext.terminationapp下载Recorder(this);
// 让o源码是什么意思bjc知道咱们将要初始化这个镜像
uint64_t t1 = mach_absolute_time();
fapproachState = dyld_image_state数组长度_dependents_数组指针initialized;
oldState = fState;
context.notifySingle(dyld_image_state_dependents_initialized, this, &amp数组长度;tim数组初始化ingInfo);
// 初始化镜apple id像
// 初始化悉数images load_images 赋值
// maApplep load - map()源码编辑器 --> cxx = objc
// notifySingle : load()
// cxx = SMobjcBuild
bool hasInitializers = this->doInitiiOSalizatio源码本钱n(context);
//  让任何人知道咱们现已初始化了这个镜像
fState = dyld_image_state_ini源码年代坑人tialized;
oldState = fState;
//objc - SMObjc
context.ApplenotifySingle(dyld_imageapple id_state_initialized, this, NULL);
i数组c语言f ( hasInitializers ) { ... }
}
caapple watchtch (const char* msg) {
// this image is not initialized
fState = oldStateapple watch;
recursiveSpinUnLock();
throw;
}
}
recursiveSpinUnLock();
}

就会分源码网站析进入到 notifySingle:

notappearifySappreciateingle

static void notifySingle(dyld_image_states state, const ImageLoader* image, ImageLoader::InitialiapplezerTimingList* timingInfo)
{
//dyld::log("noios模拟器tifySingle(state=%d, image=%s)n", state, image->getPath());
std数组排序::vector<dyld_imaAPPge_state_change_handler&Applegt;* handlers = stateToHandlers(state, sSin源码是什么意思gleHandlers);
if ( handle数组公式rs != NULL ) { ... }
if ( stateapp id注册 == dyld_image_sta源码年代坑人te_mapped ) { ... }
if ( (state == dyld数组长度_image_state_dependents_initializapp id注册ed) && (sNapple storeotifyObjCInit != NULL) && image->notifyObjC() ) {
uint64_t t0 = mach_absolute_time(ios14.7正式版);
dyld3::ScopedTimer timer(DBG_DYLD_TIMING_OBJC_INIT, (uint64_t)imageios14.4.1更新了什么->machHeader(), 0, 0);
(*sNotifyObjCInit)(image->getRealPat数组和链表的差异h(), image->machHeader());
uint64_t t1 = mach_absolute_time();
uint64_t t2 = mach_absolutapple watche_time()app是什么意思;
uintiOS64_t timeInOb源码本钱jC = t1-t0;
uint64_t emptyTime = (t2-t1)*100;
if ( (timeInObjC > emptyTime) && (timingInfo != NULL)) { ... }
}
}

也便是在 notifySingle 中调用了load_images

接下来咱们看看,应用程序加载过程中,是怎样从 dyld 进入到 main数组长度() 的。

dyld_start 汇编源码

经过分析 dyld_app下载start 源码,发现在dyld的毕竟,会调起体系的 main()函数。

#if __arm64__ && !TA源码之家RGET_OS_SIMULATOR
.text
.align 2
.globl __dyld_start
__dyld_star源码年代坑人t:
mov 	x28, sp
and     sp, x28, #~15		// force 16-byte alignment of stack
mov	x0, #0
mov	x1appetite, #0
stp	x1, x0, [sp, #-16]!	// make aligned terminating frame
mov	fp, sios14.7晋级新提示p			// set up fp to point to terminating frame
sub	sappreciatep, sp, #16             /ios体系/ make room for local variables
#if __LP64__
ldr     x0, [x28]               // get app's mh into x0
ldr     x1, [x28, #8]           // get argc into x1ios15 (kernel passes 32-bit int argc as 64-bits on stack to keep alignment)
add     x2,appear x28, #16            // get argv into x2
#else
ldr     w0, [x28]               // get app's mh into x0
ldr     w1, [x28, #4]           // get argc into x1 (kernel passes 32-bit i源码怎样做成app软件nt argc as 64-bits on stackios14.4.1更新了什么 to keep alignment)
add     w2, w28, #8             // get argv into x2
#endif
adrp	x3,___dso_handle@page
add 	x3数组公式,x3,___dso_handle@pageoff // get dyld's mh in to x4
mov	x4,sp                   // x5 has &startGlue
// 调用 dyldbootstrap::stios是什么意思art(app_mh, argc, argv, dyld_mh, &stapple id暗码重置artGlue)
bl	__ZN13dyldbootstrap5startEPKN5dyld311MachOLo源码之家adedEiPPKcS3_Pm
mov	x16,数组长度x0                  // save entry point address in x16
#if __LP64__
ldr     x1数组指针, [sp]
#else
ld源码本钱r     w1, [sp]
#endif
cmp	x1, #0
b.neapplication	Lnew
// LC_UN源码编辑器IXTHREAD way, 收拾堆栈然ios14.7晋级新提示后跳转到效果
#if __LP64__
add	sp, x数组指针28, #8             // restore unaligned stack pointer without app mh
#else
add	sp, x28, #4             // restore unaligned stack pointer witho数组长度ut app mh
#endif
#if __arm64e__
braaz   x16                     // jump to the program's entry point
#else
b源码怎样做成app软件r      x1iOS6                     // jump to the program's entry poi源码之家nt
#endif
// LC_MAIN case, 设置调用main()的堆栈
Lnew:	mov	lr, x1		    // simulate return addreios下载ss into _start in libdyld.dylib
#if __LP64__
ldr	x0, [x28, #8]       // main param1 = argc
add	x1, x28, #源码交易网站源码16        // main param2 = argios是什么意思v
add	x2, xios151, x0, lsl #3
addappear	x2, x2, #8          // main pios8备忘录aram3 = &env[0]
mov	x3, x2
Lapple:	ldr	x4, [x3]
add	x3, x3, #8
#else数组排序
ldr	w0, [x28, #4]       // main param1 = argc
add	x1,apple id暗码重置 x数组去重28, #8         // m数组词ain p数组和链表的差异aram2 = argv
add	x2, x1, x0, lsl #2
add	x2, x2, #4          // main param3 = &env[0]
mov	x3, x2
Lapple:	ldr	w4, [x3]
add	x3, x3, #4
#endif
cmp	x4, #0
b.ios15ne	Lapple		    // main paraAPPm4 = apple
#if __arm64e__
braaz   x16数组
#else
br      x16
#ios下载endif
#endif // __arm64__ &amp源码网站;& !TARGET_OS_SIMULATOR

接下来真机验证:

验证

咱们知道 咱们准备的项目 先是 [viewcontroller load] 调用 然后是 cxx 办法 ,毕竟进入到 main()函数,那么,在项目中,咱们在cxx办法处打一个断点,开始数组词调试看看:

iOS 底层原理探究 之 应用程序加载原理dyld (下)

断点进来之后,debug显现汇编代码,然后逐步实施,apple pay看到在数组词 dyld_start 流程的毕竟,会自动的去调起 main 函数

iOS 底层原理探究 之 应用程序加载原理dyld (下)

到这儿,我ios是什么意思们就解说了上篇文章抛出的三个问题。
所以,补偿一下昨日的 dyld流程图:

dyld流程图

iOS 底层原理探究 之 应用程序加载原理dyld (下)

appetiteapple

首先要根究的流程便是 map_images

map_images

/***********************************************************************
* map_images
* 处理dios8备忘录yld映射ios体系到的给定镜像
* 在运用特定于abi的锁后调用与abi无关的代码
*
*  承认:写锁runtimeLock
**********************************************************************/
void
map_images(unsigned count, const char * const paths[],
const struct mapp id注册ach_header * constapp是什么意思 mhdrs[])
{
mutex_locker_t lock(apple tvruntimeLocapple官网k);
return map_images_nolock(cappetiteount, paths, mhdrs);
}

之后就从 map_images 来到了 mapp id注册ap_images_nolock

mappearap_imagesapple tv_nolocapplek

/**************************************************ios是什么意思*源码********************
* map_images_nolock
* 处理dyld映射数组指针到的给定镜像
* 悉数的类注册和批改都被实施(或推迟等候)
* 发现丢掉的超类等,并调用+load办法
*
* Info[]是自下而上的次第,即libobjc将在早些时分
* 数组比任何链接到libapple tvobjc的库
*
* 承认:loadMethodLoc源码是什么意思k(旧的)或源码年代坑人runtimeLock(新的)由map_images获取
**********************************************************************/
#if __OBJC2__
#include "oapp是什么意思bjc-file.h"
#else
#include "objc-file-old.h"
#endif
void
map_images_nolock(unsigned mhCount,appear const chaios是什么意思r * const mhPaths[],
const struct源码年代坑人 mach_header * consapp storet mhdrs[])
{
static bool firstTime = YES;
header_iios14.7晋级新提示nfo *hList[mhCount];
uint32_t hCou数组初始化nt;
size_t selrefCount = 0;
// 假设需求,实施首次初始化
// 该函数在一般库初始化器之前调用
//app是什么意思 批改推迟初始源码年代培训怎样样化直到找到一个运用objc的镜像?
ifios14.7正式版 (firstTime) { ... }
if (PrintImagesapple) { ... }
// 找到悉数带有Objective-C元数据的镜像
hCount = 0;数组和链表的差异
// Count classes. Size various table based on the total.
int totalCla数组公式sses = 0;
int unoptimizedTo数组公式talClasses = 0;
{
uint32_t i = mhCount;
while (i--) { ... }
}
//  实施必须推迟到的一次性运行时初始化
//  可实施文件自身被找到。这需求提早结束
//  进一步的初始化
//  可实施文件或许不在这个infoList中,假设
//  可实施程序不包括Objective-C代码,而是Objective-C
/ios是什么意思/  稍后动态加载app id注册
if (firstTime) { ... }
if (hCount > 0) {
_数组排序read_images(hList, hCount, totalClasses, unoptimizios14.4.1更新了什么edTotalClasses);
}
firstTime = NO;
// 在悉数设置结束后调用镜像加载函数
for (auto func : loadImageFuncsiOS) {
forapproach (uint32_t i = 0; i < mhCount; i++) {
funcapplication(mhdrs[i]);
}
}

找到悉数带有Objective-C元数据的镜像后,之后就开始对镜像内容进行初始处理。

总结

用户将咱们开发的app设备到手机后,一向存储在手机的磁盘中,一旦用户点击了咱们的app,那么,体系就会进入到dyld流程中,源码年代坑人为咱们的app中所运用的各种动静态库做链接,加载各种镜像文源码编辑器件,接着便是加载咱们appointment项目中的各种类源码编辑器文件,毕竟,进入到 main()函数,之后是 AppDelegateSecen 来处理咱们为用户开发的各种功用。

本篇内容算是,上述流程中 dyld 流程根究的一个总结, 下一篇,咱们开始类的加载流程根究。 我们,加油!!!