Runtime底层原理总结--反汇编分析消息转发 - 简书
source link: https://www.jianshu.com/p/29d0272a97ff?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Runtime底层原理总结--反汇编分析消息转发
消息转发:发送一个消息,也就是sel查找imp,当没有找到imp,接下来进入动态方法解析,如果开发者并没有处理,会进入消息转发。
前几篇文章介绍了Runtime底层原理和动态方法解析总结
,我们知道如果前面的动态方法解析也没有解决问题的话,那么就会进入消息转发_objc_msgForward_impcache
方法,会有快速消息转发和慢速消息转发。_objc_msgForward_impcache
方法会从C转换到汇编部分__objc_msgForward_impcache
进行快速消息转发,执行闭源__objc_msgForward
。
如果我们的方法没有查找到会报错_forwarding_prep_0
但是我们在源代码中找不到该方法,除了前面文章--Runtime底层原理--动态方法解析、消息转发源码分析提到的方法外,我们可以用反汇编分析消息转发。
首先进入/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CoreFoundation.framework
中,找到可执行文件CoreFoundation
,将该文件拖入hopper中,找到CFInitialze
可以看到了___forwarding_prep_0___
进入___forwarding_prep_0___
内部,
从崩溃堆栈信息中看到有执行forwarding,进入forwarding内部,里面判断了_objc_msgSend_stret、_objc_msgSend、taggedpointer之后有个forwardingTargetForSelector:
,判断forwardingTargetForSelector:
没有实现,没有实现跳转到loc_126fc7,
进入loc_126fc7,判断僵尸对象之后执行方法签名methodSignatureForSelector:
,如果有值,获取Name、是否有效的位移等,之后会响应_forwardStackInvocation:
,
如果没有响应_forwardStackInvocation:
,则会响应forwardInvocation:
,给rdi发送rax消息,rdi就是NSInvocation,rax就是selforwardInvocation:
,这就是消息转发的流程
对_objc_msgForward
部分进行反汇编成OC代码:
int __forwarding__(void *frameStackPointer, int isStret) {
id receiver = *(id *)frameStackPointer;
SEL sel = *(SEL *)(frameStackPointer + 8);
const char *selName = sel_getName(sel);
Class receiverClass = object_getClass(receiver);
// 调用 forwardingTargetForSelector:
if (class_respondsToSelector(receiverClass, @selector(forwardingTargetForSelector:))) {
id forwardingTarget = [receiver forwardingTargetForSelector:sel];
if (forwardingTarget && forwarding != receiver) {
if (isStret == 1) {
int ret;
objc_msgSend_stret(&ret,forwardingTarget, sel, ...);
return ret;
}
return objc_msgSend(forwardingTarget, sel, ...);
}
}
// 僵尸对象
const char *className = class_getName(receiverClass);
const char *zombiePrefix = "_NSZombie_";
size_t prefixLen = strlen(zombiePrefix); // 0xa
if (strncmp(className, zombiePrefix, prefixLen) == 0) {
CFLog(kCFLogLevelError,
@"*** -[%s %s]: message sent to deallocated instance %p",
className + prefixLen,
selName,
receiver);
<breakpoint-interrupt>
}
// 调用 methodSignatureForSelector 获取方法签名后再调用 forwardInvocation
if (class_respondsToSelector(receiverClass, @selector(methodSignatureForSelector:))) {
NSMethodSignature *methodSignature = [receiver methodSignatureForSelector:sel];
if (methodSignature) {
BOOL signatureIsStret = [methodSignature _frameDescriptor]->returnArgInfo.flags.isStruct;
if (signatureIsStret != isStret) {
CFLog(kCFLogLevelWarning ,
@"*** NSForwarding: warning: method signature and compiler disagree on struct-return-edness of '%s'. Signature thinks it does%s return a struct, and compiler thinks it does%s.",
selName,
signatureIsStret ? "" : not,
isStret ? "" : not);
}
if (class_respondsToSelector(receiverClass, @selector(forwardInvocation:))) {
NSInvocation *invocation = [NSInvocation _invocationWithMethodSignature:methodSignature frame:frameStackPointer];
[receiver forwardInvocation:invocation];
void *returnValue = NULL;
[invocation getReturnValue:&value];
return returnValue;
} else {
CFLog(kCFLogLevelWarning ,
@"*** NSForwarding: warning: object %p of class '%s' does not implement forwardInvocation: -- dropping message",
receiver,
className);
return 0;
}
}
}
SEL *registeredSel = sel_getUid(selName);
// selector 是否已经在 Runtime 注册过
if (sel != registeredSel) {
CFLog(kCFLogLevelWarning ,
@"*** NSForwarding: warning: selector (%p) for message '%s' does not match selector known to Objective C runtime (%p)-- abort",
sel,
selName,
registeredSel);
} // doesNotRecognizeSelector
else if (class_respondsToSelector(receiverClass,@selector(doesNotRecognizeSelector:))) {
[receiver doesNotRecognizeSelector:sel];
}
else {
CFLog(kCFLogLevelWarning ,
@"*** NSForwarding: warning: object %p of class '%s' does not implement doesNotRecognizeSelector: -- abort",
receiver,
className);
}
// The point of no return.
kill(getpid(), 9);
}
该文章为记录本人的学习路程,希望能够帮助大家,也欢迎大家点赞留言交流!!!文章地址:https://www.jianshu.com/p/29d0272a97ff
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK