如何Objective-C的运行时检索类和方法列表? [英] How does the Objective-C runtime retrieve the list of classes and methods?

查看:220
本文介绍了如何Objective-C的运行时检索类和方法列表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我得到以下的Objective-C源文件:

If I get the following Objective-C source file:

// test.m
#import <objc/Object.h>

@interface MySuperClass: Object {

}
-(void) myMessage1;
@end

@implementation MySuperClass
-(void) myMessage1 {

}
@end

@interface MyClass: MySuperClass {

}
-(void) myMessage2;
@end

@implementation MyClass
-(void) myMessage2 {

}
@end

int main() {

    return 0;
}

和尝试从其生成汇编文件,铛-fobjc-非脆弱-ABI -fnext运行时-S test.m ,我得到以下组装code:

and try to generate an assembly file from it with clang -fobjc-nonfragile-abi -fnext-runtime -S test.m, I get the following assembly code:

    .file   "test.m"
    .text
    .align  16, 0x90
    .type   _2D__5B_MySuperClass_20_myMessage1_5D_,@function
_2D__5B_MySuperClass_20_myMessage1_5D_: # @"\01-[MySuperClass myMessage1]"
.Ltmp0:
    .cfi_startproc
# BB#0:
    movq    %rdi, -8(%rsp)
    movq    %rsi, -16(%rsp)
    ret
.Ltmp1:
    .size   _2D__5B_MySuperClass_20_myMessage1_5D_, .Ltmp1-_2D__5B_MySuperClass_20_myMessage1_5D_
.Ltmp2:
    .cfi_endproc
.Leh_func_end0:

    .align  16, 0x90
    .type   _2D__5B_MyClass_20_myMessage2_5D_,@function
_2D__5B_MyClass_20_myMessage2_5D_:      # @"\01-[MyClass myMessage2]"
.Ltmp3:
    .cfi_startproc
# BB#0:
    movq    %rdi, -8(%rsp)
    movq    %rsi, -16(%rsp)
    ret
.Ltmp4:
    .size   _2D__5B_MyClass_20_myMessage2_5D_, .Ltmp4-_2D__5B_MyClass_20_myMessage2_5D_
.Ltmp5:
    .cfi_endproc
.Leh_func_end1:

    .globl  main
    .align  16, 0x90
    .type   main,@function
main:                                   # @main
.Ltmp6:
    .cfi_startproc
# BB#0:
    movl    $0, %eax
    movl    $0, -4(%rsp)
    ret
.Ltmp7:
    .size   main, .Ltmp7-main
.Ltmp8:
    .cfi_endproc
.Leh_func_end2:

    .type   L_OBJC_CLASS_NAME_,@object # @"\01L_OBJC_CLASS_NAME_"
    .section    "__TEXT,__objc_classname,cstring_literals","aw",@progbits
L_OBJC_CLASS_NAME_:
    .asciz   "MySuperClass"
    .size   L_OBJC_CLASS_NAME_, 13

    .type   l_OBJC_METACLASS_RO_$_MySuperClass,@object # @"\01l_OBJC_METACLASS_RO_$_MySuperClass"
    .section    "__DATA, __objc_const","aw",@progbits
    .align  8
l_OBJC_METACLASS_RO_$_MySuperClass:
    .long   1                       # 0x1
    .long   40                      # 0x28
    .long   40                      # 0x28
    .zero   4
    .quad   0
    .quad   L_OBJC_CLASS_NAME_
    .quad   0
    .quad   0
    .quad   0
    .quad   0
    .quad   0
    .size   l_OBJC_METACLASS_RO_$_MySuperClass, 72

    .type   OBJC_METACLASS_$_MySuperClass,@object # @"OBJC_METACLASS_$_MySuperClass"
    .section    "__DATA, __objc_data","aw",@progbits
    .globl  OBJC_METACLASS_$_MySuperClass
    .align  8
OBJC_METACLASS_$_MySuperClass:
    .quad   OBJC_METACLASS_$_Object
    .quad   OBJC_METACLASS_$_Object
    .quad   _objc_empty_cache
    .quad   _objc_empty_vtable
    .quad   l_OBJC_METACLASS_RO_$_MySuperClass
    .size   OBJC_METACLASS_$_MySuperClass, 40

    .type   L_OBJC_METH_VAR_NAME_,@object # @"\01L_OBJC_METH_VAR_NAME_"
    .section    "__TEXT,__objc_methname,cstring_literals","aw",@progbits
