IOS底层原理之动态转发流程

前言

在上一篇文章中,我们讲述了快速查找流程,接着向下探究

一、instrumentObjcMessageSends辅助分析方法的介绍

作用: 可以打印出指定区域内调用的所有的方法

@interface MHPerson : NSObject
{
    NSString * newName;
    NSObject * objc;
}

@property(nonatomic,strong)NSString * hobby;
@property(nonatomic,  copy)NSString * name1;

@property(atomic,  copy)NSString * name;

@property(nonatomic,assign)NSInteger age;
-(void)testfunc;
@end

@implementation MHPerson

@end
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        MHPerson *p = [MHPerson alloc];
        instrumentObjcMessageSends(YES);

        [p testfunc];
        instrumentObjcMessageSends(NO);
        // insert code here...
        NSLog(@"Hello, World!");
        
    }
    return 0;
}

查看结果:此方法将指定函数开始与结束之间调用的函数全部以文件的形式输出,存储路径为:\tmp\msgSends,打开finder 找到msgSends-xxxx的文件,此文件内就是全部调用的函数了。

+ MHPerson NSObject resolveInstanceMethod:
+ MHPerson NSObject resolveInstanceMethod:
- MHPerson NSObject forwardingTargetForSelector:
- MHPerson NSObject forwardingTargetForSelector:
- MHPerson NSObject methodSignatureForSelector:
- MHPerson NSObject methodSignatureForSelector:
+ MHPerson NSObject resolveInstanceMethod:
+ MHPerson NSObject resolveInstanceMethod:
- MHPerson NSObject doesNotRecognizeSelector:
- MHPerson NSObject doesNotRecognizeSelector:
- OS_xpc_bundle OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_serializer OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_payload OS_xpc_payload dealloc
- NSObject NSObject dealloc
- OS_dispatch_mach_msg OS_dispatch_object dealloc
- OS_xpc_dictionary OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_object NSObject dealloc
- OS_xpc_dictionary OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_mach_send OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_object NSObject dealloc
- __NSCFConstantString __NSCFString _fastCStringContents:
- OS_xpc_serializer OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_payload OS_xpc_payload dealloc
- NSObject NSObject dealloc
- OS_dispatch_mach_msg OS_dispatch_object dealloc
- OS_xpc_dictionary OS_xpc_object dealloc
- OS_xpc_mach_send OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_object NSObject dealloc
- OS_xpc_dictionary OS_xpc_object dealloc
- OS_xpc_uuid OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_mach_send OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_dictionary OS_xpc_object dealloc
- OS_xpc_dictionary OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_dictionary OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_dictionary OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_object NSObject dealloc
- __NSCFString NSObject isProxy
- __NSCFString NSObject respondsToSelector:
- __NSCFString NSObject class
+ __NSCFString NSObject resolveInstanceMethod:
+ __NSCFString NSObject resolveInstanceMethod:
- __NSCFString __NSCFString isNSString__
- __NSCFString NSObject isNSCFConstantString__
- __NSCFString __NSCFString _fastCStringContents:
- OS_xpc_serializer OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_payload OS_xpc_payload dealloc
- NSObject NSObject dealloc
- OS_dispatch_mach_msg OS_dispatch_object dealloc
- OS_xpc_dictionary OS_xpc_object dealloc
- OS_xpc_mach_send OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_object NSObject dealloc
- OS_xpc_dictionary OS_xpc_object dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_object NSObject dealloc
- OS_dispatch_data NSObject retain
- OS_dispatch_data NSObject release
- OS_dispatch_data NSObject retain
- OS_dispatch_data NSObject release
- OS_dispatch_mach_msg OS_dispatch_object dealloc
- OS_xpc_serializer OS_xpc_object dealloc
- OS_dispatch_mach_msg OS_dispatch_object dealloc
- OS_object NSObject dealloc
- OS_xpc_dictionary OS_xpc_object dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_data OS_xpc_object dealloc
- OS_dispatch_data NSObject release
- OS_dispatch_data OS_dispatch_data dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_uuid OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_uuid OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_object NSObject dealloc
- OS_xpc_data OS_xpc_object dealloc
- OS_dispatch_data NSObject release
- OS_dispatch_data OS_dispatch_data dealloc
- _NSDispatchData NSObject dealloc
- OS_object NSObject dealloc
- OS_object NSObject dealloc
- NSException NSException initWithName:reason:userInfo:
- __NSCFConstantString __NSCFConstantString copy
- __NSCFString __NSCFString copy
- NSException NSObject isKindOfClass:
+ NSMutableDictionary NSObject alloc
+ NSMutableDictionary NSDictionary allocWithZone:
- __NSPlaceholderDictionary __NSPlaceholderDictionary init
- __NSPlaceholderDictionary __NSPlaceholderDictionary initWithCapacity:
- NSException NSException userInfo
+ NSThread NSThread callStackReturnAddresses
+ _NSCallStackArray NSObject alloc
+ _NSCallStackArray NSArray allocWithZone:
+ NSObject NSObject allocWithZone:
- _NSCallStackArray NSObject init
+ NSThread NSThread callStackSymbols
+ _NSCallStackArray _NSCallStackArray arrayWithFrames:count:symbols:
+ _NSCallStackArray NSObject alloc
+ _NSCallStackArray NSArray allocWithZone:
+ NSObject NSObject allocWithZone:
- _NSCallStackArray NSObject init
- __NSDictionaryM __NSDictionaryM setObject:forKey:
- __NSCFConstantString __NSCFString hash
- __NSCFConstantString __NSCFConstantString copyWithZone:
- __NSDictionaryM __NSDictionaryM setObject:forKey:
- __NSCFConstantString __NSCFString hash
- __NSCFConstantString __NSCFConstantString copyWithZone:
- NSException NSObject retain
- NSException NSObject isKindOfClass:
- NSException NSException name
- __NSCFConstantString __NSCFConstantString retain
- __NSCFConstantString __NSCFConstantString autorelease
- NSException NSException reason
- __NSCFString __NSCFString retain
- __NSCFString NSObject autorelease
- __NSDictionaryM __NSDictionaryM objectForKey:
- __NSCFConstantString __NSCFString hash
- _NSCallStackArray _NSCallStackArray count
- _NSCallStackArray _NSCallStackArray objectAtIndex:
- __NSCFNumber __NSCFNumber unsignedLongValue
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSNumber NSNumber numberWithUnsignedInteger:
- __NSCFNumber __NSCFNumber unsignedIntegerValue
- __NSCFNumber __NSCFNumber unsignedLongValue
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSNumber NSNumber numberWithUnsignedInteger:
- __NSCFNumber __NSCFNumber unsignedIntegerValue
- __NSCFNumber __NSCFNumber unsignedLongValue
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSNumber NSNumber numberWithUnsignedInteger:
- __NSCFNumber __NSCFNumber unsignedIntegerValue
- __NSCFNumber __NSCFNumber unsignedLongValue
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSNumber NSNumber numberWithUnsignedInteger:
- __NSCFNumber __NSCFNumber unsignedIntegerValue
- __NSCFNumber __NSCFNumber unsignedLongValue
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSNumber NSNumber numberWithUnsignedInteger:
- __NSCFNumber __NSCFNumber unsignedIntegerValue
- __NSCFNumber __NSCFNumber unsignedLongValue
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSNumber NSNumber numberWithUnsignedInteger:
- __NSCFNumber __NSCFNumber unsignedIntegerValue
- __NSCFNumber __NSCFNumber unsignedLongValue
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSNumber NSNumber numberWithUnsignedInteger:
- __NSCFNumber __NSCFNumber unsignedIntegerValue
- __NSCFNumber __NSCFNumber unsignedLongValue
- __NSDictionaryM __NSDictionaryM objectForKey:
- __NSCFConstantString __NSCFString hash
- _NSCallStackArray NSArray description
- _NSCallStackArray _NSCallStackArray descriptionWithLocale:indent:
+ NSMutableString NSString string
+ NSMutableString NSMutableString allocWithZone:
- __NSCFString NSObject autorelease
- __NSCFString __NSCFString appendString:
- __NSCFString __NSCFString appendFormat:
- __NSCFString __NSCFString appendFormat:
- __NSCFString __NSCFString appendFormat:
- __NSCFString __NSCFString appendFormat:
- __NSCFString __NSCFString appendFormat:
- __NSCFString __NSCFString appendFormat:
- __NSCFString __NSCFString appendFormat:
- __NSCFString __NSCFString appendFormat:
- __NSCFString __NSCFString appendString:
- _NSCallStackArray NSArray componentsJoinedByString:
- __NSCFConstantString __NSCFString isNSString__
- _NSCallStackArray _NSCallStackArray count
- _NSCallStackArray NSArray countByEnumeratingWithState:objects:count:
- _NSCallStackArray _NSCallStackArray count
- _NSCallStackArray NSArray getObjects:range:
- _NSCallStackArray _NSCallStackArray count
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSString NSString stringWithUTF8String:
+ NSString NSString allocWithZone:
- __NSCFString NSObject autorelease
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSString NSString stringWithUTF8String:
+ NSString NSString allocWithZone:
- NSPlaceholderString NSPlaceholderString initWithBytes:length:encoding:
- __NSCFString NSObject autorelease
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSString NSString stringWithUTF8String:
+ NSString NSString allocWithZone:
- NSPlaceholderString NSPlaceholderString initWithBytes:length:encoding:
- __NSCFString NSObject autorelease
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSString NSString stringWithUTF8String:
+ NSString NSString allocWithZone:
- NSPlaceholderString NSPlaceholderString initWithBytes:length:encoding:
- __NSCFString NSObject autorelease
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSString NSString stringWithUTF8String:
+ NSString NSString allocWithZone:
- NSPlaceholderString NSPlaceholderString initWithBytes:length:encoding:
- __NSCFString NSObject autorelease
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSString NSString stringWithUTF8String:
+ NSString NSString allocWithZone:
- NSPlaceholderString NSPlaceholderString initWithBytes:length:encoding:
- __NSCFString NSObject autorelease
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSString NSString stringWithUTF8String:
+ NSString NSString allocWithZone:
- NSPlaceholderString NSPlaceholderString initWithBytes:length:encoding:
- __NSCFString NSObject autorelease
- _NSCallStackArray _NSCallStackArray objectAtIndex:
+ NSString NSString stringWithUTF8String:
+ NSString NSString allocWithZone:
- NSPlaceholderString NSPlaceholderString initWithBytes:length:encoding:
- __NSCFString NSObject autorelease
- __NSCFString NSString description
- __NSCFString NSString description
- __NSCFString NSString description
- __NSCFString NSString description
- __NSCFString NSString description
- __NSCFString NSString description
- __NSCFString NSString description
- __NSCFString NSString description
- _NSCallStackArray NSArray countByEnumeratingWithState:objects:count:
- __NSCFString NSObject autorelease
- __NSCFString __NSCFString UTF8String
- NSMutableString NSString UTF8String
- __NSCFString __NSCFString length
- __NSCFString NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange:
- __NSCFString __NSCFString length
+ NSMutableData NSMutableData allocWithZone:
+ NSObject NSObject allocWithZone:
- NSConcreteMutableData NSConcreteMutableData initWithLength:
- NSConcreteMutableData NSConcreteMutableData setLength:
- NSConcreteMutableData NSConcreteMutableData mutableBytes
- __NSCFString NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange:
- __NSCFString __NSCFString length
- __NSCFString __NSCFString UTF8String
- __NSCFConstantString __NSCFString _fastCStringContents:
- __NSCFString NSObject isProxy
- __NSCFString NSObject respondsToSelector:
- __NSCFString NSObject class
- __NSCFString __NSCFString isNSString__
- __NSCFString NSObject isNSCFConstantString__
- __NSCFString __NSCFString _fastCStringContents:
- OS_dispatch_data NSObject retain
- OS_dispatch_data NSObject release
- OS_dispatch_data NSObject retain
- OS_dispatch_data NSObject release
- OS_xpc_serializer OS_xpc_object dealloc
- OS_dispatch_mach_msg OS_dispatch_object dealloc
- OS_object NSObject dealloc
- OS_xpc_dictionary OS_xpc_object dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_data OS_xpc_object dealloc
- OS_dispatch_data NSObject release
- OS_dispatch_data OS_dispatch_data dealloc
- _NSDispatchData NSObject dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_uuid OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_uuid OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_string OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_uint64 OS_xpc_object dealloc
- OS_object NSObject dealloc
- OS_xpc_data OS_xpc_object dealloc
- OS_dispatch_data NSObject release
- OS_dispatch_data OS_dispatch_data dealloc
- _NSDispatchData NSObject dealloc
- OS_object NSObject dealloc
- OS_object NSObject dealloc

