OC底层原理探索之汇编objc_msgSend原理分析
2023-09-10 12:55:34
揭秘 Objective-C 中的神秘黑盒:objc_msgSend 汇编实现
探索 ObjC 消息传递的底层机制
Objective-C 作为一门面向对象的编程语言,其消息传递机制一直是其核心的秘密武器。今天,我们将潜入汇编指令的世界,一步步剖析 objc_msgSend 函数的实现,揭开其神秘的面纱,让你对 ObjC 底层机制有更深入的理解。
汇编指令的逐行分解
objc_msgSend 的汇编实现是 libobjc.a 库中的精妙杰作。对于 arm64 架构,它的代码如下:
_objc_msgSend:
stp x0, x1, [sp, -16]! // 保存参数和lr寄存器
ldr x2, [x0, #8] // x2 = self
ldr x0, [x0] // x0 = cls
ldp x0, x1, [x0, x2, lsl #3] // x0 = method pointer, x1 = encoding
ldr x16, [x1, #4] // x16 = arguments size (encoding low 4 bits)
add x0, x0, x16, lsl #3 // x0 = actual method pointer
ldp x2, x3, [sp, #16] // x2 = receiver, x3 = selector
br x0 // jmp to actual method
1. 保存参数和寄存器
旅程的第一步是妥善保存我们的参数和 lr 寄存器,因为我们即将踏入一个未知的领域。stp x0, x1, [sp, -16]!
指令就像一位管家,将这些珍贵的物品整齐地放入栈中,为我们的冒险做好准备。
2. 获取 self 和 cls
现在,我们准备好探索消息传递的对象了。ldr x2, [x0, #8]
指令提取第一个参数(self),而 ldr x0, [x0]
指令获取第二个参数(cls)。
3. 计算方法指针和编码
接下来,是时候计算出方法指针,这是指向实际方法的指南针。ldp x0, x1, [x0, x2, lsl #3]
指令根据 cls 和 self 计算方法指针(x0)和编码(x1)。
4. 计算参数大小
编码中隐藏着一条关键的信息——参数的大小,它存储在低 4 位中。ldr x16, [x1, #4]
指令小心地提取这个值,因为它将帮助我们确定实际方法指针。
5. 计算实际方法指针
万众期待的时刻到了!add x0, x0, x16, lsl #3
指令将参数大小左移 3 位并加到方法指针上,得到我们一直在寻找的实际方法指针(x0)。
6. 恢复 self 和 selector
最后,我们需要恢复 self 和 selector,以便可以将其传递给实际方法。ldp x2, x3, [sp, #16]
指令从栈中检索这些值,为最后的步骤做好准备。
7. 跳转到实际方法
一切就绪,br x0
指令将我们送往实际方法的入口。方法指针就像一扇门,它将我们带到代码中方法的具体位置,让消息可以被处理。
深入理解消息传递机制
通过剖析 objc_msgSend 的汇编实现,我们揭开了 ObjC 消息传递机制的神秘面纱。它是一系列复杂但高效的步骤,协调对象、方法和参数之间的交互。
结论
深入理解 objc_msgSend 的汇编实现是通往 ObjC 底层奥秘的窗口。它不仅使我们能够了解消息传递机制的内部运作,还为深入探索 ObjC 的高级特性奠定了基础。
常见问题解答
- objc_msgSend 在哪里实现?
objc_msgSend 的汇编实现位于 libobjc.a 库中。 - 如何计算方法指针?
方法指针根据 cls 和 self 通过ldp x0, x1, [x0, x2, lsl #3]
指令计算。 - 参数大小在哪里存储?
参数大小存储在编码的低 4 位中,通过ldr x16, [x1, #4]
指令提取。 - 如何跳转到实际方法?
实际方法指针存储在 x0 寄存器中,br x0
指令用于跳转。 - objc_msgSend 对 ObjC 语言有什么重要性?
objc_msgSend 是 ObjC 消息传递机制的核心,它使对象能够与方法和参数进行交互。