11

次の Objective-C ソース ファイルを取得した場合:

// 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;
}

を使用してアセンブリ ファイルを生成しようとするとclang -fobjc-nonfragile-abi -fnext-runtime -S test.m、次のアセンブリ コードが得られます。

    .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

私の質問はtest.o、実行可能ファイルを正常に作成できるようにリンクする必要がある Objective-C ランタイム ライブラリが、vtable などを作成するためにどのようにメソッド リストを取得するのかということです。.section ..., @function.section ..., @objectまたはアセンブリ ディレクティブを使用して、.section ..., @progbits少なくともリンク時にこの情報を取得することは可能ですか?

4

2 に答える 2

22

コンパイラ、リンカー、およびランタイムは連携して動作します。

まず、コンパイラは各クラスのソース コードを解析し、クラスのインスタンス変数、プロパティ、セレクター、およびメソッドを記述する.long.zero、および などのディレクティブを発行します。.quadアセンブラは、これらのディレクティブを生データに変換します。

データは、ランタイムが理解できる形式です。たとえば、symbol で始まるデータOBJC_CLASS_$_MyClassは、ランタイムのレイアウトstruct class_t(で定義objc-runtime-new.h) と一致します。シンボルのデータl_OBJC_CLASS_RO_$_MyClassは、ランタイムのレイアウトと一致しますstruct class_ro_t(ただし、ほとんどのフィールドは 0 です。これは、ランタイムがクラスをロードするときにそれらを更新するためです)。struct class_ro_tには type のフィールドbaseMethodsmethod_list_t *あり、 の場合l_OBJC_CLASS_RO_$_MyClassは に初期化されl_OBJC_$_INSTANCE_METHODS_MyClassます。l_OBJC_$_INSTANCE_METHODS_MyClassのようにレイアウトされたデータがあり、クラスのメソッドごとに -struct method_list_tの配列で終わります。struct method_tあなたの例では、各クラスにメソッドが 1 つしかないため、あまり興味深いものではありません。

コンパイラは.sectionディレクティブを使用して、そのデータのチャンクをグループ化する方法をリンカに指示します。たとえば、すべてのstruct class_tチャンクは という名前のセクションにまとめられ__objc_classlistます。このように、ランタイムは という名前のセクションを検索するだけで、セクション__objc_classlist全体を の配列として処理できますstruct class_tGETSECTのマクロを見てくださいobjc-file.mm

リンカは、関数_objc_init(in objc-os.mm) がプロセスの有効期間の非常に早い段階で実行されるように調整しますmain。この_objc_init関数は、いくつかのコールバックをダイナミック ローダーに登録します。特に、ローダーにmap_images(in objc-runtime-new.mm) を呼び出すように指示し、これが を呼び出しmap_images_nolock、最終的に を呼び出します_read_images。この_read_images関数は、コンパイラによって出力されたデータのチャンクを実際に解析し、objc_msgSend実際にオブジェクトにメッセージを送信するために使用するデータ構造に変換します。

詳細については、Mac OS X 10.8 Objective-C ランタイム ソース コードのアーカイブをダウンロードしてください。このアーカイブには、iOS/ARM (さらには Windows!) のソース ファイルも含まれていますが、iOSのどのバージョンにも正確に対応していない可能性があります。

于 2012-08-11T19:39:36.190 に答える
0

ランタイムがプログラムの読み取り方法を認識しているわけではありませんが、objc フロントエンドがコード ベースを変換してランタイムを使用するようになっています。

于 2012-08-11T18:11:05.640 に答える