源码

void instrumentObjcMessageSends(BOOL flag)
{
    bool enable = flag;

    // Shortcut NOP
    if (objcMsgLogEnabled == enable)
        return;

    // If enabling, flush all method caches so we get some traces
    if (enable)
        _objc_flush_caches(Nil);

    // Sync our log file
    if (objcMsgLogFD != -1)
        fsync (objcMsgLogFD);

    objcMsgLogEnabled = enable;
}

二、开始探索

之前对resolveInstanceMethod已经探索过了,接下来探索log里面的forwardingTargetForSelector

1.forwardingTargetForSelector

forwardingTargetForSelector
通过此文档可以得知forwardingTargetForSelector为快速转发流程的一个执行者,如果使用此方法对某一个函数进行重定向,那么将非常的有效。forwardingTargetForSelector会返回一个对象,成为未识别的消息的第一继承者,即方法的重定向。如果你想要更多的操作自由,请用forwardInvocation进行操作。

代码验证
@implementation MHPerson
-(id)forwardingTargetForSelector:(SEL)aSelector {
    NSLog(@"%s-%@", __func__, NSStringFromSelector(aSelector));
    return [super forwardingTargetForSelector:aSelector];
}
@end
`2021-07-07 15:05:48.446394+0800 test[11883:1110018] -[MHPerson forwardingTargetForSelector:]-testfunc
2021-07-07 15:05:48.447683+0800 test[11883:1110018] -[MHPerson testfunc]: unrecognized selector sent to instance 0x106328a50`

