【发布时间】:2012-08-27 00:56:33
【问题描述】:
我在弄乱 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。但是,它没有被调用,也就是说,查找对象数据的函数甚至没有被调用,而是被调用并导致错误(因为它返回一个nil(顺便说一句,它没有事情))。在调用objc_msgSend_lookup 之前程序段失败...
编辑 2
更完整的汇编sn-p:
.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 结构定义的指针,它也是由编译器生成的,它也存在于汇编代码中。
【问题讨论】:
-
这是 Objective-C,而不是 C。重新标记。
-
+1 因为尽管这不是我的问题,但它促使我学习新东西
-
感谢您的澄清,但您能否提供崩溃的汇编输出?实际段错误之前的 10 或 20 行?
-
查看我帖子底部的编辑 3...
-
嘿,伙计们,我刚刚发现了一些有趣的事情。如果我将 objc_msgSend_fixup 定义放在主文件中(就像我在上面的代码 sn-ps 中所做的那样),则调用该函数并打印该消息,就像我希望它做的那样。但我实际上将 objc_msgSend_fixup 的定义放在另一个与主文件链接的文件中。这样,我的主要可执行文件似乎没有找到函数地址。我会尝试做出一些改变。这似乎真的是一个链接问题......
标签: objective-c assembly segmentation-fault objective-c-runtime