我在弄乱 Objective-C 运行时,试图编译 Objective-c 代码而不将其链接到libobjc
,并且我在程序中遇到了一些分段错误问题,因此我从中生成了一个汇编文件。我认为没有必要显示整个程序集文件。在我的main
函数的某个时刻,我有以下行(顺便说一句,这是我得到 seg 错误的那一行):
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
(之后l_objc_msgSend_fixup_alloc:
)应该是什么(函数或对象)?
编辑
为了更好地解释,我没有将我的源文件链接到 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
被叫。但是,它没有被调用,也就是说,查找对象数据的函数甚至没有被调用,而是被调用并导致错误(因为它返回 a nil
(顺便说一句,没关系)) . objc_msgSend_lookup
程序段在被调用之前失败...
编辑 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
对于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
对于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
结构定义的指针,它也是由编译器生成的,它也存在于汇编代码中。