L_OBJC_METH_VAR_NAME_:
    .asciz   "myMessage1"
    .size   L_OBJC_METH_VAR_NAME_, 11

    .type   L_OBJC_METH_VAR_TYPE_,@object # @"\01L_OBJC_METH_VAR_TYPE_"
    .section    "__TEXT,__objc_methtype,cstring_literals","aw",@progbits
L_OBJC_METH_VAR_TYPE_:
    .asciz   "v16@0:8"
    .size   L_OBJC_METH_VAR_TYPE_, 8

    .type   l_OBJC_$_INSTANCE_METHODS_MySuperClass,@object # @"\01l_OBJC_$_INSTANCE_METHODS_MySuperClass"
    .section    "__DATA, __objc_const","aw",@progbits
    .align  8
l_OBJC_$_INSTANCE_METHODS_MySuperClass:
    .long   24                      # 0x18
    .long   1                       # 0x1
    .quad   L_OBJC_METH_VAR_NAME_
    .quad   L_OBJC_METH_VAR_TYPE_
    .quad   _2D__5B_MySuperClass_20_myMessage1_5D_
    .size   l_OBJC_$_INSTANCE_METHODS_MySuperClass, 32

    .type   l_OBJC_CLASS_RO_$_MySuperClass,@object # @"\01l_OBJC_CLASS_RO_$_MySuperClass"
    .align  8
l_OBJC_CLASS_RO_$_MySuperClass:
    .long   0                       # 0x0
    .long   8                       # 0x8
    .long   8                       # 0x8
    .zero   4
    .quad   0
    .quad   L_OBJC_CLASS_NAME_
    .quad   l_OBJC_$_INSTANCE_METHODS_MySuperClass
    .quad   0
    .quad   0
    .quad   0
    .quad   0
    .size   l_OBJC_CLASS_RO_$_MySuperClass, 72

    .type   OBJC_CLASS_$_MySuperClass,@object # @"OBJC_CLASS_$_MySuperClass"
    .section    "__DATA, __objc_data","aw",@progbits
    .globl  OBJC_CLASS_$_MySuperClass
    .align  8
OBJC_CLASS_$_MySuperClass:
    .quad   OBJC_METACLASS_$_MySuperClass
    .quad   OBJC_CLASS_$_Object
    .quad   _objc_empty_cache
    .quad   _objc_empty_vtable
    .quad   l_OBJC_CLASS_RO_$_MySuperClass
    .size   OBJC_CLASS_$_MySuperClass, 40

    .type   L_OBJC_CLASS_NAME_1,@object # @"\01L_OBJC_CLASS_NAME_1"
    .section    "__TEXT,__objc_classname,cstring_literals","aw",@progbits
L_OBJC_CLASS_NAME_1:
    .asciz   "MyClass"
    .size   L_OBJC_CLASS_NAME_1, 8

    .type   l_OBJC_METACLASS_RO_$_MyClass,@object # @"\01l_OBJC_METACLASS_RO_$_MyClass"
    .section    "__DATA, __objc_const","aw",@progbits
    .align  8
l_OBJC_METACLASS_RO_$_MyClass:
    .long   1                       # 0x1
    .long   40                      # 0x28
    .long   40                      # 0x28
    .zero   4
    .quad   0
    .quad   L_OBJC_CLASS_NAME_1
    .quad   0
    .quad   0
    .quad   0
    .quad   0
    .quad   0
    .size   l_OBJC_METACLASS_RO_$_MyClass, 72

    .type   OBJC_METACLASS_$_MyClass,@object # @"OBJC_METACLASS_$_MyClass"
    .section    "__DATA, __objc_data","aw",@progbits
    .globl  OBJC_METACLASS_$_MyClass
    .align  8
OBJC_METACLASS_$_MyClass:
    .quad   OBJC_METACLASS_$_Object
    .quad   OBJC_METACLASS_$_MySuperClass
    .quad   _objc_empty_cache
    .quad   _objc_empty_vtable
    .quad   l_OBJC_METACLASS_RO_$_MyClass
    .size   OBJC_METACLASS_$_MyClass, 40

    .type   L_OBJC_METH_VAR_NAME_2,@object # @"\01L_OBJC_METH_VAR_NAME_2"
    .section    "__TEXT,__objc_methname,cstring_literals","aw",@progbits
