Objective c “objc\u msgSend\u fixup”到底是什么?
我在处理Objective-C运行时,试图编译Objective-C代码而不将其与Objective c “objc\u msgSend\u fixup”到底是什么?,objective-c,assembly,segmentation-fault,objective-c-runtime,Objective C,Assembly,Segmentation Fault,Objective C Runtime,我在处理Objective-C运行时,试图编译Objective-C代码而不将其与libobjc链接,并且我在程序中遇到了一些分段错误问题,因此我从中生成了一个汇编文件。我认为没有必要显示整个装配文件。在我的main函数的某个点上,我得到了下面的一行(顺便说一下,这是我得到seg故障的那一行): 下面是l_objc_msgSend_fixup_alloc的定义: .hidden l_objc_msgSend_fixup_alloc # @"\01l_objc_msgSend_fixup_allo
libobjc
链接,并且我在程序中遇到了一些分段错误问题,因此我从中生成了一个汇编文件。我认为没有必要显示整个装配文件。在我的main
函数的某个点上,我得到了下面的一行(顺便说一下,这是我得到seg故障的那一行):
下面是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\u msgSend\u fixup
重新实现为一个函数(id objc\u msgSend\u fixup(id self,SEL op,…)
),它返回nil
(看看会发生什么),但这个函数甚至没有被调用(程序在调用之前崩溃)
所以,我的问题是,callq*l\u objc\u msgSend\u fixup\u alloc
应该做什么,以及objc\u msgSend\u fixup\u fixup
(在l\u objc\u msgSend\u fixup\u alloc:
之后)应该是(函数还是对象)
编辑
为了更好地解释,我没有将源文件链接到objc库。我想做的是实现libray的一些部分,看看它是如何工作的。以下是我所做工作的方法:
#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;
}
对于l\u objc\u msgSend\u fixup\u 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\u OBJC\u CLASSLIST\u REFERENCES\u$\ uuu
:
.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\u CLASS\uu$\u MyClass
是指向MyClass
结构定义的指针,该结构定义也由编译器生成,它也存在于汇编代码中。好的,您的代码是Objective-C,而不是C
编辑/关于objc\u msgSend\u修正
<代码> ObjcMSgsEnthFixUp> /COD>是内部Objy-C运行时的东西,用于使用C++样式方法VTABLE管理调用。
你可以在这里阅读一些关于这方面的文章:
objc\u msgSend
函数完成。这就是您在执行以下操作时使用的内容:
[ someObject someFunction: someArg ];
翻译成:
objc_msgSend( someObject, @selector( someFunction ), someArg );
因此,如果您在这样的运行时函数中有segfault,例如objc\u msgSend\u fixup\u alloc
,这当然意味着您在未初始化的指针(如果不使用ARC)或已释放的对象上调用方法。
比如:
NSObject * o;
[ o retain ]; // Will segfault somewhere in the Obj-C runtime in non ARC, as 'o' may point to anything.
或:
因此,即使segfault位置在运行时,在您自己的代码中,这肯定是一个基本的Objective-C内存管理问题。
尝试启用NSZombie,应该会有所帮助。还可以尝试静态分析器 编辑2 它在运行时崩溃,因为运行时需要访问对象的vtable以找到要调用的正确方法 由于对象无效,vtable查找会导致无效指针的取消引用 这就是segfault位于此处的原因 编辑3 您说您没有与objc库链接。
您将«objc库»称为什么 我这样问是因为,正如我们在您的代码中看到的,您正在使用Objective-C编译器 您可能不链接到提供基础对象的“基础”框架,但是既然使用的是Objy-C编译器,那么<强> LIBOBJC <强>库(提供运行时)仍将隐式链接。 你确定不是这样吗?在生成的二进制文件上尝试一个简单的
nm
编辑4
如果确实是这样,那么要重新创建运行时,objc\u msgSend\u fixup
不是第一个要执行的函数
定义类时,运行时需要了解它,因此需要编写类似于objc\u allocateClassPair
和friends之类的代码
您还需要确保编译器不会使用快捷方式
我在你的代码中看到过这样的东西:L\u OBJC\u CLASSLIST\u REFERENCES\u$\ uu
这个符号是否存在于您自己的版本中?要理解什么是
objc\u msgSend\u fixup
以及它的作用,有必要确切地知道Objective-C中消息发送是如何执行的。有一天,所有objc程序员都听说编译器将[obj message]
语句转换为objc\u msgSend(obj,sel_registerName(“message”))
调用。然而,这并不完全准确
为了更好地解释我的解释,请考虑下面的Objc片段:
[obj mesgA];
[obj mesgB];
[obj mesgA];
[obj mesgB];
在这个代码段中,两条消息被发送到obj
,每条消息被发送两次。因此,您可以想象生成了以下代码:
objc_msgSend(obj, sel_registerName("mesgA"));
objc_msgSend(obj, sel_registerName("mesgB"));
objc_msgSend(obj, sel_registerName("mesgA"));
objc_msgSend(obj, sel_registerName("mesgB"));
但是,sel_registerName
可能成本太高,因此在调用特定方法时调用它不是明智之举。然后,编译器为要发送的每条消息生成如下结构:
typedef struct message_ref {
id (*trampoline) (id obj, struct message_ref *ref, ...);
union {
const char *str;
SEL sel;
};
} message_ref;
因此,在上面的示例中,当程序启动时,我们有如下内容:
message_ref l_objc_msgSend_fixup_mesgA = { &objc_msgSend_fixup, "mesgA" };
message_ref l_objc_msgSend_fixup_mesgB = { &objc_msgSend_fixup, "mesgB" };
id objc_msgSend_fixup(id obj, struct message_ref *ref, ...) {
ref->sel = sel_registerName(ref->str);
ref->trampoline = &objc_msgSend_fixedup;
objc_msgSend_fixedup(obj, ref, ...);
}
id objc_msgSend_fixedup(id obj, struct message_ref *ref, ...) {
objc_msgSend(obj, ref->sel, ...);
}
当需要将这些消息发送到obj
时,编译器将生成与以下内容等效的代码:
l_objc_msgSend_fixup_mesgA.trampoline(obj, &l_objc_msgSend_fixup_mesgA, ...); // [obj mesgA];
l_objc_msgSend_fixup_mesgB.trampoline(obj, &l_objc_msgSend_fixup_mesgB, ...); // [obj mesgB];
在程序启动时,消息引用trampoline是指向objc\u msgSend\u fixup
函数的指针。对于每个message\u ref
,当其trampoline
指针第一次被调用时,objc\u msgSend\u fixup
将被调用,以接收消息要发送到的obj
,并且emessage\u ref
从中调用它的结构。因此,objc\u msgSend\u fixup
必须做的是获取要调用的消息的选择器。由于每个消息引用只需执行一次,因此,objc\u msgSend\u fixup
还必须用指向另一个乐趣的指针替换ref的trampoline
字段不修复消息选择器的操作。此函数称为objc\u msgSend\u fixedup
message_ref l_objc_msgSend_fixup_mesgA = { &objc_msgSend_fixup, "mesgA" }; message_ref l_objc_msgSend_fixup_mesgB = { &objc_msgSend_fixup, "mesgB" };
l_objc_msgSend_fixup_mesgA.trampoline(obj, &l_objc_msgSend_fixup_mesgA, ...); // [obj mesgA];
l_objc_msgSend_fixup_mesgB.trampoline(obj, &l_objc_msgSend_fixup_mesgB, ...); // [obj mesgB];
id objc_msgSend_fixup(id obj, struct message_ref *ref, ...) {
ref->sel = sel_registerName(ref->str);
ref->trampoline = &objc_msgSend_fixedup;
objc_msgSend_fixedup(obj, ref, ...);
}
id objc_msgSend_fixedup(id obj, struct message_ref *ref, ...) {
objc_msgSend(obj, ref->sel, ...);
}