结果是崩溃,但是在崩溃之前有一次打印,证明了上述的探索方向是OK的,在此过程可以对方法进行重定向,以防止程序crash。

防止崩溃
@interface MHTeacher : NSObject

@end
@implementation MHTeacher

-(void)testfunc {
    NSLog(@"111");
}
-(id)forwardingTargetForSelector:(SEL)aSelector {
    NSLog(@"%s-%@", __func__, NSStringFromSelector(aSelector));
    return [MHTeacher alloc];
//    return [super forwardingTargetForSelector:aSelector];
}
2021-07-07 15:30:46.767623+0800 test[11964:1122435] -[MHPerson forwardingTargetForSelector:]-testfunc
2021-07-07 15:30:46.768480+0800 test[11964:1122435] 111
test was compiled with optimization - stepping may behave oddly; variables may not be available.
2021-07-07 15:30:46.768909+0800 test[11964:1122435] Hello, World!

成功了,但是感觉有点不正常,为什么不用自己的方法来解决呢?

2.methodSignatureForSelector

methodSignatureForSelector
该方法用于协议的实现。此方法也用于必须创建NSInvocation对象的情况,例如在消息转发期间。如果您的对象维护一个委托或能够处理它没有直接实现的消息,您应该重写此方法以返回适当的方法签名。

