arm64: 剖析 ARM64 下的 objc_msgSend

zhouyingjie 坐标: 99092 目录:婚姻家庭

以下全部代码就是 nil 的处理过程。

0x00a4 mov x1, #0x0 0x00a8 movi d0, #0000000000000000 0x00ac movi d1, #0000000000000000 0x00b0 movi d2, #0000000000000000 0x00b4 movi d3, #0000000000000000 0x00b8 ret

nil 的处理方式和其他代码完全不同。没有类的查找也没有方法的派发。这里为 nil 做的所有事情就是返回 0 给调用者。

事实上这个过程有点复杂,objc_msgSend 不知道调用者希望得到什么类型的返回值,是一个整型?两个?还是一个浮点数类型,或是其他?

幸运的是,所有用于返回值的寄存器都能够被安全的覆盖,即使他们没有被用于这次特定的调用者的返回值。整型的返回值被保存在 x0 和 x1 中,浮点数返回值被保存在向量寄存器 v0 至 v3 中。还有多个寄存器被用于返回更小的结构。

上面的代码清除了 x1,以及 v0 至 v3。d0 至 d3 指的是对应的 v 寄存器的底部后半部分,存储在其中可以清楚前半部分,所以 4 条 movi 指令的作用就是清空这 4 个寄存器。然后将控制权返回给调用者。

你可能想要知道为什么不清楚 x0。回答很简单:x0 中放的是 self,现在的情况中是 nil,所以它原本就是 0!你可以节省一条清零的指令。

对于寄存器不够存储的,更大结构的返回值会怎样?这需要调用者的一些合作。通过调用者来分配足够多的内存存储大型的结构体,并将内存地址传入 x8。函数通过写入这块内存来返回值。objc_msgSend 不能清除这块内存,因为它不知道返回值到底有多大。为了解决这个问题,编译器生成的代码会在调用 objc_msgSend 之前用 0 填满这块内存。

以上就是 nil 的处理方法,以及 objc_msgSend 的全部

专题栏目
最新