Objective c “objc\u msgSend\u fixup”到底是什么?

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

我在处理Objective-C运行时,试图编译Objective-C代码而不将其与
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管理调用。 你可以在这里阅读一些关于这方面的文章:

编辑/结束

现在说说你的过错

Objective-C使用运行时进行消息传递、分配等

消息传递(方法调用)通常由
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
,并且e
message\u ref
从中调用它的结构。因此,
objc\u msgSend\u fixup
必须做的是获取要调用的消息的选择器。由于每个消息引用只需执行一次,因此,
objc\u msgSend\u fixup
还必须用指向另一个乐趣的指针替换ref的
trampoline
字段不修复消息选择器的操作。此函数称为
objc\u msgSend\u fixedupmessage_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, ...);
}