代码验证
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(testfunc)) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return  [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"%@--%@",anInvocation.target, NSStringFromSelector(anInvocation.selector));
    MHTeacher * t = [MHTeacher alloc];
    if ([self respondsToSelector:anInvocation.selector]) {
        [anInvocation invoke];
    }else if ([self respondsToSelector:anInvocation.selector]) {
        [anInvocation invokeWithTarget:t];
        
    }else {
        NSLog(@"%s - %@", __func__, NSStringFromSelector(anInvocation.selector));
    }
}
2021-07-08 14:44:02.316835+0800 test[1833:50734] <MHPerson: 0x1005957b0>--\M-0WY--0x7ffeefbff3c8--
test was compiled with optimization - stepping may behave oddly; variables may not be available.
2021-07-08 14:44:05.221739+0800 test[1833:50734] <MHPerson: 0x1005957b0>--testfunc
2021-07-08 14:44:05.222021+0800 test[1833:50734] -[MHPerson forwardInvocation:] - testfunc

成功!

小结

快速转发:通过forwardingTargetForSelector实现,如果此时有指定的对象去接收这个消息,就会走之指定对象的查找流程,如果返回是nil,进入慢速转发流程
慢速转发:通过methodSignatureForSelectorforwardInvocation共同实现,如果methodSignatureForSelector返回值是nil,慢速查找流程结束,如果有返回值forwardInvocation的事务处理不处理都不会崩溃

