首页
学习
活动
专区
圈层
工具
发布
    • 综合排序
    • 最热优先
    • 最新优先
    时间不限
  • 来自专栏HelloCode开发者学习平台

    objc_msgSend底层探索(上)

    我这篇文章呢,主要来分析一下objc_msgSend,关于他的一个执行流程和快速查找的过程,那首先我需要了解一下Runtime是怎么调起底层的呢?也就是Runtime是怎么发起的呢? ,我进行任何的方法的调用,他在底层的名字都叫做objc_msgSend,直观的翻译过来就是消息的发送。 所以我通过这种objc_msgSend的方式,也是一样能够实现OC的方法调用的。这里Runtime的三种方式就用了两种,还一种方式是什么呢? 那问题就来了,objc_msgSend是如何让消息传递到父类的呢?难道我要去看他的底层源码吗?先不管这么多,我先全局搜索一下试试。 报了个错,根据之前调用objc_msgSend的经验,也一样的需要强转一下。

    28910编辑于 2022-01-14
  • 来自专栏网罗开发

    objc_msgSend 实现分析

    /message.h> [obj sayHello]; objc_msgSend(obj,@selector(sayHello)); objc_msgSend(obj,sel_registerName 需要配置让 objc_msgSend 支持多个参数。 3. objc_msgSend源码解析 objc_msgSend 打断点发现是 libobjc.A.dylib 库的: ? 汇编相关的指令可以参考我之前的文章汇编-循环、选择、判断 3.1 _objc_msgSend 源码解读如下: //入口 ENTRY _objc_msgSend UNWIND _objc_msgSend ,__objc_msgSend_uncached) CacheLookup NORMAL, _objc_msgSend, __objc_msgSend_uncached #if SUPPORT_TAGGED_POINTERS

    1.1K30发布于 2021-07-21
  • 来自专栏西二旗一哥

    iOS - Dissecting objc_msgSend on ARM64

    objc_msgSend 的任务是把对象和选择器传入并查找相应方法的函数指针,然后跳转到这个函数指针指向的位置。 查找方法的过程是很复杂的。 0x002 cbz x9, __objc_msgSend_uncached x9 包含了从 bucket 中读取的选择器,这条命令比较了它和0并且如果它不是0的话会跳转到 __objc_msgSend_uncached 这就是 `objc_msgSend` 主体的结尾。剩下的是对 nil 和 标记指针特殊的处理。 objc_msgSend 不能清除这块内存,因为它不知道返回值到底有多大。为了解决这个问题,编译器生成的代码会在调用 objc_msgSend 之前用 0 填满这块内存。 这就是 nil 处理的结尾,也是整个 objc_msgSend 的结尾。 对于 objc_msgSend() 代码有一点不够清晰就是缓存中也包含了 "负" 的缓存值来记录 misses 的缓存。

    86240发布于 2018-09-30
  • 来自专栏欧阳大哥的轮子

    深入解构objc_msgSend函数的实现

    objc_msgSend方法内部会访问和使用到的数据成员。 objc_msgSend函数的内部实现 objc_msgSend函数是所有OC方法调用的核心引擎,它负责查找真实的类或者对象方法的实现,并去执行这些方法函数。 }; /* objc_msgSend的C语言版本伪代码实现. receiver: 是调用方法的对象 op: 是要调用的方法名称字符串 */ id objc_msgSend(id receiver 是指传递给objc_msgSend的OC方法中的参数。 else return objc_msgSend_uncached(receiver, op, cls, ...); } /* 方法未命中缓存处理函数:objc_msgSend_uncached

    1.1K20发布于 2018-08-22
  • 来自专栏HelloCode开发者学习平台

    objc_msgSend底层探索(下)

    上一篇里面,我从OC层面来探索了objc_msgSend如何进行消息的发送,对普通开发者来说也是比较容易理解的,那很多人都知道,Runtime是由C或者C++以及汇编语言写的一套底层的API。 然后我打开objc源码,全局搜索objc_msgSend。 竟然有644个!看哪一个呢?我之前已经剧透了,objc_msgSend是用汇编写的,所以我来找汇编文件就可以了,按住command。 展开arm64.s文件之后,也会看到很多的objc_msgSend,如果稍微有点熟悉的话,你就会知道,在汇编里面,经常有这么一个方法,ENTRY。 这里先插一个问题,为什么objc_msgSend是用汇编写的?而不是用C/C++写呢?我刚刚随便一搜索就搜到了很多的objc_msgSend。 也就是说,源码里面包含了多个版本的objc_msgSend方法,他们是根据返回值的类型和调用者的类型分别处理的,如果说用C或者C++来实现。

    32820编辑于 2022-01-14
  • 来自专栏小黑娃Henry

    OC底层探索11-objc_msgSend慢速查找流程OC底层探索11-objc_msgSend慢速查找流程

    由于首次调用或者缓存扩容等问题导致的缓存查找失败,就需要进入慢速查找流程. objc_msgSend慢速查找 慢速查找入口-汇编部分 在快速查找流程无法找到对应缓存的时候,会跳到CheckMiss\JumpMiss 这个macro中并且走到__objc_msgSend_uncached这个函数中。 STATIC_ENTRY __objc_msgSend_uncached UNWIND __objc_msgSend_uncached, FrameWithNoSaves // THIS 点击下一步来到__objc_msgSend_uncached ? 最终调用lookUpImpOrForward,而且给出了c++函数的位置 ? objc_msgSend慢速流程.png cache_getImp没有发生递归 STATIC_ENTRY _cache_getImp GetClassFromIsa_p16 p0 CacheLookup

    43810发布于 2021-08-09
  • 来自专栏iOS技术

    iOS 底层拾遗:objc_msgSend 与方法缓存

    前言 Runtime 消息发送与转发流程总是大家关注的重点,却常常忽略方法缓存机制这个显著提升 objc_msgSend 性能的幕后功臣。 一、从 objc_msgSend 谈起 注意:arm64 汇编代码会出现很多p字母,实际上是一个宏,64 位下是x,32 位下是w,p就是寄存器。 objc_msgSend objc_msgSend 代码如下: ENTRY _objc_msgSend UNWIND _objc_msgSend, NoFram ...// 处理对象是 STATIC_ENTRY __objc_msgSend_uncached UNWIND __objc_msgSend_uncached, FrameWithNoSaves MethodTableLookup 那么在前面分析的__objc_msgSend_uncached方法就仍然会调用这个IMP,接下来就是真正的消息转发阶段了。

    1.3K10发布于 2019-10-28
  • 来自专栏网罗开发

    objc_msgSend 消息快速查找 - cache 查找

    上一篇文章分析了 objc_msgSend 的汇编实现,这边文章继续分析 objc_msgSend 中缓存的查找逻辑以及汇编代码是如何进入 c/c++ 代码的。 1. CacheLookup 查找缓存 1.1 CacheLookup源码分析 传递的参数是 NORMAL, _objc_msgSend, __objc_msgSend_uncached: //NORMAL, _objc_msgSend, __objc_msgSend_uncached .macro CacheLookup Mode, Function, MissLabelDynamic, MissLabelConstant __objc_msgSend_uncached() } 2. __objc_msgSend_uncached 在缓存没有命中的情况下会走到 __objc_msgSend_uncached() 的逻辑: STATIC_ENTRY __objc_msgSend_uncached

    73420发布于 2021-07-21
  • 来自专栏小黑娃Henry

    OC底层探索10-objc_msgSend快速查找流程OC底层探索10-objc_msgSend快速查找流程

    ((void (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("sayHello")); //简化: objc_msgSend 方法快速查找 objc_msgSend源码流程 想要了解方法是如何查找的,就需要查看objc_msgSend的方法实现。(前提:方法快速查找流程使用汇编编写) ? //objc_msgSend(id,Sel); ENTRY _objc_msgSend UNWIND _objc_msgSend, NoFrame // p0表示该方法的第一个参数。 CacheLookup NORMAL, _objc_msgSend objc_msgSend快速查找源码流程 想要看懂这部分内容需要对:类的结构、cacae_t的结构有一个清楚的理解。 ... .endmacro 查找失败后都会进入__objc_msgSend_uncached STATIC_ENTRY __objc_msgSend_uncached UNWIND __objc_msgSend_uncached

    52230发布于 2021-08-09
  • 来自专栏欧阳大哥的轮子

    静态拦截iOS对象方法调用的简易实现

    因此我们可以将所有静态库字符串表中的objc_msgSend统一替换为另外一个长度相同的字符串:hook_msgSend(名字任意只要长度一致并唯一)即可。 然后在主工程源代码中实现一个名字为hook_msgSend的函数即可。 这个函数必须要和objc_msgSend的函数签名保持一致,这样在链接时所有静态库中的objc_msgSend调用都会统一转化为hook_msgSend调用。 下面的是具体的实现步骤: 1. 在主工程中编写hook_msgSend的实现。 hook_msgSend的函数签名要和objc_msgSend保持一致,并且要在主工程代码中实现,而且必须要用汇编代码实现。 三)、将字符串表中的objc_msgSend字符串替换为hook_msgSend字符串。 四)、保存并关闭静态库.a文件。 5. 编译、链接并运行你的主工程程序。

    2.3K30发布于 2020-01-15
  • 来自专栏逆向与安全

    某IOS可信ID产品原理分析

    (v31, (const char *)&unk_190A2D5CF); v138 = v32; v33 = objc_msgSend(v32, "rmxhgtexxxYJsr { v37 = (void *)objc_alloc(&OBJC_CLASS___xxYuxCNxkKxxZe); v134 = objc_msgSend (v37, (const char *)&unk_190A2D5CF); v133 = objc_msgSend(v134, "GlvxhXtNyNxYxb::", v137, (v4, "init"); v5 = (void *)objc_alloc(&OBJC_CLASS___NSDictionary); *(_QWORD *)&v386 = objc_msgSend (v5, "init"); v6 = (void *)objc_alloc(&OBJC_CLASS___xxxNxNxxfRxxxx); v385 = objc_msgSend(v6, "init

    2.2K40发布于 2020-10-29
  • 来自专栏Helloted

    无源调试

    objc_msgSend函数是runtime中核心的函数,为什么会崩溃在这,怎么处理这种crash? 2、objc_msgSend原理 每一个OC对象有一个类,每一个OC类都有一个方法列表。 另一个原因是objc_msgSend必须够快。 当然,谁都不会想要用汇编写下整个复杂的消息查找过程。这没必要。 因此,objc_msgSend主要有以下几个步骤: 获取传入的对象的类 获取这个类的方法缓存 通过传入的selector,在缓存中查找方法 如果缓存中没有,调用C代码 跳到这个方法的IMP 3、objc_msgSend 使用符号断点,我们可以查看objc_msgSend的符号指令 libobjc.A.dylib`objc_msgSend: 0x1931bb6a0 <+0>: cmp x0, #0x0 4、objc_msgSend crash原因 如上图,对象在堆内存区,在还没有被销毁之前,isa指针会指向其Class对象的内存地址,此时objc_msgSend是没有问题的,而对象被销毁之后,堆内存被回收

    65020编辑于 2022-06-08
  • 来自专栏HelloCode开发者学习平台

    iOS底层原理之Runimte 运行时&方法的本质

    追根溯源找到了objc_msgSend,下面探究下objc_msgSend。 既然方法调用都是通过objc_msgSend的,那么我可不可以直接通过objc_msgSend发消息呢。 在用objc_msgSend方式发送消息。 objc_msgSend汇编探究 探究objc_msgSend首先找到objc_msgSend所在的底层库。怎么找呢? 必须拿出yysd-汇编 汇编显示objc_msgSend在libobjc.A.dylib系统库,实际上看objc_msgSend前缀是objc猜测应该在 objc源码中。

    57610编辑于 2022-01-11
  • 来自专栏Helloted

    C++与Objective-C混编

    编译器会将一个下面的一个消息表达式 [receiver message] 转变成一个消息函数 objc_msgSend,这个函数将接收者和消息中提到的方法的名称(即方法selector)作为其两个主要参数 : objc_msgSend(receiver, selector) 消息中传递的其他参数也在 objc_msgSend被处理 objc_msgSend(receiver, selector, arg1 所以,利用objc_msgSend也可以达到混编的目的 假设我们有一个OC对象NewObject继承自NSObject: @interface NewObject : NSObject - (void ((id)objc_getClass("NewObject"), sel_registerName("alloc"), sel_registerName("init")); objc_msgSend ((id)myobj, sel_registerName("doSomethingWith:"), (char *)"abc"); 如果是类方法则更简单了: objc_msgSend((id)objc_getClass

    2.1K20编辑于 2022-06-08
  • 来自专栏岑志军的专栏

    (3)OC中消息和消息转发-01

    )((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc (eat)); 上面方法调用的意思就是:给p对象发送名为eat的消息,所以OC中给对象发消息本质上都是调用objc_msgSend方法,接着看下苹果官方文档对这个方法的定义(我是用的Dash查看的): 和objc_msgSend_stret。 接下来我们再看下objc_msgSend的底层实现,objc 源码,发现底层是用汇编代码实现的(表示很蛋疼): ENTRY _objc_msgSend UNWIND _objc_msgSend, NoFrame __objc_msgSend_uncached UNWIND __objc_msgSend_uncached, FrameWithNoSaves // THIS IS NOT A CALLABLE

    58940发布于 2018-05-28
  • 来自专栏逆向与安全

    IOS防作弊产品技术原理分析

    objc_retainAutoreleasedReturnValue(v5); 85 CFRelease(v69); 86 CFRelease(v68); 87 v6 = objc_msgSend (v63, (const char *)&unk_195F9F96E); 96 month = objc_msgSend(v63, (const char *)&unk_195F9F973); 97 day = objc_msgSend(v63, (const char *)&unk_195F9F979); 98 hour = objc_msgSend(v63, (const char *)&unk_195F34810); 99 minute = objc_msgSend(v63, (const char *)&unk_195F5F105); 100 second = objc_msgSend (v37, "setKey:", v46); 196 objc_msgSend(v37, "setClazz:", v40); 197 objc_msgSend

    3.9K31发布于 2019-06-04
  • 来自专栏Golang语言社区

    Runtime 中的消息机制

    说道Objective-C里面的消息机制,大部分人都知道是调用方法其实就是发送消息,一个叫objc_msgSend的东西负责的。 这个实现的函数就是objc_msgSend,该函数定义如下: void objc_msgSend(id self, SEL cmd, ...) 函数调用)中的那些参数 举例来说: id return = [git commit:parameter]; 上面的Objective-C方法在运行时会转换成如下函数: id return = objc_msgSend (git, @selector(commit), parameter); objc_msgSend函数会在接收者所属的类中搜寻其方法列表,如果能找到这个跟选择子名称相同的方法,就跳转到其实现代码,往下执行 说过了OC的函数调用实现,你会觉得消息转发要处理很多,尤其是在搜索上,幸运的是objc_msgSend在搜索这块是有做缓存的,每个OC的类都有一块这样的缓存,objc_msgSend会将匹配结果缓存在快速映射表

    1.3K50发布于 2018-03-27
  • 来自专栏技术总结

    iOS进阶之传递消息

    、理解objc_msgSend的作用 对象上调用方法用OC的术语,叫做“传递消息”。消息有名称或选择子,可以接受参数,而且可能还有返回值。 先理解C语言的函数调用方式。 ,其“原型”如下: void objc_msgSend(id self, SEL cmd, ...) ); objc_msgSend函数会依据接受者与选择子的函数来调用适当的方法。 objc_msgSend等函数正是通过这张表格来寻找应该执行的方法并跳至其实现的。请注意,原型的样子和objc_msgSend函数很像。 这项优化对objc_msgSend非常关键,如果不这么做的话,那么每次调用Objective-C方法之前,都需要为调用objc_msgSend函数准备“栈帧”,大家在“栈踪迹”中可以看到这种“栈帧”。

    1K60发布于 2018-05-22
  • 来自专栏大宇笔记

    iOS Runtime msg_send报错 too many argument to function call

    BUG:使用objc_msgSend时报错 原因:Xcode默认设置是禁用Runtime objc_msgSend call方法的 解决办法: 将 objc_msgSend设置成no.不让禁用即可 所有用objc_msgSend肯定可以上架的。 ?

    60320发布于 2019-01-15
  • 来自专栏Swift-开源分析

    iOS16 和 Xcode14 如何改进 App 大小和运行时性能

    bl _objc_msgSend dateComponents.month = 2022; bl _objc_msgSend objc_msgSend 方法是汇编实现的,它的函数定义是 Id objc_msgSend(id self, SEL _cmd, ...) : id 表示当前对象,sel 表示这个对象的所有方法。 前面已经提到调用 objc_msgSend 需要指令(例如上图中,使用 bl 汇编指令跳转 _objc_msgSend 函数)。 不过我们仍然需要调用真正的 objc_msgSend函数。 同样,objc_msgSend有另一个不同的间接方式来加载函数本身的地址并调用它。 但带来的负面影响是这将连续进行两次调用(_objc_msgSend$dateFromComponents 和 _objc_msgSend),这对性能来说并不理想。

    4.4K30编辑于 2022-06-26
领券