2012-08-11 13 views
10

Nếu tôi nhận được tập tin nguồn Objective-C sau:Thời gian chạy Objective-C lấy danh sách các lớp và phương thức như thế nào?

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

và cố gắng tạo ra một file lắp ráp từ nó với clang -fobjc-nonfragile-abi -fnext-runtime -S test.m, tôi lấy mã lắp ráp sau:

.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 

Câu hỏi của tôi là: thư viện runtime Objective-C, mà phải được liên kết với test.o để tệp thực thi có thể được tạo thành công, truy xuất danh sách phương thức để tạo, ví dụ, vtable? Có thể sử dụng chỉ thị lắp ráp .section ..., @function, .section ..., @object hoặc .section ..., @progbits để nhận thông tin này, ít nhất là về thời gian liên kết không?

+0

Tôi phát hiện ra rằng nhãn 'L_OBJC_LABEL_CLASS_ $' (ở cuối tệp lắp ráp) được theo sau bởi danh sách tất cả các địa chỉ lớp được triển khai trong mảng. Điều này có thể hữu ích ... – LuisABOL

Trả lời

20

Trình biên dịch, trình liên kết và thời gian chạy hoạt động cùng nhau.

Đầu tiên, trình biên dịch phân tích mã nguồn cho mỗi lớp và phát ra các chỉ thị như .long, .zero.quad mô tả các biến cá thể, thuộc tính, bộ chọn và phương thức của lớp. Người lắp ráp biến các chỉ thị này thành dữ liệu thô.

Dữ liệu ở định dạng mà thời gian chạy hiểu được. Ví dụ: dữ liệu bắt đầu từ biểu tượng OBJC_CLASS_$_MyClass khớp với bố cục của thời gian chạy struct class_t (được xác định trong objc-runtime-new.h). Dữ liệu ở biểu tượng l_OBJC_CLASS_RO_$_MyClass khớp với bố cục của thời gian chạy struct class_ro_t (mặc dù hầu hết các trường là 0 vì thời gian chạy cập nhật chúng khi tải lớp). struct class_ro_t có trường baseMethods loại method_list_t *, trong trường hợp l_OBJC_CLASS_RO_$_MyClass được khởi tạo thành l_OBJC_$_INSTANCE_METHODS_MyClass. Tại l_OBJC_$_INSTANCE_METHODS_MyClass bạn sẽ tìm thấy dữ liệu được trình bày như một số struct method_list_t, kết thúc bằng một mảng là struct method_t - một cho mỗi phương thức trong lớp. Trong ví dụ của bạn, nó không phải là rất thú vị bởi vì mỗi lớp của bạn chỉ có một phương thức.

Trình biên dịch sử dụng chỉ thị .section để cho trình liên kết biết cách nhóm các khối dữ liệu đó lại với nhau. Ví dụ: tất cả các khối struct class_t sẽ được đặt cùng nhau trong một phần có tên là __objc_classlist. Bằng cách này, thời gian chạy chỉ có thể tra cứu phần có tên __objc_classlist và sau đó xử lý toàn bộ phần dưới dạng mảng struct class_t. Hãy xem macro GETSECT trong objc-file.mm.

Các mối liên kết sắp xếp cho hàm _objc_init (trong objc-os.mm) để chạy rất sớm trong vòng đời của quá trình của bạn, trước khi main. Chức năng _objc_init đăng ký một số cuộc gọi lại bằng trình tải động. Cụ thể, nó yêu cầu trình tải gọi map_images (trong objc-runtime-new.mm), gọi số map_images_nolock, cuối cùng gọi số _read_images. Hàm _read_images thực sự phân tích các khối dữ liệu được trình biên dịch phát ra và biến chúng thành các cấu trúc dữ liệu mà objc_msgSend sử dụng để thực sự gửi các thông điệp tới các đối tượng.

You can download an archive of the Mac OS X 10.8 Objective-C runtime source code để tìm hiểu thêm. Bản lưu trữ này cũng chứa các tệp nguồn cho iOS/ARM (và thậm chí cả Windows!), Mặc dù nó có thể không tương ứng chính xác đối với bất kỳ phiên bản iOS nào.

+1

Rất tốt, người đàn ông! Đó chính là điều tôi muốn biết. Cảm ơn nhiều! – LuisABOL

0

Nó không phải là thời gian chạy biết làm thế nào để đọc chương trình của bạn, nhưng objc front-end dịch cơ sở mã để sử dụng thời gian chạy.

+0

có, bạn nói đúng, nhưng mã lắp ráp ở trên là mã được tạo bởi trình biên dịch để sử dụng thời gian chạy mục tiêu-c (tôi nghĩ). Nó có tham chiếu đến các ký hiệu thuộc về thời gian chạy Objective-C ('objc_msgSend_fixup',' _objc_empty_cache' và '_objc_empty_vtable', ví dụ). Nhưng ví dụ, hàm 'objc_msgSend_fixup' cần phải lấy các phương thức của các lớp và tôi tưởng tượng điều này được thực hiện bằng cách đọc một phần cụ thể của tệp thi hành. Vì vậy, tôi muốn biết phần này là gì và cách thực hiện điều này. – LuisABOL