流程图

在这里插入图片描述

三、逆向查看流程

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    frame #0: 0x00007fff2044c92e libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x000000010038de79 libsystem_pthread.dylib`pthread_kill + 263
    frame #2: 0x00007fff203d0411 libsystem_c.dylib`abort + 120
    frame #3: 0x00007fff2043eef2 libc++abi.dylib`abort_message + 241
    frame #4: 0x00007fff204305fd libc++abi.dylib`demangling_terminate_handler() + 266
    frame #5: 0x00007fff2032958d libobjc.A.dylib`_objc_terminate() + 96
    frame #6: 0x00007fff2043e307 libc++abi.dylib`std::__terminate(void (*)()) + 8
    frame #7: 0x00007fff20440beb libc++abi.dylib`__cxxabiv1::failed_throw(__cxxabiv1::__cxa_exception*) + 27
    frame #8: 0x00007fff20440bb2 libc++abi.dylib`__cxa_throw + 116
    frame #9: 0x00007fff20326ec0 libobjc.A.dylib`objc_exception_throw + 350
    frame #10: 0x00007fff2067138d CoreFoundation`-[NSObject(NSObject) doesNotRecognizeSelector:] + 132
    frame #11: 0x00007fff2055690b CoreFoundation`___forwarding___ + 1448
    frame #12: 0x00007fff205562d8 CoreFoundation`_CF_forwarding_prep_0 + 120
  * frame #13: 0x0000000100003d9a test`main(argc=<unavailable>, argv=<unavailable>) at main.m:70:9 [opt]
    frame #14: 0x00007fff20496f5d libdyld.dylib`start + 1
(lldb) 

