2012-08-11 55 views
10

如果我得到以下的Objective-C源文件: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 "[email protected]: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鏈接以便可以成功創建可執行文件,如何檢索方法列表以創建例如vtable?是否可以使用.section ..., @function.section ..., @object.section ..., @progbits組裝指令來獲取此信息,至少在鏈接時間上?

+0

我發現'L_OBJC_LABEL_CLASS_ $'標籤(在程序集文件的末尾)後面跟着一個所有實現的類地址列表。這可能是有用的...... – LuisABOL 2012-08-11 19:22:21

回答

20

編譯器,鏈接器和運行時一起工作。

首先,編譯器解析每個類的源代碼,併發出描述類的實例變量,屬性,選擇器和方法的指令,如.long.zero.quad。彙編程序將這些指令轉換爲原始數據。

數據採用運行時可以理解的格式。例如,從符號OBJC_CLASS_$_MyClass開始的數據與運行時的struct class_t(在objc-runtime-new.h中定義)的佈局相匹配。符號爲l_OBJC_CLASS_RO_$_MyClass的數據與運行時的struct class_ro_t的佈局相匹配(儘管大多數字段爲0,因爲運行時會在加載類時更新它們)。 struct class_ro_t具有類型method_list_t *baseMethods字段,其​​在l_OBJC_CLASS_RO_$_MyClass的情況下被初始化爲l_OBJC_$_INSTANCE_METHODS_MyClass。在l_OBJC_$_INSTANCE_METHODS_MyClass,你會發現數據排列如struct method_list_t,以struct method_t的數組結尾 - 每個類的一個方法。在你的例子中,它不是很有趣,因爲你的每個類只有一個方法。

編譯器使用.section指令告訴鏈接器如何將數據的塊組合在一起。例如,所有的struct class_t塊都將放在一個名爲__objc_classlist的部分。這樣,運行時可以查找名爲__objc_classlist的部分,然後將整個部分處理爲struct class_t的數組。看看objc-file.mm中的GETSECT宏。

鏈接器安排功能_objc_init(在objc-os.mm)運行在過程的生命週期很早,main之前。 _objc_init函數用動態加載器註冊一些回調函數。特別是,它告訴裝載程序調用map_images(在objc-runtime-new.mm),該程序調用map_images_nolock,最終調用_read_images_read_images函數實際上解析了編譯器發出的那些數據塊,並將它們轉換爲objc_msgSend用於實際發送消息到對象的數據結構。

You can download an archive of the Mac OS X 10.8 Objective-C runtime source code瞭解更多信息。該存檔還包含iOS/ARM(甚至Windows!)的源文件,但它可能不對應到任何版本的iOS。

+1

非常好,男人!這正是我想知道的。非常感謝你! – LuisABOL 2012-08-11 20:03:43

0

並不是說運行時知道如何讀取程序,而是objc前端將代碼庫轉換爲使用運行時。

+0

是的,你是對的,但上面的彙編代碼是由編譯器生成的使用Objective-C運行時(我認爲)的彙編代碼。它引用了屬於Objective-C運行時的符號(例如,「objc_msgSend_fixup」,「_objc_empty_cache」和「_objc_empty_vtable」)。但是'objc_msgSend_fixup'函數需要獲取這些類的方法,我想這是通過讀取可執行文件的特定部分來完成的。所以,我想知道這是什麼部分,以及這是如何完成的。 – LuisABOL 2012-08-11 19:03:55

相關問題