消息转发:发送一个消息,也就是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); // 0xaif (strncmp(className, zombiePrefix, prefixLen) == 0) {CFLog(kCFLogLevelError,@"*** -[%s %s]: message sent to deallocated instance %p",className + prefixLen,selName,receiver);<breakpoint-interrupt>}// 调用 methodSignatureForSelector 获取方法签名后再调用 forwardInvocationif (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);} // doesNotRecognizeSelectorelse 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

Runtime底层原理总结--反汇编分析消息转发相关推荐

  1. Runtime底层原理--Runtime简介、函数注释

    Runtime官方文档介绍直通车 扩展:编译时 看到运行时就会想到编译时,编译时主要是将源代码翻译成可识别的机器语言,如果编译时类型检查等翻译过程中发现语法分析之类有错误会给出相应的提示.比如OC,s ...

  2. Runtime底层原理--动态方法解析、消息转发源码分析

    了解了Runtime函数含义,我们就可以直接使用Runtime的API了,那接下来继续探究Runtime的源码,经过源码分析来更加深刻的了解Runtime原理. 开发应用 都知道Runtime很重要, ...

  3. Runtime底层原理探究(二) --- 消息发送机制(慢速查找)

    源码 /*********************************************************************** * lookUpImpOrForward. * ...

  4. LR_scheduler及warmup底层原理和代码分析

    LR_scheduler LR_scheduler是用于调节学习率lr的,在代码中,我们经常看到这样的一行代码 scheduler.step() 通过这行代码来实现lr的更新的,那么其中的底层原理是什 ...

  5. Runloop底层原理--源码分析

    什么是Runloop? Runloop不仅仅是一个运行循环(do-while循环),也是提供了一个入口函数的对象,消息机制处理模式.运行循环从两种不同类型的源接收事件. 输入源提供异步事件,通常是来自 ...

  6. Runtime底层原理--动态方法解析总结

    方法的底层会编译成消息,消息进行递归,先从实例方法开始查找,到父类最后到NSObject.如果在汇编部分快速查找没有找到IMP,就会进入C/C++中的动态方法解析进入lookUpImpOrForwar ...

  7. iOS之深入解析数组遍历的底层原理和性能分析

    一.OC 数组的类体系 当我们创建一个 NSArray 对象时,实际上得到的是 NSArray 的子类 __NSArrayI 对象.同样的,创建 NSMutableArray 对象,得到的同样是其子类 ...

  8. Dubbo底层原理架构图

    今天和大家分享一下Dubbo底层原理的架构分析 首先看一张dubbo经典图: 简单分析流程图如下: 1.首先服务提供者会启动服务,然后将服务注册到服务注册中心. 2.服务消费者会定时拉取服务提供者列表 ...

  9. iOS之深入解析objc_msgSend消息转发机制的底层原理

    一.抛砖引玉 objc_msgSend() 消息发送的过程就是 通过 SEL 查找 IMP 的过程 . objc_msgSend() 是用 汇编语言 实现的,使用汇编实现的优势是: 消息发送的过程需要 ...

最新文章

  1. linux 下screen命令
  2. 『ACM-算法-数据结构』信息竞赛进阶指南--树状数组 (模板)
  3. CF429E Points and Segments(欧拉回路)
  4. 弹簧和线程:TaskExecutor
  5. python的作者叫什么_作者的来历是什么?
  6. Intel Core Enhanced Core架构/微架构/流水线 (6) - 指令预译码/指令队列/指令译码
  7. 一个Linux驱动:Simple - REALLY simple memory mapping demonstration.
  8. [试题]Python大赛部分答案
  9. VC中Radio控件的用法
  10. java课程设计学生信息管理系统。
  11. Teamtalk线程池
  12. 芝麻授权 java调用_手机浏览器怎么调用支付宝进行用户授权呢?
  13. 申请高德地图开发者key
  14. BNN系列-Dropout as a Bayesian Approximation
  15. 图机器学习——2.1 节点嵌入:基于随机游走
  16. 《Rework》读书笔记
  17. 微服务选择Spring Cloud还是Dubbo?
  18. 复旦陈果老师关于孤独、寂寞、朋友和人际的课堂笔记
  19. linux下创建php文档,linux新建文件有哪些方法
  20. iOS创建framework静态库(SDK组件化)

热门文章

  1. go mongodb排序查询_「赵强老师」MongoDB中的索引(下)
  2. oracle取本月最后一天是星期几_Oracle 获取本周、本月、本季、现年的第一天和最后一天...
  3. 股票系列,动态规划,加油,九月太浪了,十月不许浪
  4. java架构师学习笔记
  5. CTO案头必备|AI技术产业落地的42章经
  6. node n 切换node版本失败_记一次 node-sass@4.x 安装失败
  7. feign直接走熔断_四、Spring Cloud之熔断处理 Hystrix
  8. python内置函数源代码_4.内置函数源码总结
  9. pyqt 事件更新图片显示_使用PyQTamp;树莓派制作一个天气站
  10. Struts2-day1总结