我們?cè)谥暗奶骄窟^程中發(fā)現(xiàn)dyld加載中會(huì)調(diào)用到_objc_init,這篇文章我們從_objc_init開始研究其具體做了什么。
_objc_init源碼
void _objc_init(void)
{
static bool initialized = false;
if (initialized) return;
initialized = true;
// fixme defer initialization until an objc-using image is found?
environ_init();//環(huán)境變量
tls_init();//線程綁定key
static_init();//c++靜態(tài)構(gòu)造函數(shù)運(yùn)行
runtime_init();//運(yùn)行時(shí)初始化
exception_init();//libobjc異常處理
cache_init();//緩存初始化
_imp_implementationWithBlock_init();
// map_images() load_images()
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
#if __OBJC2__
didCallDyldNotifyRegister = true;
#endif
}
從_objc_init的源碼分析,主要分成以下部分:
- environ_init:環(huán)境變量初始化
- tls_init:關(guān)于線程key的綁定
- static_init:運(yùn)行C++靜態(tài)構(gòu)造函數(shù)(只會(huì)運(yùn)行系統(tǒng)級(jí)別的構(gòu)造函數(shù)),在dyld調(diào)用靜態(tài)析構(gòu)函數(shù)之前丁侄,libc會(huì)調(diào)用_objc_init
- runtime_init:runtime運(yùn)行時(shí)環(huán)境初始化,里面操作是unattachedCategories朝巫、allocatedClasses(表的初始化)
- exception_init:libobjc異常處理初始化
- cache_init: 緩存初始化
- _imp_implementationWithBlock_init :?jiǎn)?dòng)回調(diào)機(jī)制鸿摇。
- _dyld_objc_notify_register: dyld的注冊(cè)
在這些部分中,包含了各種初始化的操作劈猿,以及最重要的部分_dyld_objc_notify_register拙吉,其中有使用到map_images(處理dyld給的鏡像文件)、load_images(加載映射鏡像文件)揪荣。
_dyld_objc_notify_register源碼
void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,
_dyld_objc_notify_init init,
_dyld_objc_notify_unmapped unmapped);
map_images對(duì)應(yīng)mapped筷黔,load_images對(duì)應(yīng)init,unmap_image對(duì)應(yīng)unmapped仗颈。
從_dyld_objc_notify_register方法定義位于dyld_priv.h文件中必逆,其對(duì)應(yīng)的實(shí)現(xiàn)是在dyld的源碼中的,在dyld的源碼中我們找到了對(duì)應(yīng)的處理
void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,
_dyld_objc_notify_init init,
_dyld_objc_notify_unmapped unmapped)
{
log_apis("_dyld_objc_notify_register(%p, %p, %p)\n", mapped, init, unmapped);
gAllImages.setObjCNotifiers(mapped, init, unmapped);
}
void AllImages::setObjCNotifiers(_dyld_objc_notify_mapped map, _dyld_objc_notify_init init, _dyld_objc_notify_unmapped unmap)
{
_objcNotifyMapped = map;
_objcNotifyInit = init;
_objcNotifyUnmapped = unmap;
.....
}
從這里我們可以看出揽乱,map_images名眉、load_images、unmap_image的調(diào)用實(shí)現(xiàn)是來自于dyld的凰棉。程序運(yùn)行先是dyld_start鏈接操作损拢,鏈接主程序、執(zhí)行主程序初始化撒犀,所有庫(kù)初始化福压,然后執(zhí)行objc_init函數(shù)掏秩,寫入注冊(cè)函數(shù),通知dyld可以繼續(xù)執(zhí)行其他流程荆姆。
map_images
void
map_images(unsigned count, const char * const paths[],
const struct mach_header * const mhdrs[])
{
mutex_locker_t lock(runtimeLock);
return map_images_nolock(count, paths, mhdrs);
}
map_images會(huì)調(diào)用map_images_nolock蒙幻,map_images_nolock中代碼過長(zhǎng)我們就不一一貼出來分析了,直接看其最關(guān)鍵的代碼
if (hCount > 0) {
_read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
}
_read_images從源碼分析其實(shí)現(xiàn)
- 條件控制加載一次胆筒。
- 修復(fù)selector涉及的混亂問題邮破。
- 發(fā)現(xiàn)類,修復(fù)未解決類仆救,標(biāo)記捆綁類抒和。
- 修復(fù)重新映射類
- 修復(fù)舊的objc_msgSend_fixup調(diào)用
- 發(fā)現(xiàn)protocols,修復(fù)protocol引用
- 修復(fù)@protocol引用
- 分類加載處理
- 類加載處理
- 未解析處理的類彤蔽,防止被侵犯摧莽。
在這過程中,有些比較重要的處理我們需要注意
static size_t UnfixedSelectors;
{
mutex_locker_t lock(selLock);
for (EACH_HEADER) {
if (hi->hasPreoptimizedSelectors()) continue;
bool isBundle = hi->isBundle();
SEL *sels = _getObjc2SelectorRefs(hi, &count);
UnfixedSelectors += count;
for (i = 0; i < count; i++) {
const char *name = sel_cname(sels[i]);
SEL sel = sel_registerNameNoLock(name, isBundle);
if (sels[i] != sel) {
sels[i] = sel;
}
}
}
}
這段源碼中顿痪,sels[i] != sel進(jìn)行帶地址的字符串匹配,兩者字符會(huì)一樣但是地址可能不一樣镊辕。
(lldb) po sels[i]
"class"
(lldb) po sel
"class"
(lldb) p/x sels[i]
(SEL) $3 = 0x000000010045ec5e "class"
(lldb) p/x sel
(SEL) $4 = 0x00007fff77889d1d "class"
(lldb)
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;
}
}
這段代碼中我們主要是看readClass,這個(gè)方法會(huì)讀編譯器編寫的類和元類蚁袭。cls在這里會(huì)由一個(gè)地址征懈,經(jīng)過readClass讀取類信息,readClass讀取的流程后續(xù)再進(jìn)行分析撕阎。
接下來看
for (EACH_HEADER) {
classref_t const *classlist =
_getObjc2NonlazyClassList(hi, &count);
for (i = 0; i < count; i++) {
Class cls = remapClass(classlist[i]);
if (!cls) continue;
addClassTableEntry(cls);
if (cls->isSwiftStable()) {
if (cls->swiftMetadataInitializer()) {
_objc_fatal("Swift class %s with a metadata initializer "
"is not allowed to be non-lazy",
cls->nameForLogging());
}
// fixme also disallow relocatable classes
// We can't disallow all Swift classes because of
// classes like Swift.__EmptyArrayStorage
}
realizeClassWithoutSwift(cls, nil);
}
}
這里是分類的加載處理受裹,具體的加載情況及加載時(shí)機(jī)我們后續(xù)再分析。