我很惊讶搜索 j__objc_msgSend 会在stackoverflow上返回0结果,Google似乎也不太了解它。根据它的disassembly,j__objc_msgSend只调用objc_msgSend,那么为什么当我们有objc_msgSend时我们需要j__objc_msgSend?一般来说,j__objc_msgSend和objc_msgSend的区别是什么?
特别是在这个screenshot中,最右边的分支以“函数结束”结尾的区别是什么,最左边的分支结尾没有“函数结束”?是否与 j__objc_msgSend 有关?
答案 0 :(得分:1)
这是ARM RISC代码,ARM的首选编程模式是 relative - 不使用绝对地址,始终使用“IP +/- offset”。这里,被叫地址超出了直接调用或跳转的范围,编译器使用了他能找到的最近的地址。它增加了额外的跳跃(或超过1!),但它与位置无关。 (*)
编译器无法使用简单指令构造跳转到目标地址,因为您无法使用RISC程序集立即加载每个可能的2 ^ 32数字。
如果例程objc_msgSend
返回自己的,那么这相当于call objc_msgSend; return
- 只是更短。从当前函数的角度来看,两种形式都只进行一次“返回”。
(*)您可以在反汇编截图中看到(为什么不是文本?)R12加载目标和当前地址之间的差异。这种差异由编译器计算; not 在原始二进制文件中显示为减法,这是IDA的工作。然后将差异添加到当前地址 - 无论这是什么!立即值objc_msgSend - 0x1AE030
使用足够少的位在一条指令中加载到R12中(您应该熟悉的ARM RISC'功能)。
如果您想知道j__label
语法:那只是IDA,告诉您这是直接跳转到已知标签。据推测,如果您的代码足够长,您可能会发现此标签的距离太大,因此您可能会找到j__j__objc_msgSend
。