1 introduction
We know from the underlying principle of iOS — the association between DYLD and OBJC that when DYLD is associated with objC, the readClass function in _read_images is used to read the information of classes and associate them. This paper mainly discusses the loading of classes.
2 see first_read_images
function
Since we explore the loading of classes, and we have mainly analyzed the function of _read_images in the association between dyld and OBJC, the underlying principle of iOS, we will mainly look at the relevant part of the code of _read_images function, the above code
// Discover classes. Fix up unresolved future classes. Mark bundle classes. bool hasDyldRoots = dyld_shared_cache_some_image_overridden(); for (EACH_HEADER) { if (! mustReadClasses(hi, hasDyldRoots)) { // Image is sufficiently optimized that we need not call readClass() continue; } classref_t const *classlist = _getObjc2ClassList(hi, &count); bool headerIsBundle = hi->isBundle(); bool headerIsPreoptimized = hi->hasPreoptimizedClasses(); for (i = 0; i < count; i++) { Class cls = (Class)classlist[i]; Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized); if (newCls ! = cls && newCls) { // Class was moved but not deleted. Currently this occurs // only when the new class resolved a future class. // Non-lazily realize the class below. resolvedFutureClasses = (Class *) realloc(resolvedFutureClasses, (resolvedFutureClassCount+1) * sizeof(Class)); resolvedFutureClasses[resolvedFutureClassCount++] = newCls; } } } ts.log("IMAGE TIMES: discover classes");Copy the code
2.1 Analysis CallreadClass
Part of the code
2.1.1 No callreadClass
Previous CLS analysis
Without callingreadClass
, we read the CLS informationFrom the figure above we can see that the CLS is just a string of addresses at this point
2.1.2 callreadClass
And then CLS analysis
callreadClass
After that, we read the CLS informationFrom the figure above, we know that CLS has changed from a list of addresses to the LGPerson class. So we know that it must bereadClsss
What does the delta function doreadClsss
Function.
3 readClsss
Function analysis
3.1 the source code
Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized) { const char *mangledName = cls->mangledName(); const char *LGPersonName = "LGPerson"; if (strcmp(mangledName, LGPersonName) == 0) { auto kc_ro = (const class_ro_t *)cls->data(); Printf ("readClass: this is what I want to study %s \n",LGPersonName); } if (missingWeakSuperclass(cls)) { // No superclass (probably weak-linked). // Disavow any knowledge of this subclass. if (PrintConnecting) { _objc_inform("CLASS: IGNORING class '%s' with " "missing weak-linked superclass", cls->nameForLogging()); } addRemappedClass(cls, nil); cls->superclass = nil; return nil; } cls->fixupBackwardDeployingStableSwift(); Class replacing = nil; if (Class newCls = popFutureNamedClass(mangledName)) { // This name was previously allocated as a future class. // Copy objc_class to future class's struct. // Preserve future's rw data block. if (newCls->isAnySwift()) { _objc_fatal("Can't complete future class request for '%s' " "because the real class is too big.", cls->nameForLogging()); } class_rw_t *rw = newCls->data(); const class_ro_t *old_ro = rw->ro(); memcpy(newCls, cls, sizeof(objc_class)); rw->set_ro((class_ro_t *)newCls->data()); newCls->setData(rw); freeIfMutable((char *)old_ro->name); free((void *)old_ro); addRemappedClass(cls, newCls); replacing = cls; cls = newCls; } if (headerIsPreoptimized && ! replacing) { // class list built in shared cache // fixme strict assert doesn't work because of duplicates // ASSERT(cls == getClass(name)); ASSERT(getClassExceptSomeSwift(mangledName)); } else { addNamedClass(cls, mangledName, replacing); addClassTableEntry(cls); } // for future reference: shared cache never contains MH_BUNDLEs if (headerIsBundle) { cls->data()->flags |= RO_FROM_BUNDLE; cls->ISA()->data()->flags |= RO_FROM_BUNDLE; } return cls; }Copy the code
Source code in order to better distinguish outLGPerson
“, deliberately adding judgmentLGPerson
Type code
3.2 Code Tracing
Through code debugging, finally executedaddNamedClsss
functionIn the implementationaddNamedClsss
Function before printing CLS is still a string of addresses. When performing theaddNamedClsss
When the CLS function is printed it is found pointing toLGPerson
So we getaddNamedClsss
A pointing operation is performed on the CLS.
3.3 addNamedClsss
function
Lazy-loaded and non-lazy-loaded classes
4.1 define
Lazy loading class
: classes that defer loading until the first message is sent are calledLazy loading class
;Non-lazy-loaded classes
In:map_images
Function performs_read_images
The class loaded when the function is calledNon-lazy-loaded classes
- Commonly understood as when a class is implemented
+load
Delta function, delta function, delta functionNon-lazy-loaded classes
, is not implementedLazy loading class
4.2 Lazy loading class
Analysis of the
Not implemented for the LGPerson class+load
The delta function, we know from the previous analysis_read_images
In dealing withNon-lazy-loaded classes
Code, we hit the breakpoint and print, as shownBecause LGPerson is not implemented+load
Function, so lazily loading the class, and therefore not entering our breakpoint. However,LGPerson
When is the class loaded? We studyNon-lazy-loaded classes
The code found, implementedrealizeClassWithoutSwift
Delta function, so let’s seeLazy loading class
Is going to go into this function.
2realizeClassWithoutSwift
And from here we’ve verified thatLazy loading class
Class loading delays toThe first message is sent
4.3 Non-lazy-loaded classes
Analysis of the
We letLGPerson
implementation+load
Function, you don’t have to do anything in it, rightLook at this time_read_images
In the relevantNon-lazy-loaded classes
The processing ofAt this point we see that we have entered and executed our original breakpointrealizeClassWithoutSwift
function
4.4 Key AnalysisrealizeClassWithoutSwift
function
Key code analysis