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); // 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底层原理总结--反汇编分析消息转发相关推荐
- Runtime底层原理--Runtime简介、函数注释
Runtime官方文档介绍直通车 扩展:编译时 看到运行时就会想到编译时,编译时主要是将源代码翻译成可识别的机器语言,如果编译时类型检查等翻译过程中发现语法分析之类有错误会给出相应的提示.比如OC,s ...
- Runtime底层原理--动态方法解析、消息转发源码分析
了解了Runtime函数含义,我们就可以直接使用Runtime的API了,那接下来继续探究Runtime的源码,经过源码分析来更加深刻的了解Runtime原理. 开发应用 都知道Runtime很重要, ...
- Runtime底层原理探究(二) --- 消息发送机制(慢速查找)
源码 /*********************************************************************** * lookUpImpOrForward. * ...
- LR_scheduler及warmup底层原理和代码分析
LR_scheduler LR_scheduler是用于调节学习率lr的,在代码中,我们经常看到这样的一行代码 scheduler.step() 通过这行代码来实现lr的更新的,那么其中的底层原理是什 ...
- Runloop底层原理--源码分析
什么是Runloop? Runloop不仅仅是一个运行循环(do-while循环),也是提供了一个入口函数的对象,消息机制处理模式.运行循环从两种不同类型的源接收事件. 输入源提供异步事件,通常是来自 ...
- Runtime底层原理--动态方法解析总结
方法的底层会编译成消息,消息进行递归,先从实例方法开始查找,到父类最后到NSObject.如果在汇编部分快速查找没有找到IMP,就会进入C/C++中的动态方法解析进入lookUpImpOrForwar ...
- iOS之深入解析数组遍历的底层原理和性能分析
一.OC 数组的类体系 当我们创建一个 NSArray 对象时,实际上得到的是 NSArray 的子类 __NSArrayI 对象.同样的,创建 NSMutableArray 对象,得到的同样是其子类 ...
- Dubbo底层原理架构图
今天和大家分享一下Dubbo底层原理的架构分析 首先看一张dubbo经典图: 简单分析流程图如下: 1.首先服务提供者会启动服务,然后将服务注册到服务注册中心. 2.服务消费者会定时拉取服务提供者列表 ...
- iOS之深入解析objc_msgSend消息转发机制的底层原理
一.抛砖引玉 objc_msgSend() 消息发送的过程就是 通过 SEL 查找 IMP 的过程 . objc_msgSend() 是用 汇编语言 实现的,使用汇编实现的优势是: 消息发送的过程需要 ...
最新文章
- python就业方向选择-【经验分享】Python最好的几大就业方向与岗位技能要求!
- Shiro集成Web时的Shiro JSP标签
- 【USACO15DEC】最大流Max Flow
- js中的时间与毫秒数互相转换,倒计时
- Codeforces Round #401 (Div. 2) E. Hanoi Factory 栈
- 电脑添加打印机方法/步骤
- 博客园在我的博客添加点击小心心特效
- vue前期项目搭建所需要安装的插件,idea操作
- MaxDEA如何计算超效率DEA
- GreenSock GSAP 3.0 最新版 所有内容创建于2020年4月4日
- Windows7下Edge的首页关闭我的资讯,兴趣等
- linux fedora14 u盘运行,用U盘安装FEDORA14后必须从U盘启动,从硬盘无法启动
- 计算机原理非门,反相器和非门有什么区别
- python分号_python中的分号(“;”)
- 程序员希望收到什么礼物
- 安装Android Studio遇到的几个困难和解决办法
- C++小游戏 苍穹世界2.2 测试版
- 在vue项目中插入视频
- 走进梦龙冰淇淋的生产线 揭晓“灯塔工厂”背后的秘密
- IDEA 修改单行的注释格式
热门文章
- html5中有哪些新属性,整理HTML5中表单的常用属性及新属性
- 三、深入elasticsearch基本语法
- 四十五、和我一起看看,国外的Python考试到底是怎么样(上篇)
- Bengio等人新作:基于双层规划的端到端分子构象生成框架
- 详解预训练模型、图神经网络、模型压缩、知识图谱、信息抽取、序列模型、深度学习、语法分析、文本处理...
- 百度机器翻译已经进化到什么程度?
- 【公开课预告】百度语言与知识最新技术成果详解
- EMNLP2018论文解读 | 利用篇章信息提升机器翻译质量
- 自动机器学习(AutoML)最新综述
- ACM MM 2018论文概述:基于多粒度监督的图像语义物体协同标注