我正在摆弄 Objective-C 运行时,尝试编译 Objective-C 代码而不将其链接到libobjc
,并且我的程序遇到了一些分段错误问题,因此我从中生成了一个汇编文件。我认为没有必要显示整个汇编文件。在我的某个时刻main
函数,我有以下行(顺便说一句,这是我收到段错误之后的行):
callq *l_objc_msgSend_fixup_alloc
这是定义l_objc_msgSend_fixup_alloc
:
.hidden l_objc_msgSend_fixup_alloc # @"\01l_objc_msgSend_fixup_alloc"
.type l_objc_msgSend_fixup_alloc,@object
.section "__DATA, __objc_msgrefs, coalesced","aw",@progbits
.weak l_objc_msgSend_fixup_alloc
.align 16
l_objc_msgSend_fixup_alloc:
.quad objc_msgSend_fixup
.quad L_OBJC_METH_VAR_NAME_
.size l_objc_msgSend_fixup_alloc, 16
我已经重新实现了objc_msgSend_fixup
作为一个函数(id objc_msgSend_fixup(id self, SEL op, ...)
)返回nil
(只是为了看看会发生什么),但是这个函数甚至没有被调用(程序在调用它之前崩溃了)。
所以,我的问题是,什么是callq *l_objc_msgSend_fixup_alloc
应该做什么以及什么是objc_msgSend_fixup
(after l_objc_msgSend_fixup_alloc:
) 应该是(函数或对象)?
Edit
为了更好地解释,我没有将我的源文件链接到 objc 库。我想做的是实现库的某些部分,只是为了看看它是如何工作的。这是我所做的一种方法:
#include <stdio.h>
#include <objc/runtime.h>
@interface MyClass {
}
+(id) alloc;
@end
@implementation MyClass
+(id) alloc {
// alloc the object
return nil;
}
@end
id objc_msgSend_fixup(id self, SEL op, ...) {
printf("Calling objc_msgSend_fixup()...\n");
// looks for the method implementation for SEL in self's method list
return nil; // Since this is just a test, this function doesn't need to do that
}
int main(int argc, char *argv[]) {
MyClass *m;
m = [MyClass alloc]; // At this point, according to the assembly code generated
// objc_msgSend_fixup should be called. So, the program should, at least, print
// "Calling objc_msgSend_fixup()..." on the screen, but it crashes before
// objc_msgSend_fixup() is called...
return 0;
}
如果运行时需要访问对象的 vtable 或对象类的方法列表以找到要调用的正确方法,那么实际执行此操作的函数是什么?我觉得是这样的objc_msgSend_fixup
, 在这种情况下。所以,当objc_msgSend_fixup
被调用时,它接收一个对象作为其参数之一,如果该对象尚未初始化,则该函数将失败。
所以,我实现了我自己的版本objc_msgSend_fixup
。根据上面的汇编源码,应该是可以调用的。该函数是否实际上正在寻找作为参数传递的选择器的实现并不重要。我只是想objc_msgSend_lookup
被称为。但是,它没有被调用,也就是说,查找对象数据的函数甚至没有被调用,而不是被调用并导致错误(因为它返回一个nil
(顺便说一句,这并不重要))。程序段之前失败objc_msgSend_lookup
叫做...
Edit 2
更完整的组装片段:
.globl main
.align 16, 0x90
.type main,@function
main: # @main
.Ltmp20:
.cfi_startproc
# BB#0:
pushq %rbp
.Ltmp21:
.cfi_def_cfa_offset 16
.Ltmp22:
.cfi_offset %rbp, -16
movq %rsp, %rbp
.Ltmp23:
.cfi_def_cfa_register %rbp
subq $32, %rsp
movl $0, %eax
leaq l_objc_msgSend_fixup_alloc, %rcx
movl $0, -4(%rbp)
movl %edi, -8(%rbp)
movq %rsi, -16(%rbp)
movq L_OBJC_CLASSLIST_REFERENCES_$_, %rsi
movq %rsi, %rdi
movq %rcx, %rsi
movl %eax, -28(%rbp) # 4-byte Spill
callq *l_objc_msgSend_fixup_alloc
movq %rax, -24(%rbp)
movl -28(%rbp), %eax # 4-byte Reload
addq $32, %rsp
popq %rbp
ret
For l_objc_msgSend_fixup_alloc
, 我们有:
.hidden l_objc_msgSend_fixup_alloc # @"\01l_objc_msgSend_fixup_alloc"
.type l_objc_msgSend_fixup_alloc,@object
.section "__DATA, __objc_msgrefs, coalesced","aw",@progbits
.weak l_objc_msgSend_fixup_alloc
.align 16
l_objc_msgSend_fixup_alloc:
.quad objc_msgSend_fixup
.quad L_OBJC_METH_VAR_NAME_
.size l_objc_msgSend_fixup_alloc, 16
For L_OBJC_CLASSLIST_REFERENCES_$_
:
.type L_OBJC_CLASSLIST_REFERENCES_$_,@object # @"\01L_OBJC_CLASSLIST_REFERENCES_$_"
.section "__DATA, __objc_classrefs, regular, no_dead_strip","aw",@progbits
.align 8
L_OBJC_CLASSLIST_REFERENCES_$_:
.quad OBJC_CLASS_$_MyClass
.size L_OBJC_CLASSLIST_REFERENCES_$_, 8
OBJC_CLASS_$_MyClass
是一个指向MyClass
结构体定义,它也是由编译器生成的,并且也存在于汇编代码中。