L_OBJC_METH_VAR_NAME_2:
    .asciz   "myMessage2"
    .size   L_OBJC_METH_VAR_NAME_2, 11

    .type   l_OBJC_$_INSTANCE_METHODS_MyClass,@object # @"\01l_OBJC_$_INSTANCE_METHODS_MyClass"
    .section    "__DATA, __objc_const","aw",@progbits
    .align  8
l_OBJC_$_INSTANCE_METHODS_MyClass:
    .long   24                      # 0x18
    .long   1                       # 0x1
    .quad   L_OBJC_METH_VAR_NAME_2
    .quad   L_OBJC_METH_VAR_TYPE_
    .quad   _2D__5B_MyClass_20_myMessage2_5D_
    .size   l_OBJC_$_INSTANCE_METHODS_MyClass, 32

    .type   l_OBJC_CLASS_RO_$_MyClass,@object # @"\01l_OBJC_CLASS_RO_$_MyClass"
    .align  8
l_OBJC_CLASS_RO_$_MyClass:
    .long   0                       # 0x0
    .long   8                       # 0x8
    .long   8                       # 0x8
    .zero   4
    .quad   0
    .quad   L_OBJC_CLASS_NAME_1
    .quad   l_OBJC_$_INSTANCE_METHODS_MyClass
    .quad   0
    .quad   0
    .quad   0
    .quad   0
    .size   l_OBJC_CLASS_RO_$_MyClass, 72

    .type   OBJC_CLASS_$_MyClass,@object # @"OBJC_CLASS_$_MyClass"
    .section    "__DATA, __objc_data","aw",@progbits
    .globl  OBJC_CLASS_$_MyClass
    .align  8
OBJC_CLASS_$_MyClass:
    .quad   OBJC_METACLASS_$_MyClass
    .quad   OBJC_CLASS_$_MySuperClass
    .quad   _objc_empty_cache
    .quad   _objc_empty_vtable
    .quad   l_OBJC_CLASS_RO_$_MyClass
    .size   OBJC_CLASS_$_MyClass, 40

    .type   L_OBJC_LABEL_CLASS_$,@object # @"\01L_OBJC_LABEL_CLASS_$"
    .section    "__DATA, __objc_classlist, regular, no_dead_strip","aw",@progbits
    .align  8
L_OBJC_LABEL_CLASS_$:
    .quad   OBJC_CLASS_$_MySuperClass
    .quad   OBJC_CLASS_$_MyClass
    .size   L_OBJC_LABEL_CLASS_$, 16

    .type   L_OBJC_IMAGE_INFO,@object # @"\01L_OBJC_IMAGE_INFO"
    .section    "__DATA, __objc_imageinfo, regular, no_dead_strip","a",@progbits
    .align  4
L_OBJC_IMAGE_INFO:
    .long   0                       # 0x0
    .long   16                      # 0x10
    .size   L_OBJC_IMAGE_INFO, 8


    .section    ".note.GNU-stack","",@progbits

我的问题是:如何做的Objective-C运行库,它必须与 test.o 这样的可执行文件可以成功创建链接,检索方法列表,以创建,例如,一个V表?是否有可能使用 .section伪...,@function .section伪...,@object .section伪...,@progbits 装配指令来获得这些信息,至少在连接时间?

My question is: how does the Objective-C runtime library, which must be linked against test.o so that the executable file can be successfully created, retrieves the methods list in order to create, for example, a vtable? Is it possible to use the .section ..., @function, .section ..., @object or .section ..., @progbits assembly directives to get this information, at least on linking time?

推荐答案

编译器,链接器和运行时一起工作。

The compiler, linker, and runtime work together.

首先,编译器解析源$ C ​​$ C为每个类,并发出指令,如。长 .zero .quad 描述类的实例变量,属性选择器和方法。汇编程序打开这些指令到的原始数据。

First, the compiler parses the source code for each class and emits directives like .long, .zero, and .quad describing the class's instance variables, properties, selectors, and methods. The assembler turns these directives into raw data.

