这是一篇很无聊的文章,对开发移动App的人来说没什么卵用。本文仅仅是对@hursing的xcode反汇编调试iOS模拟器程序(五)调试objc_msgSend函数的x86-64再现。
环境
- Xcode 8.2.1
- objc4-706源码
步骤
新建一个iOS工程,viewDidLoad中添加如下代码:
UILabel *label = [[UILabel alloc] init];
[label setText:@"xxxxcontent"];
main函数加断点:
运行工程,注意要在模拟器环境下调试,跑到断点处,添加以下lldb命令,给-[UILabel setText:]方法加个断点
(lldb) b -[UILabel setText:]
继续运行,会停在如下的反汇编处
这里就是 -[UILabel setText:] 的汇编实现,对runtime有了解的都知道,这个方法最终会转换成这样的一个函数,
objc_msgSend(id self, SEL op,...)
/*-[UILabel setText:]会相应的传递三个参数:
self对应label实例
op对应@selector(setText:)
param对应字符串@"xxxContent"
*/
下面利用lldb验证下,单步调试Step over,直到objc_msgSend的入口
cpu运行到这里,已经为objc_msgSend函数调用传递好了参数,根据x86-64架构的ABI约定
%rdi,%rsi,%rdx,%rcx,%r8,%r9 用作函数参数,依次对应第1参数,第2参数…..
可知,此时self,op,param会放到%rdi,%rsi,%rdx三个寄存器来传递,下面验证,lldb输入以下命令,打印寄存器内容
(lldb) register read
结果
看图可知,rsi寄存器确实放的是方法名:__setText:,多一个下划线是因为符合C语言调用规范的函数在转化为符号时都以下划线为前缀,rdx确实放的是字符串@”xxxContent”