发现滴啊用的方法___forwarding____CF_forwarding_prep_0是CoreFoundation框架下的,有些奇奇怪怪的,看一下源码,全局搜了一下,结果什么都没有找到,然后用Hopper查看了一下CoreFoundation的macho文件,找到了这个

    int ____forwarding___(int arg0, int arg1) {
    ····省略代码,因为下面会有····

分析一下流程:

forwardingTargetForSelector
  int ____forwarding___(int arg0, int arg1) {
        r15 = rdi;
        var_-48 = *___stack_chk_guard;
        rcx = COND_BYTE_SET(NE);
        if (rsi != 0x0) {  // 根据arg1判断通过_objc_msgSend_stret或_objc_msgSend发送消息
                r12 = _objc_msgSend_stret;
        }
        else {
                r12 = _objc_msgSend;
        }
        rbx = *(r15 + rcx * 0x8); //
        var_-320 = *(r15 + rcx * 0x8 + 0x8);
        r13 = rcx * 0x8;
        if ((rbx & 0x1) == 0x0) goto loc_649bb; //如果为0跳转至loc_649bb

    loc_6498b:
        rcx = *_objc_debug_taggedpointer_obfuscator;  // targed pointer
        rcx = rcx ^ rbx;
        rax = rcx >> 0x1 & 0x7;
        if (rax == 0x7) {
                rax = (rcx >> 0x4 & 0xff) + 0x8;
        }
        if (rax == 0x0) goto loc_64d48;

    loc_649bb:  // rbx & 0x1 如果为0 跳转方法
        var_-328 = r13;
        var_-312 = r12;
        var_-344 = rsi;
        rax = object_getClass(rbx); //拿到当前类
        r12 = rax;
        r13 = class_getName(rax);
        r14 = @selector(forwardingTargetForSelector:);
        if (class_respondsToSelector(r12, r14) == 0x0) goto loc_64a67; // 判断当前那类是否可以响应forwardingTargetForSelector 否 跳转loc_64a67

这一端代码根据arg1判断通过_objc_msgSend_stret或_objc_msgSend发送消息,然后判断当前那类是否可以响应forwardingTargetForSelector 否 跳转loc_64a67

methodSignatureForSelector
   loc_64a67:
        var_-312 = rbx;
        if (strncmp(r13, "_NSZombie_", 0xa) == 0x0) goto loc_64dc1;

    loc_64a8a:
        rbx = @selector(methodSignatureForSelector:);
        r14 = var_-312;
        var_-328 = r15;
        if (class_respondsToSelector(r12, rbx) == 0x0) goto loc_64dd7;

    loc_64ab2:
        rax = _objc_msgSend(r14, rbx);
        rbx = var_-344;
        if (rax == 0x0) goto loc_64e3c;

紧接着判断是否有僵尸对象,如果没有,进入慢速转发流程

  • 如果methodSignatureForSelector没有实现直接跳转到loc_64dd7流程,然后跳转到loc_64e3c
    loc_64dd7:
        rbx = class_getSuperclass(r12);
        r14 = object_getClassName(r14);
        if (rbx == 0x0) {
                _CFLog(0x4, @"*** NSForwarding: warning: object %p of class '%s' does not implement methodSignatureForSelector: -- did you forget to declare the superclass of '%s'?", var_-312, r14, object_getClassName(var_-312));
        }
        else {
                _CFLog(0x4, @"*** NSForwarding: warning: object %p of class '%s' does not implement methodSignatureForSelector: -- trouble ahead", var_-312, r14);
        }
        goto loc_64e3c;
  • 如果methodSignatureForSelector返回值等于nil跳转到loc_64e3c流程
   loc_64e3c:
        rax = sel_getName(var_-320);
        r14 = rax;
        rax = sel_getUid(rax);
        if (rax != var_-320) {
                r8 = rax;
                _CFLog(0x4, @"*** NSForwarding: warning: selector (%p) for message '%s' does not match selector known to Objective C runtime (%p)-- abort", var_-320, r14, r8);
        }
        rbx = @selector(doesNotRecognizeSelector:);
        if (class_respondsToSelector(object_getClass(var_-312), rbx) == 0x0) {
                ____forwarding___.cold.2(var_-312);
        }
        rax = _objc_msgSend(var_-312, rbx);
        asm{ ud2 };
        return rax;
  • 如果methodSignatureForSelector返回了签名信息的对象 (中间跳的有点多,直接上最后的返回代码)
    loc_64a5b:
        *(0x0 + r13) = rax;
        r15 = 0x0;
        goto loc_64d82;

    loc_64d82:
        if (*___stack_chk_guard == var_-48) {
                rax = r15;
        }
        else {
                rax = __stack_chk_fail();
        }
        return rax;

感觉有点乱,先到这里,加油。

总结

底层的探索是在一次次挫败和小有所得中慢慢开拓的,希望我们一起深入学习,提升自我

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值