2012-08-11 17 views
10

Si me sale el siguiente archivo de origen de Objective-C:¿Cómo recupera el tiempo de ejecución de Objective-C la lista de clases y métodos?

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

y tratar de generar un archivo de ensamblaje de ella con clang -fobjc-nonfragile-abi -fnext-runtime -S test.m, me sale el siguiente código de montaje:

.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 

mi pregunta es: ¿Cómo funciona la biblioteca de tiempo de ejecución de Objective-C, que debe vincularse con test.o para que el archivo ejecutable se pueda crear con éxito, recupera la lista de métodos para crear, por ejemplo, un vtable? ¿Es posible utilizar las directivas de ensamblado .section ..., @function, .section ..., @object o .section ..., @progbits para obtener esta información, al menos en el tiempo de enlace?

+0

Descubrí que la etiqueta 'L_OBJC_LABEL_CLASS_ $' (al final del archivo de ensamblaje) va seguida de una lista de todas las direcciones de clase implementadas en la matriz. Esto puede ser útil ... – LuisABOL

Respuesta

20

El compilador, el enlazador y el tiempo de ejecución funcionan en conjunto.

En primer lugar, el compilador analiza el código fuente para cada clase y emite directivas como .long, .zero, y .quad describen instancia variables, propiedades, selectores, y métodos de la clase. El ensamblador convierte estas directivas en datos brutos.

Los datos están en un formato que entiende el tiempo de ejecución. Por ejemplo, los datos que comienzan en el símbolo OBJC_CLASS_$_MyClass coinciden con el diseño de struct class_t del motor de ejecución (definido en objc-runtime-new.h). Los datos en el símbolo l_OBJC_CLASS_RO_$_MyClass coinciden con el diseño del tiempo de ejecución struct class_ro_t (aunque la mayoría de los campos son 0 porque el tiempo de ejecución los actualiza cuando carga la clase). El struct class_ro_t tiene un campo baseMethods de tipo method_list_t *, que en el caso de l_OBJC_CLASS_RO_$_MyClass se inicializa en l_OBJC_$_INSTANCE_METHODS_MyClass. En l_OBJC_$_INSTANCE_METHODS_MyClass encontrará datos dispuestos como struct method_list_t, que finaliza con una matriz de struct method_t, uno para cada método de la clase. En su ejemplo, no es muy interesante porque cada una de sus clases tiene solo un método.

El compilador usa las directivas .section para indicar al vinculador cómo agrupar los fragmentos de esa información. Por ejemplo, todos los fragmentos struct class_t se juntarán en una sección llamada __objc_classlist. De esta forma, el tiempo de ejecución solo puede buscar la sección llamada __objc_classlist, y luego procesar toda la sección como una matriz de struct class_t. Eche un vistazo a la macro GETSECT en objc-file.mm.

El enlazador se encarga de la función _objc_init (en objc-os.mm) para ejecutar muy temprano en la vida de su proceso, antes de main. La función _objc_init registra algunas devoluciones de llamada con el cargador dinámico. En particular, le dice al cargador que llame al map_images (en objc-runtime-new.mm), que llama al map_images_nolock, que finalmente llama al _read_images. La función _read_images realmente analiza los fragmentos de datos emitidos por el compilador y los convierte en las estructuras de datos que objc_msgSend usa para enviar mensajes a los objetos.

You can download an archive of the Mac OS X 10.8 Objective-C runtime source code para obtener más información. Este archivo también contiene archivos fuente para iOS/ARM (e incluso Windows!), Aunque puede no corresponder exactamente a cualquier versión de iOS.

+1

¡Muy bien, amigo! Eso es exactamente lo que quería saber. ¡Muchas gracias! – LuisABOL

0

No es que el runtime sepa cómo leer su programa, sino que el front-end de objc traduce la base de código para usar el tiempo de ejecución.

+0

sí, tienes razón, pero el código de ensamblado anterior es el generado por el compilador para usar el tiempo de ejecución de object-c (creo). Tiene referencias a símbolos que pertenecen al tiempo de ejecución de Objective-C ('objc_msgSend_fixup',' _objc_empty_cache' y '_objc_empty_vtable', por ejemplo). Pero la función 'objc_msgSend_fixup', por ejemplo, necesita obtener los métodos de las clases e imagino que esto se hace leyendo una sección específica del archivo ejecutable. Entonces, quiero saber qué sección es esta y cómo se hace esto. – LuisABOL

Cuestiones relacionadas