所以我正在调试一个问题,并试图弄清楚这是怎么发生的。
以下是obj-c运行时中方法的程序集,称为objc_msgsend()
libobjc.A.dylib`objc_msgSend:
0x7fff9084a0c0 <+0>: testq %rdi, %rdi
0x7fff9084a0c3 <+3>: je 0x7fff9084a140 ; <+128>
0x7fff9084a0c6 <+6>: testb $0x1, %dil
0x7fff9084a0ca <+10>: jne 0x7fff9084a14b ; <+139>
0x7fff9084a0cd <+13>: movabsq $0x7ffffffffff8, %r11
0x7fff9084a0d7 <+23>: andq (%rdi), %r11
0x7fff9084a0da <+26>: movq %rsi, %r10
0x7fff9084a0dd <+29>: andl 0x18(%r11), %r10d
我正在使用Xcode的lldb来查看寄存器和地址。
这是我得到的有趣输出,当我第一次检查偏移+0处的寄存器时(预期):
(lldb) register read
r11 = 0x00007fff74a940f0 (void *)0x00007fff74a94118: NSObject
偏移+13(预期)之后:
(lldb) register read
r11 = 0x00007ffffffffff8
偏移+23后(不期望):
(lldb) register read
r11 = 0x0000000100761138 (void *)0x0000000100761160: GTMOAuth2WindowController
然后如果我po
寄存器此处:
(lldb) po $rdi
<GTMOAuth2WindowController: 0x6100001c2850>
(lldb) po &$rdi
0x000000010bc2b3b8
(lldb) po $r11
GTMOAuth2WindowController
(lldb) po &$r11
0x000000010bc2b3b8
所以这就是我迷失的地方;在偏移+23之后,当register read
时,该地址是什么?
0x0000000100761138
。我希望它有0x6100001c2850
,来自+23
如果我po $r11
它打印出类名(这是预期的,因为我们正在查看isa
属性),如果我在内存中打印指针的位置,它就不会t匹配register read
中的地址,它与%rdi
(预期)的地址匹配。
答案 0 :(得分:2)
%r11
之后的<+23>
中的地址0x0000000100761138
是代表您的GTMOAuth2WindowController
类的类对象的地址。
在编译时定义一个类(使用@interface
和@implementation
)时,运行时会有一个表示类的特殊对象。事实上,它被称为“类对象”,并且就像您创建的所有对象一样是一个真实对象。这意味着类对象本身可以响应消息。在po %r11
之后说<+23>
时,调试器将description
消息发送到类对象。类对象的description
方法将类的名称返回为NSString
,因此调试器打印了类的名称。
You can learn more about class objects here。该页面上的图片链接已在Chrome中中断,但您可以点击它以查看pdf。