的数据是在运行时能够理解的格式。例如,开始在符号中的数据 OBJC_CLASS _ $ _ MyClass的的布局相匹配的运行时的结构class_t (在<定义href=\"http://opensource.apple.com/source/objc4/objc4-532/runtime/objc-runtime-new.h\"><$c$c>objc-runtime-new.h).在符号数据 l_OBJC_CLASS_RO _ $ _ MyClass的相匹配的布局运行时的结构class_ro_t (虽然大多数字段为0,因为运行时更新它们时,它加载类)。在结构class_ro_t 有类型的 baseMethods 字段 method_list_t * ,这在 l_OBJC_CLASS_RO的情况下_ $ _ MyClass的初始化为 l_OBJC _ $ _ INSTANCE_METHODS_MyClass 。在 l_OBJC _ $ _ INSTANCE_METHODS_MyClass ,你会发现奠定了像一个数据结构method_list_t ,与数组结束结构method_t - 。一个类中的每个方法,在你的榜样,这不是很有趣,因为每个班只有一个方法

The data is in a format that the runtime understands. For example, the data starting at symbol OBJC_CLASS_$_MyClass matches the layout of the runtime's struct class_t (defined in objc-runtime-new.h). The data at symbol l_OBJC_CLASS_RO_$_MyClass matches the layout of the runtime's struct class_ro_t (although most of the fields are 0 because the runtime updates them when it loads the class). The struct class_ro_t has a baseMethods field of type method_list_t *, which in the case of l_OBJC_CLASS_RO_$_MyClass is initialized to l_OBJC_$_INSTANCE_METHODS_MyClass. At l_OBJC_$_INSTANCE_METHODS_MyClass you will find data laid out like a struct method_list_t, which ends with an array of struct method_t - one for each method in the class. In your example, it's not very interesting because each of your classes has only one method.

编译器使用 .section伪指令告诉链接器如何组数据块在一起。例如,所有的结构class_t 的块将在名为节 __ objc_classlist 放在一起。通过这种方式,运行时可以只是仰望评为部分 __ objc_classlist ,然后处理整款为结构class_t 。看看在<一的 GETSECT 宏href=\"http://opensource.apple.com/source/objc4/objc4-532/runtime/objc-file.mm\"><$c$c>objc-file.mm.

The compiler uses the .section directives to tell the linker how to group chunks of that data together. For example, all of the struct class_t chunks will be put together in a section named __objc_classlist. This way, the runtime can just look up the section named __objc_classlist, and then process the entire section as an array of struct class_t. Take a look at the GETSECT macro in objc-file.mm.

链接器安排功能 _objc_init (在<一个href=\"http://opensource.apple.com/source/objc4/objc4-532/runtime/objc-os.mm\"><$c$c>objc-os.mm)运行的非常的在你的过程中,生命周期早期的前 _objc_init 功能注册一些回调的动态加载程序。尤其是,它指示loader调用 map_images (在<一个href=\"http://opensource.apple.com/source/objc4/objc4-532/runtime/objc-runtime-new.mm\"><$c$c>objc-runtime-new.mm),这就要求 map_images_nolock ,最终调用 _read_images _read_images 函数实际上解析编译器发出的数据,这些数据块,并把它们放入数据结构 objc_msgSend 使用实际发送消息的对象。

The linker arranges for the function _objc_init (in objc-os.mm) to run very early in the lifetime of your process, before main. The _objc_init function registers some callbacks with the dynamic loader. In particular, it tells the loader to call map_images (in objc-runtime-new.mm), which calls map_images_nolock, which eventually calls _read_images. The _read_images function actually parses those chunks of data emitted by the compiler and turns them into the data structures that objc_msgSend uses to actually send messages to objects.

您可以下载Mac OS X 10.8的Objective-C运行时源$ C ​​$的存档ç以了解更多信息。此档案还包含源文件的iOS / ARM(甚至是Windows操作系统!),虽然它可能不符合的究竟的到iOS的任何版本。

You can download an archive of the Mac OS X 10.8 Objective-C runtime source code to learn more. This archive also contains source files for iOS/ARM (and even Windows!), although it might not correspond exactly to any version of iOS.

这篇关于如何Objective-C的运行时检索类和方法列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