回顾:
上边博客分析了objc_msgSend通过receiver和SEL查找到对应imp的过程,这篇我们探索下如果最终未找到imp,执行的__objc_msgSend_uncached这个方法。
一、真机跟汇编流程 (可以真机调试的小伙伴自行探索)
register read x1
读各种内存比对,然后验证回顾并加深objc_msgSend流程。
二、__objc_msgSend_uncached
汇编就只有这么几行:
STATIC_ENTRY __objc_msgSend_uncached
UNWIND __objc_msgSend_uncached, FrameWithNoSaves
// THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band p15 is the class to search
MethodTableLookup
TailCallFunctionPointer x17 //br $0 返回执行$0
END_ENTRY __objc_msgSend_uncached
宏TailCallFunctionPointer:
.macro TailCallFunctionPointer
// $0 = function pointer value
br $0
.endmacro
.macro MethodTableLookup
SAVE_REGS MSGSEND
// lookUpImpOrForward(obj, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER)
// receiver and selector already in x0 and x1
mov x2, x16
mov x3, #3
bl _lookUpImpOrForward
// IMP in x0
mov x17, x0
RESTORE_REGS MSGSEND
.endmacro
重点是_lookUpImpOrForward,但全局搜索不到,那么去掉下划线我们再全局搜索,最终在objc-runtime-new.mm文件中找到了该函数。
我们终于又回到了C++的世界,不用再看晦涩的汇编了。
疑问:为什么objc_msgSend要用汇编来写呢?
答:
- 汇编接近机器语言,执行比较快,保持高效率。
- 安全。
- 更加动态化。
三、慢速查找流程
遍历寻找imp的过程是比较耗时&#x