注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

gcc如何实现objc语言字符串到类成员指针的转换  

2016-04-25 21:33:17|  分类: Gcc源代码分析 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、使用的测试代码
tsecer@harry :cat objcname2sel.m 
#include <objc/Object.h>
#include <objc/objc-api.h>
#include <objc/objc-list.h>
#include <stdio.h>

#define IMPFUN(name) \
{\
SEL sel = @selector(name);\
printf("id %ld type %s\n", (long)sel->sel_id, sel->sel_types);\
}

@interface tsecer:Object
-(void) func1;
-(int) func3:(int)arg1 ;
@end

@implementation tsecer:Object
-(void) func1
IMPFUN(func1)
-(int) func3:(int)arg1 
IMPFUN(func3)
@end

@interface harry:Object
-(void) func3:(double)arg1 ;
-(void) func1;
@end

@implementation harry:Object
-(void) func3:(double)arg1 
IMPFUN(func3)
-(void) func1
IMPFUN(func1)
@end

#define CONTAINER_OF(type, mem, ptr) ((type*)((void*)ptr - offsetof(type, mem)))

int main(int argc, char * argv[])
{
id t = [tsecer alloc];
id h = [harry alloc];
[t func1];
[h func1];

SEL tsel = class_get_instance_method(t->class_pointer, @selector(func3:))->method_name;
SEL hsel = class_get_instance_method(h->class_pointer, @selector(func3:))->method_name;

printf("t sel %lx type %s\n", (long)tsel->sel_id, tsel->sel_types);
printf("h sel %lx type %s\n", (long)hsel->sel_id, hsel->sel_types);

}
tsecer@harry :/home/tsecer/Downloads/gccobj4.1/gcc/xgcc objcname2sel.m -S
tsecer@harry :cat -n objcname2sel.s 
     1 .file "objcname2sel.m"
     2 .text
     3 .type list_free, @function
     4 list_free:
     5 .LFB42:
     6 pushq %rbp
     7 .LCFI0:
     8 movq %rsp, %rbp
     9 .LCFI1:
    10 subq $16, %rsp
    11 .LCFI2:
    12 movq %rdi, -8(%rbp)
    13 cmpq $0, -8(%rbp)
    14 je .L4
    15 movq -8(%rbp), %rax
    16 movq 8(%rax), %rdi
    17 call list_free
    18 movq -8(%rbp), %rdi
    19 call objc_free
    20 .L4:
    21 leave
    22 ret
    23 .LFE42:
    24 .size list_free, .-list_free
    25 .section .rodata
    26 .LC0:
    27 .string "id %ld type %s\n"
    28 .text
    29 .type _i_tsecer__func1, @function
    30 _i_tsecer__func1:
    31 .LFB43:
    32 pushq %rbp
    33 .LCFI3:
    34 movq %rsp, %rbp
    35 .LCFI4:
    36 subq $32, %rsp
    37 .LCFI5:
    38 movq %rdi, -24(%rbp)
    39 movq %rsi, -32(%rbp)
    40 movq $_OBJC_SELECTOR_TABLE, -8(%rbp)
    41 movq -8(%rbp), %rax
    42 movq 8(%rax), %rdx
    43 movq -8(%rbp), %rax
    44 movq (%rax), %rax
    45 movq %rax, %rsi
    46 movl $.LC0, %edi
    47 movl $0, %eax
    48 call printf
    49 leave
    50 ret
    51 .LFE43:
    52 .size _i_tsecer__func1, .-_i_tsecer__func1
    53 .type _i_tsecer__func3_, @function
    54 _i_tsecer__func3_:
    55 .LFB44:
    56 pushq %rbp
    57 .LCFI6:
    58 movq %rsp, %rbp
    59 .LCFI7:
    60 subq $48, %rsp
    61 .LCFI8:
    62 movq %rdi, -24(%rbp)
    63 movq %rsi, -32(%rbp)
    64 movl %edx, -36(%rbp)
    65 movl $_OBJC_SELECTOR_TABLE+16, %eax
    66 movq %rax, -8(%rbp)
    67 movq -8(%rbp), %rax
    68 movq 8(%rax), %rdx
    69 movq -8(%rbp), %rax
    70 movq (%rax), %rax
    71 movq %rax, %rsi
    72 movl $.LC0, %edi
    73 movl $0, %eax
    74 call printf
    75 leave
    76 ret
    77 .LFE44:
    78 .size _i_tsecer__func3_, .-_i_tsecer__func3_
    79 .type _i_harry__func3_, @function
    80 _i_harry__func3_:
    81 .LFB45:
    82 pushq %rbp
    83 .LCFI9:
    84 movq %rsp, %rbp
    85 .LCFI10:
    86 subq $48, %rsp
    87 .LCFI11:
    88 movq %rdi, -24(%rbp)
    89 movq %rsi, -32(%rbp)
    90 movsd %xmm0, -40(%rbp)
    91 movl $_OBJC_SELECTOR_TABLE+16, %eax
    92 movq %rax, -8(%rbp)
    93 movq -8(%rbp), %rax
    94 movq 8(%rax), %rdx
    95 movq -8(%rbp), %rax
    96 movq (%rax), %rax
    97 movq %rax, %rsi
    98 movl $.LC0, %edi
    99 movl $0, %eax
   100 call printf
   101 leave
   102 ret
   103 .LFE45:
   104 .size _i_harry__func3_, .-_i_harry__func3_
   105 .type _i_harry__func1, @function
   106 _i_harry__func1:
   107 .LFB46:
   108 pushq %rbp
   109 .LCFI12:
   110 movq %rsp, %rbp
   111 .LCFI13:
   112 subq $32, %rsp
   113 .LCFI14:
   114 movq %rdi, -24(%rbp)
   115 movq %rsi, -32(%rbp)
   116 movq $_OBJC_SELECTOR_TABLE, -8(%rbp)
   117 movq -8(%rbp), %rax
   118 movq 8(%rax), %rdx
   119 movq -8(%rbp), %rax
   120 movq (%rax), %rax
   121 movq %rax, %rsi
   122 movl $.LC0, %edi
   123 movl $0, %eax
   124 call printf
   125 leave
   126 ret
   127 .LFE46:
   128 .size _i_harry__func1, .-_i_harry__func1
   129 .section .rodata
   130 .LC1:
   131 .string "tsecer"
   132 .LC2:
   133 .string "harry"
   134 .LC3:
   135 .string "t sel %lx type %s\n"
   136 .LC4:
   137 .string "h sel %lx type %s\n"
   138 .text
   139 .globl main
   140 .type main, @function
   141 main:
   142 .LFB47:
   143 pushq %rbp
   144 .LCFI15:
   145 movq %rsp, %rbp
   146 .LCFI16:
   147 pushq %rbx
   148 .LCFI17:
   149 subq $56, %rsp
   150 .LCFI18:
   151 movl %edi, -44(%rbp)
   152 movq %rsi, -56(%rbp)
   153 movl $.LC1, %edi
   154 call objc_get_class
   155 movq %rax, %rbx
   156 movl $_OBJC_SELECTOR_TABLE+32, %eax
   157 movq %rax, %rsi
   158 movq %rbx, %rdi
   159 call objc_msg_lookup
   160 movq %rax, %rdx
   161 movl $_OBJC_SELECTOR_TABLE+32, %eax
   162 movq %rax, %rsi
   163 movq %rbx, %rdi
   164 call *%rdx
   165 movq %rax, -40(%rbp)
   166 movl $.LC2, %edi
   167 call objc_get_class
   168 movq %rax, %rbx
   169 movl $_OBJC_SELECTOR_TABLE+32, %eax
   170 movq %rax, %rsi
   171 movq %rbx, %rdi
   172 call objc_msg_lookup
   173 movq %rax, %rdx
   174 movl $_OBJC_SELECTOR_TABLE+32, %eax
   175 movq %rax, %rsi
   176 movq %rbx, %rdi
   177 call *%rdx
   178 movq %rax, -32(%rbp)
   179 movq -40(%rbp), %rbx
   180 movl $_OBJC_SELECTOR_TABLE+48, %eax
   181 movq %rax, %rsi
   182 movq %rbx, %rdi
   183 call objc_msg_lookup
   184 movq %rax, %rdx
   185 movl $_OBJC_SELECTOR_TABLE+48, %eax
   186 movq %rax, %rsi
   187 movq %rbx, %rdi
   188 call *%rdx
   189 movq -32(%rbp), %rbx
   190 movl $_OBJC_SELECTOR_TABLE+48, %eax
   191 movq %rax, %rsi
   192 movq %rbx, %rdi
   193 call objc_msg_lookup
   194 movq %rax, %rdx
   195 movl $_OBJC_SELECTOR_TABLE+48, %eax
   196 movq %rax, %rsi
   197 movq %rbx, %rdi
   198 call *%rdx
   199 movl $_OBJC_SELECTOR_TABLE+64, %eax
   200 movq %rax, %rsi
   201 movq -40(%rbp), %rax
   202 movq (%rax), %rdi
   203 call class_get_instance_method
   204 movq (%rax), %rax
   205 movq %rax, -24(%rbp)
   206 movl $_OBJC_SELECTOR_TABLE+64, %eax
   207 movq %rax, %rsi
   208 movq -32(%rbp), %rax
   209 movq (%rax), %rdi
   210 call class_get_instance_method
   211 movq (%rax), %rax
   212 movq %rax, -16(%rbp)
   213 movq -24(%rbp), %rax
   214 movq 8(%rax), %rdx
   215 movq -24(%rbp), %rax
   216 movq (%rax), %rax
   217 movq %rax, %rsi
   218 movl $.LC3, %edi
   219 movl $0, %eax
   220 call printf
   221 movq -16(%rbp), %rax
   222 movq 8(%rax), %rdx
   223 movq -16(%rbp), %rax
   224 movq (%rax), %rax
   225 movq %rax, %rsi
   226 movl $.LC4, %edi
   227 movl $0, %eax
   228 call printf
   229 addq $56, %rsp
   230 popq %rbx
   231 leave
   232 ret
   233 .LFE47:
   234 .size main, .-main
   235 .data
   236 .align 32
   237 .type _OBJC_SYMBOLS, @object
   238 .size _OBJC_SYMBOLS, 48
   239 _OBJC_SYMBOLS:
   240 .quad 0
   241 .quad _OBJC_SELECTOR_TABLE
   242 .value 2
   243 .value 0
   244 .zero 4
   245 .quad _OBJC_CLASS_harry
   246 .quad _OBJC_CLASS_tsecer
   247 .long 0
   248 .zero 4
   249 .type _OBJC_METH_VAR_NAME_0, @object
   250 .size _OBJC_METH_VAR_NAME_0, 6
   251 _OBJC_METH_VAR_NAME_0:
   252 .string "func1"
   253 .type _OBJC_METH_VAR_TYPE_0, @object
   254 .size _OBJC_METH_VAR_TYPE_0, 8
   255 _OBJC_METH_VAR_TYPE_0:
   256 .string "v16@0:8"
   257 .type _OBJC_METH_VAR_NAME_1, @object
   258 .size _OBJC_METH_VAR_NAME_1, 7
   259 _OBJC_METH_VAR_NAME_1:
   260 .string "func3:"
   261 .type _OBJC_METH_VAR_TYPE_1, @object
   262 .size _OBJC_METH_VAR_TYPE_1, 11
   263 _OBJC_METH_VAR_TYPE_1:
   264 .string "v24@0:8d16"
   265 .align 32
   266 .type _OBJC_INSTANCE_METHODS_harry, @object
   267 .size _OBJC_INSTANCE_METHODS_harry, 64
   268 _OBJC_INSTANCE_METHODS_harry:
   269 .long 0
   270 .zero 4
   271 .long 2
   272 .zero 4
   273 .quad _OBJC_METH_VAR_NAME_0
   274 .quad _OBJC_METH_VAR_TYPE_0
   275 .quad _i_harry__func1
   276 .quad _OBJC_METH_VAR_NAME_1
   277 .quad _OBJC_METH_VAR_TYPE_1
   278 .quad _i_harry__func3_
   279 .type _OBJC_CLASS_NAME_0, @object
   280 .size _OBJC_CLASS_NAME_0, 6
   281 _OBJC_CLASS_NAME_0:
   282 .string "harry"
   283 .type _OBJC_CLASS_NAME_1, @object
   284 .size _OBJC_CLASS_NAME_1, 7
   285 _OBJC_CLASS_NAME_1:
   286 .string "Object"
   287 .align 32
   288 .type _OBJC_METACLASS_harry, @object
   289 .size _OBJC_METACLASS_harry, 104
   290 _OBJC_METACLASS_harry:
   291 .quad _OBJC_CLASS_NAME_1
   292 .quad _OBJC_CLASS_NAME_1
   293 .quad _OBJC_CLASS_NAME_0
   294 .quad 0
   295 .quad 2
   296 .quad 104
   297 .long 0
   298 .zero 4
   299 .long 0
   300 .zero 4
   301 .long 0
   302 .zero 4
   303 .long 0
   304 .zero 4
   305 .long 0
   306 .zero 4
   307 .long 0
   308 .zero 4
   309 .long 0
   310 .zero 4
   311 .align 32
   312 .type _OBJC_CLASS_harry, @object
   313 .size _OBJC_CLASS_harry, 104
   314 _OBJC_CLASS_harry:
   315 .quad _OBJC_METACLASS_harry
   316 .quad _OBJC_CLASS_NAME_1
   317 .quad _OBJC_CLASS_NAME_0
   318 .quad 0
   319 .quad 1
   320 .quad 8
   321 .long 0
   322 .zero 4
   323 .quad _OBJC_INSTANCE_METHODS_harry
   324 .long 0
   325 .zero 4
   326 .long 0
   327 .zero 4
   328 .long 0
   329 .zero 4
   330 .long 0
   331 .zero 4
   332 .long 0
   333 .zero 4
   334 .type _OBJC_METH_VAR_TYPE_2, @object
   335 .size _OBJC_METH_VAR_TYPE_2, 11
   336 _OBJC_METH_VAR_TYPE_2:
   337 .string "i20@0:8i16"
   338 .align 32
   339 .type _OBJC_INSTANCE_METHODS_tsecer, @object
   340 .size _OBJC_INSTANCE_METHODS_tsecer, 64
   341 _OBJC_INSTANCE_METHODS_tsecer:
   342 .long 0
   343 .zero 4
   344 .long 2
   345 .zero 4
   346 .quad _OBJC_METH_VAR_NAME_1
   347 .quad _OBJC_METH_VAR_TYPE_2
   348 .quad _i_tsecer__func3_
   349 .quad _OBJC_METH_VAR_NAME_0
   350 .quad _OBJC_METH_VAR_TYPE_0
   351 .quad _i_tsecer__func1
   352 .type _OBJC_CLASS_NAME_2, @object
   353 .size _OBJC_CLASS_NAME_2, 7
   354 _OBJC_CLASS_NAME_2:
   355 .string "tsecer"
   356 .align 32
   357 .type _OBJC_METACLASS_tsecer, @object
   358 .size _OBJC_METACLASS_tsecer, 104
   359 _OBJC_METACLASS_tsecer:
   360 .quad _OBJC_CLASS_NAME_1
   361 .quad _OBJC_CLASS_NAME_1
   362 .quad _OBJC_CLASS_NAME_2
   363 .quad 0
   364 .quad 2
   365 .quad 104
   366 .long 0
   367 .zero 4
   368 .long 0
   369 .zero 4
   370 .long 0
   371 .zero 4
   372 .long 0
   373 .zero 4
   374 .long 0
   375 .zero 4
   376 .long 0
   377 .zero 4
   378 .long 0
   379 .zero 4
   380 .align 32
   381 .type _OBJC_CLASS_tsecer, @object
   382 .size _OBJC_CLASS_tsecer, 104
   383 _OBJC_CLASS_tsecer:
   384 .quad _OBJC_METACLASS_tsecer
   385 .quad _OBJC_CLASS_NAME_1
   386 .quad _OBJC_CLASS_NAME_2
   387 .quad 0
   388 .quad 1
   389 .quad 8
   390 .long 0
   391 .zero 4
   392 .quad _OBJC_INSTANCE_METHODS_tsecer
   393 .long 0
   394 .zero 4
   395 .long 0
   396 .zero 4
   397 .long 0
   398 .zero 4
   399 .long 0
   400 .zero 4
   401 .long 0
   402 .zero 4
   403 .type _OBJC_METH_VAR_NAME_2, @object
   404 .size _OBJC_METH_VAR_NAME_2, 6
   405 _OBJC_METH_VAR_NAME_2:
   406 .string "func3"
   407 .type _OBJC_METH_VAR_NAME_3, @object
   408 .size _OBJC_METH_VAR_NAME_3, 6
   409 _OBJC_METH_VAR_NAME_3:
   410 .string "alloc"
   411 .type _OBJC_METH_VAR_TYPE_3, @object
   412 .size _OBJC_METH_VAR_TYPE_3, 8
   413 _OBJC_METH_VAR_TYPE_3:
   414 .string "@16@0:8"
   415 .align 32
   416 .type _OBJC_SELECTOR_TABLE, @object
   417 .size _OBJC_SELECTOR_TABLE, 96
   418 _OBJC_SELECTOR_TABLE:
   419 .quad _OBJC_METH_VAR_NAME_0
   420 .long 0
   421 .zero 4
   422 .quad _OBJC_METH_VAR_NAME_2
   423 .long 0
   424 .zero 4
   425 .quad _OBJC_METH_VAR_NAME_3
   426 .quad _OBJC_METH_VAR_TYPE_3
   427 .quad _OBJC_METH_VAR_NAME_0
   428 .quad _OBJC_METH_VAR_TYPE_0
   429 .quad _OBJC_METH_VAR_NAME_1
   430 .long 0
   431 .zero 4
   432 .long 0
   433 .zero 4
   434 .long 0
   435 .zero 4
   436 .type _OBJC_CLASS_NAME_3, @object
   437 .size _OBJC_CLASS_NAME_3, 15
   438 _OBJC_CLASS_NAME_3:
   439 .string "objcname2sel.m"
   440 .align 32
   441 .type _OBJC_MODULES, @object
   442 .size _OBJC_MODULES, 32
   443 _OBJC_MODULES:
   444 .quad 8
   445 .quad 32
   446 .quad _OBJC_CLASS_NAME_3
   447 .quad _OBJC_SYMBOLS
   448 .text
   449 .type __objc_gnu_init, @function
   450 __objc_gnu_init:
   451 .LFB48:
   452 pushq %rbp
   453 .LCFI19:
   454 movq %rsp, %rbp
   455 .LCFI20:
   456 movl $_OBJC_MODULES, %edi
   457 call __objc_exec_class
   458 leave
   459 ret
   460 .LFE48:
   461 .size __objc_gnu_init, .-__objc_gnu_init
   462 .section .ctors,"aw",@progbits
   463 .align 8
   464 .quad __objc_gnu_init
   465 .data
   466 .align 8
   467 .type __objc_class_ref_tsecer, @object
   468 .size __objc_class_ref_tsecer, 8
   469 __objc_class_ref_tsecer:
   470 .quad __objc_class_name_tsecer
   471 .align 8
   472 .type __objc_class_ref_harry, @object
   473 .size __objc_class_ref_harry, 8
   474 __objc_class_ref_harry:
   475 .quad __objc_class_name_harry
   476 .align 8
   477 .type __objc_class_ref_Object, @object
   478 .size __objc_class_ref_Object, 8
   479 __objc_class_ref_Object:
   480 .quad __objc_class_name_Object
   481 .globl __objc_class_name_harry
   482 .section .rodata
   483 .align 8
   484 .type __objc_class_name_harry, @object
   485 .size __objc_class_name_harry, 8
   486 __objc_class_name_harry:
   487 .zero 8
   488 .globl __objc_class_name_tsecer
   489 .align 8
   490 .type __objc_class_name_tsecer, @object
   491 .size __objc_class_name_tsecer, 8
   492 __objc_class_name_tsecer:
   493 .zero 8
   494 .section .eh_frame,"a",@progbits
   495 .Lframe1:
   496 .long .LECIE1-.LSCIE1
   497 .LSCIE1:
   498 .long 0x0
   499 .byte 0x1
   500 .string "zR"
   501 .uleb128 0x1
   502 .sleb128 -8
   503 .byte 0x10
   504 .uleb128 0x1
   505 .byte 0x3
   506 .byte 0xc
   507 .uleb128 0x7
   508 .uleb128 0x8
   509 .byte 0x90
   510 .uleb128 0x1
   511 .align 8
   512 .LECIE1:
   513 .LSFDE1:
   514 .long .LEFDE1-.LASFDE1
   515 .LASFDE1:
   516 .long .LASFDE1-.Lframe1
   517 .long .LFB42
   518 .long .LFE42-.LFB42
   519 .uleb128 0x0
   520 .byte 0x4
   521 .long .LCFI0-.LFB42
   522 .byte 0xe
   523 .uleb128 0x10
   524 .byte 0x86
   525 .uleb128 0x2
   526 .byte 0x4
   527 .long .LCFI1-.LCFI0
   528 .byte 0xd
   529 .uleb128 0x6
   530 .align 8
   531 .LEFDE1:
   532 .LSFDE3:
   533 .long .LEFDE3-.LASFDE3
   534 .LASFDE3:
   535 .long .LASFDE3-.Lframe1
   536 .long .LFB43
   537 .long .LFE43-.LFB43
   538 .uleb128 0x0
   539 .byte 0x4
   540 .long .LCFI3-.LFB43
   541 .byte 0xe
   542 .uleb128 0x10
   543 .byte 0x86
   544 .uleb128 0x2
   545 .byte 0x4
   546 .long .LCFI4-.LCFI3
   547 .byte 0xd
   548 .uleb128 0x6
   549 .align 8
   550 .LEFDE3:
   551 .LSFDE5:
   552 .long .LEFDE5-.LASFDE5
   553 .LASFDE5:
   554 .long .LASFDE5-.Lframe1
   555 .long .LFB44
   556 .long .LFE44-.LFB44
   557 .uleb128 0x0
   558 .byte 0x4
   559 .long .LCFI6-.LFB44
   560 .byte 0xe
   561 .uleb128 0x10
   562 .byte 0x86
   563 .uleb128 0x2
   564 .byte 0x4
   565 .long .LCFI7-.LCFI6
   566 .byte 0xd
   567 .uleb128 0x6
   568 .align 8
   569 .LEFDE5:
   570 .LSFDE7:
   571 .long .LEFDE7-.LASFDE7
   572 .LASFDE7:
   573 .long .LASFDE7-.Lframe1
   574 .long .LFB45
   575 .long .LFE45-.LFB45
   576 .uleb128 0x0
   577 .byte 0x4
   578 .long .LCFI9-.LFB45
   579 .byte 0xe
   580 .uleb128 0x10
   581 .byte 0x86
   582 .uleb128 0x2
   583 .byte 0x4
   584 .long .LCFI10-.LCFI9
   585 .byte 0xd
   586 .uleb128 0x6
   587 .align 8
   588 .LEFDE7:
   589 .LSFDE9:
   590 .long .LEFDE9-.LASFDE9
   591 .LASFDE9:
   592 .long .LASFDE9-.Lframe1
   593 .long .LFB46
   594 .long .LFE46-.LFB46
   595 .uleb128 0x0
   596 .byte 0x4
   597 .long .LCFI12-.LFB46
   598 .byte 0xe
   599 .uleb128 0x10
   600 .byte 0x86
   601 .uleb128 0x2
   602 .byte 0x4
   603 .long .LCFI13-.LCFI12
   604 .byte 0xd
   605 .uleb128 0x6
   606 .align 8
   607 .LEFDE9:
   608 .LSFDE11:
   609 .long .LEFDE11-.LASFDE11
   610 .LASFDE11:
   611 .long .LASFDE11-.Lframe1
   612 .long .LFB47
   613 .long .LFE47-.LFB47
   614 .uleb128 0x0
   615 .byte 0x4
   616 .long .LCFI15-.LFB47
   617 .byte 0xe
   618 .uleb128 0x10
   619 .byte 0x86
   620 .uleb128 0x2
   621 .byte 0x4
   622 .long .LCFI16-.LCFI15
   623 .byte 0xd
   624 .uleb128 0x6
   625 .byte 0x4
   626 .long .LCFI18-.LCFI16
   627 .byte 0x83
   628 .uleb128 0x3
   629 .align 8
   630 .LEFDE11:
   631 .LSFDE13:
   632 .long .LEFDE13-.LASFDE13
   633 .LASFDE13:
   634 .long .LASFDE13-.Lframe1
   635 .long .LFB48
   636 .long .LFE48-.LFB48
   637 .uleb128 0x0
   638 .byte 0x4
   639 .long .LCFI19-.LFB48
   640 .byte 0xe
   641 .uleb128 0x10
   642 .byte 0x86
   643 .uleb128 0x2
   644 .byte 0x4
   645 .long .LCFI20-.LCFI19
   646 .byte 0xd
   647 .uleb128 0x6
   648 .align 8
   649 .LEFDE13:
   650 .ident "GCC: (GNU) 4.1.0"
   651 .section .note.GNU-stack,"",@progbits
tsecer@harry :/home/tsecer/Downloads/gccobj4.1/gcc/xgcc objcname2sel.m -lobjc
tsecer@harry :./a.out 
id 94489280513 type (null)
id 94489280513 type (null)
t sel 1800000001 type i20@0:8i16
h sel 1800000001 type v24@0:8d16
tsecer@harry :
tsecer@harry :
二、查找一个方法的基本数据结构
objc的实现要求通过函数名称找到对应的实现,在这个过程中,最直观的方法就是在调用的时候首先通过字符串来查找一个hash表、并且这个hash表最好为单个类特有;或者是保证一个类的所有方法都按照字符串的字典序排列,然后查找的时候通过二分查找来找到对应的函数指针。至少从objc公开的数据结构来看可能是这么实现的,我们看下objc对于SEL结构的定义:
/*
** Definition of a selector.  Selectors themselves are not unique, but
** the sel_id is a unique identifier.
*/
typedef const struct objc_selector 
{
  void *sel_id;
  const char *sel_types;
} *SEL;
在我们上面看到的汇编代码中,其中SEL结构中的sel_id指向的是函数名称的字符串,而sel_types则是函数声明按照特定规则的编码。可以想像,这种实现方法效率还是比较低的,因为每次函数调用都要进行字符串查找,而这个字符串的查找又避免不了字符串的逐个比较。
以上面的代码为例,main函数中对func1的调用使用的selector结构为;

   180 movl $_OBJC_SELECTOR_TABLE+48, %eax
……
   249 .type _OBJC_METH_VAR_NAME_0, @object
   250 .size _OBJC_METH_VAR_NAME_0, 6
   251 _OBJC_METH_VAR_NAME_0:
   252 .string "func1"
   253 .type _OBJC_METH_VAR_TYPE_0, @object
   254 .size _OBJC_METH_VAR_TYPE_0, 8
   255 _OBJC_METH_VAR_TYPE_0:
   256 .string "v16@0:8"
   257 .type _OBJC_METH_VAR_NAME_1, @object
   258 .size _OBJC_METH_VAR_NAME_1, 7
……
   425 .quad _OBJC_METH_VAR_NAME_3
   426 .quad _OBJC_METH_VAR_TYPE_3
……
   427 .quad _OBJC_METH_VAR_NAME_0
   428 .quad _OBJC_METH_VAR_TYPE_0   
也就是425行对应的就是objc_selector中定义的SEL结构的内容,可以看到,两个指针指向的分别是字符串"func1"和"v16@0:8",关于类型的编码待会再说,这里还是先看关键的sel_id字段。这个字段从这里看是一个字符串,然后编译器将这个objc_selector结构传递给了objc_msg_lookup (id receiver, SEL op)函数来查找实现,这个函数比较简单,在函数的最开始是这么执行的
      result = sarray_get_safe (receiver->class_pointer->dtable, 
(sidx)op->sel_id);
这里很奇怪的是把这个sel_id当作了一个数组下标来操作,并没有我们期望的字符串比较和查找操作。
三、sel_id在什么时候由字符串转换为了下标
我们看下上面的汇编代码,在这个地方有一个不起眼的声明,这个声明将函数__objc_gnu_init的地址放在了.ctors段中,这其实就是gcc/libc的约定,在程序启动的时候,要早于main函数执行位于.ctors节中的函数指针列表。这个特性是gcc的一个扩展,用于实现类似于C++中全局实例构造函数的执行,但是在其它的C语言中也可以使用,使用的扩展是__attribute__((constructor))。不过关于这个功能具体如何实现的,这里就不再继续讨论了,总之,这个汇编指令导致的后果就是__objc_gnu_init函数将会在main函数执行之前执行
   462 .section .ctors,"aw",@progbits
   463 .align 8
   464 .quad __objc_gnu_init
   465 .data                                
其实这个__objc_gnu_init执行的功能非常简单,只是简单的封装了对于__objc_exec_class函数的调用,函数中的代码主要就是为了给函数构造需要的Module结构指针,汇编代码显示为
   450 __objc_gnu_init:
   451 .LFB48:
   452 pushq %rbp
   453 .LCFI19:
   454 movq %rsp, %rbp
   455 .LCFI20:
   456 movl $_OBJC_MODULES, %edi
   457 call __objc_exec_class
   458 leave
   459 ret
结构定义为gcc-4.1.0\libobjc\objc\objc-api.h中下面定义,由于汇编代码和这个原始数据结构的对应非常直观,这里也就不废话了。
/*
** The compiler generates one of these structures for each module that
** composes the executable (eg main.m).  
** 
** This data structure is the root of the definition tree for the module.  
** 
** A collect program runs between ld stages and creates a ObjC ctor array. 
** That array holds a pointer to each module structure of the executable. 
*/
typedef struct objc_module {
  unsigned long version;                        /* Compiler revision. */
  unsigned long size;                           /* sizeof(Module). */
  const char* name;                             /* Name of the file where the 
                                                  module was generated.   The 
                                                  name includes the path. */

  Symtab_t    symtab;                           /* Pointer to the Symtab of
                                                  the module.  The Symtab
                                                  holds an array of 
 pointers to 
                                                  the classes and categories 
                                                  defined in the module. */
} Module, *Module_t;
四、__objc_exec_class的相关功能
这个Module主要是Symtab_t结构,这个结构又主要分为三部分,一个是这个类中所有定义的接口的objc_selector结构;另一个是模块中定义的所有类的声明,最后是这个模块中定义的所有的扩展类的方法声明,这里也只关心这里第一个部分,也就是objc_selector列表的信息。
   416 .type _OBJC_SELECTOR_TABLE, @object
   417 .size _OBJC_SELECTOR_TABLE, 96
   418 _OBJC_SELECTOR_TABLE:
   419 .quad _OBJC_METH_VAR_NAME_0 //"func1"
   420 .long 0
   421 .zero 4
   422 .quad _OBJC_METH_VAR_NAME_2 //"func3"
   423 .long 0
   424 .zero 4
   425 .quad _OBJC_METH_VAR_NAME_3 //alloc
   426 .quad _OBJC_METH_VAR_TYPE_3 //"@16@0:8"
   427 .quad _OBJC_METH_VAR_NAME_0 //"func1"
   428 .quad _OBJC_METH_VAR_TYPE_0 //"v16@0:8"
   429 .quad _OBJC_METH_VAR_NAME_1 //"func3:"
   430 .long 0
虽然类的名称不同,但是在
id t = [tsecer alloc];
id h = [harry alloc];
[t func1];
[h func1];
这些代码的时候,由于两个函数类中定义的alloc和func1函数的字符串名称和类型都是相同的,所以两处调用使用的是相同的selector
   425 .quad _OBJC_METH_VAR_NAME_3 //alloc
   426 .quad _OBJC_METH_VAR_TYPE_3 //"@16@0:8"
   427 .quad _OBJC_METH_VAR_NAME_0 //"func1"
   428 .quad _OBJC_METH_VAR_TYPE_0 //"v16@0:8"
在__objc_exec_class函数中,关键代码如下
 /* Constructors are constant static data so we can safely store
    pointers to them in the runtime structures. is_const == YES */
 __sel_register_typed_name (name, type, 
    (struct objc_selector *) &(selectors[i]),
    YES);
在函数__sel_register_typed_name中                                     
  i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
  if (soffset_decode (i) != 0)
    {
      for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
  l; l = l->tail)
{
           ……   
    if (orig)
{
 orig->sel_id = (void *) i;
 return orig;
}
                ……
         }
……
    l = list_cons ((void *) j, l);
    sarray_at_put_safe (__objc_selector_names, i, (void *) new_name);
    sarray_at_put_safe (__objc_selector_array, i, (void *) l);
    if (is_new)
      objc_hash_add (&__objc_selector_hash, (void *) new_name, (void *) i);
在上面的循环体外,只是通过selector中的名字作为键值,从__objc_selector_hash找到下标i,然后将传入的 orig结构中的sel_id修改为数值i,这里要注意的一个事实是虽然在 __sel_register_typed_name函数中考虑了objc_selector中的sel_types类型,但是这个并不影响对于orig中sel_id的初始化,它始终初始化的是相同的i值,至于这个type信息只是作为原始的selector的以部分,放入了__objc_selector_array引导的objc_list链表中,这一点乍一看有点困惑(至少我最开始是想当然的一位type不同会导致sel_id不同),其实结合objc的另一个限制:同一个类中不允许有名称相同的方法,即使这些方法的参数如何不同,例如下面代码:
tsecer@harry :cat -n objcnameclash.m 
     1 @interface tsecer
     2 -(void) harry:(int)arg1;
     3 -(void) harry:(double)arg1;
     4 @end
tsecer@harry :/home/tsecer/Downloads/gccobj4.1/gcc/xgcc objcnameclash.m 
objcnameclash.m:3: error: duplicate declaration of method ‘-harry:’
tsecer@harry :
这也就是说,在main函数启动之前,所有本模块定义的方法和调用的外部方法的selector中的sel_id都已经被替换成了数值类型的下标。进而根据__sel_register_typed_name代码的实现可以知道,所有的字符串名称相同的方法都具有相同的sel_id数值,这一点从最开始的代码中可以看到,虽然func3在两个类中定义的顺序不同,但是它们使用的sle_id是相同的:
t sel 1800000001 type i20@0:8i16
h sel 1800000001 type v24@0:8d16
回过头来再看objc_msg_lookup (id receiver, SEL op)--->>__objc_init_install_dtable--->>__objc_install_dispatch_table_for_class--->>__objc_install_methods_in_dtable
      sarray_at_put_safe (class->dtable,
 (sidx) method->method_name->sel_id,
 method->method_imp);
这个地方就可以放心的把method->method_name->sel_id作为数组下标来使用了。每个不同的类在__objc_install_dispatch_table_for_class
  if (super == 0)
    {
      objc_mutex_lock (__objc_runtime_mutex);
      class->dtable = sarray_new (__objc_selector_max_index, 0);
      objc_mutex_unlock (__objc_runtime_mutex);
    }
  else
    class->dtable = sarray_lazy_copy (super->dtable);
中分配类自己的一份跳转表,这意味着:相同的sel_id对于不同类来说,它们有不同的IMP值,这也可以认为是objc中多态的实现方式,从这里也可以看出,每个类的跳转表大小理论上说是可执行文件中所有不同selector(也就是不同的字符串名称)的数量,这可能也是objc内部使用sarray(sparse array)的原因吧,毕竟一个类的跳转表和所有类的跳转表比起来还是太稀疏了。
五、如何通过字符串来获得一个类的函数实现
由于所有类的同名接口都有相同的下标,所以只要找到一个SEL就可以找到任意一个类中该接口的实现:
tsecer@harry :cat -n objccallbyname.m 
     1 #include <objc/Object.h>
     2 #include <objc/objc-api.h>
     3 #include <objc/objc-list.h>
     4 #include <stdio.h>
     5
     6 #define IMPFUN(name) \
     7 {\
     8 SEL sel = @selector(name);\
     9 printf("id %ld type %s\n", (long)sel->sel_id, sel->sel_types);\
    10 }
    11
    12 @interface tsecer:Object
    13 -(void) func1;
    14 -(int) func3:(int)arg1 ;
    15 @end
    16
    17 @implementation tsecer:Object
    18 -(void) func1
    19 IMPFUN(func1)
    20 -(int) func3:(int)arg1 
    21 IMPFUN(func3)
    22 @end
    23
    24 @interface harry:Object
    25 -(void) func3:(double)arg1 ;
    26 -(void) func1;
    27 @end
    28
    29 @implementation harry:Object
    30 -(void) func3:(double)arg1 
    31 IMPFUN(func3)
    32 -(void) func1
    33 IMPFUN(func1)
    34 @end
    35
    36 #define CONTAINER_OF(type, mem, ptr) ((type*)((void*)ptr - offsetof(type, mem)))
    37
    38 int main(int argc, char * argv[])
    39 {
    40 [[tsecer alloc] perform: sel_get_any_uid(argv[1])];
    41 }
tsecer@harry :/home/tsecer/Downloads/gccobj4.1/gcc/xgcc objccallbyname.m -lobjc
tsecer@harry :./a.out func3:
id 98784247809 type (null)
tsecer@harry :
六、sel_types的编码规则
gcc-4.1.0\gcc\objc\objc-act.c
static tree
encode_method_prototype (tree method_decl)
{
……
  /* ONEWAY and BYCOPY, for remote object are the only method qualifiers.  */
  encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (method_decl)));

  /* Encode return type.  */
  encode_type (objc_method_parm_type (method_decl),
      obstack_object_size (&util_obstack),
      OBJC_ENCODE_INLINE_DEFS);
……
  sprintf (buf, "%d@0:%d", parm_offset, i);
  ……
  sprintf (buf, "%d@0:%d", parm_offset, i);
  obstack_grow (&util_obstack, buf, strlen (buf));

  /* Argument types.  */
  parm_offset = 2 * i;
  for (parms = METHOD_SEL_ARGS (method_decl); parms;
       parms = TREE_CHAIN (parms))
    {
      tree type = objc_method_parm_type (parms);

      /* Process argument qualifiers for user supplied arguments.  */
      encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (parms)));

      /* Type.  */
      encode_type (type, obstack_object_size (&util_obstack),
  OBJC_ENCODE_INLINE_DEFS);

      /* Compute offset.  */
      sprintf (buf, "%d", parm_offset);
      parm_offset += objc_encoded_type_size (type);

      obstack_grow (&util_obstack, buf, strlen (buf));
    }
/* FORMAT will be OBJC_ENCODE_INLINE_DEFS or OBJC_ENCODE_DONT_INLINE_DEFS.  */
static void
encode_type (tree type, int curtype, int format)
{
  enum tree_code code = TREE_CODE (type);
  char c;

  if (TYPE_READONLY (type))
    obstack_1grow (&util_obstack, 'r');

  if (code == INTEGER_TYPE)
    {
      switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
{
case 8:  c = TYPE_UNSIGNED (type) ? 'C' : 'c'; break;
case 16: c = TYPE_UNSIGNED (type) ? 'S' : 's'; break;
case 32: 
 if (type == long_unsigned_type_node
     || type == long_integer_type_node)
        c = TYPE_UNSIGNED (type) ? 'L' : 'l';
 else
        c = TYPE_UNSIGNED (type) ? 'I' : 'i';
 break;
case 64: c = TYPE_UNSIGNED (type) ? 'Q' : 'q'; break;
default: abort ();
}
      obstack_1grow (&util_obstack, c);
    }

  else if (code == REAL_TYPE)
    {
      /* Floating point types.  */
      switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
{
case 32:  c = 'f'; break;
case 64:
case 96:
case 128: c = 'd'; break;
default: abort ();
}
      obstack_1grow (&util_obstack, c);
    }

  else if (code == VOID_TYPE)
    obstack_1grow (&util_obstack, 'v');

  else if (code == BOOLEAN_TYPE)
    obstack_1grow (&util_obstack, 'B');

  else if (code == ARRAY_TYPE)
    encode_array (type, curtype, format);

  else if (code == POINTER_TYPE)
    encode_pointer (type, curtype, format);

  else if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE)
    encode_aggregate (type, curtype, format);

  else if (code == FUNCTION_TYPE) /* '?' */
    obstack_1grow (&util_obstack, '?');
}        

七、类/实例 方法的编码规则
gcc-4.1.0\gcc\objc\objc-act.c
/* This is the default way of generating a method name.  */
/* I am not sure it is really correct.
   Perhaps there's a danger that it will make name conflicts
   if method names contain underscores. -- rms.  */
#ifndef OBJC_GEN_METHOD_LABEL
#define OBJC_GEN_METHOD_LABEL(BUF, IS_INST, CLASS_NAME, CAT_NAME, SEL_NAME, NUM) \
  do {    \
    char *temp;    \
    sprintf ((BUF), "_%s_%s_%s_%s",    \
    ((IS_INST) ? "i" : "c"),    \
    (CLASS_NAME),    \
    ((CAT_NAME)? (CAT_NAME) : ""), \
    (SEL_NAME));    \
    for (temp = (BUF); *temp; temp++)    \
      if (*temp == ':') *temp = '_';    \
  } while (0)
#endif

例如前面的harry类的func1方法,这里没有使用category,所以func1前为空,
   275 .quad _i_harry__func1
我们定义一个category看下
tsecer@harry :cat  objccategory.m
#include <objc/Object.h>
#include <objc/objc-api.h>
#include <objc/objc-list.h>
#include <stdio.h>

#define IMPFUN(name) \
{\
SEL sel = @selector(name);\
printf("id %ld type %s\n", (long)sel->sel_id, sel->sel_types);\
}

@interface tsecer:Object
-(void) func1;
@end

@implementation tsecer:Object
-(void) func1
IMPFUN(func1)
@end

@interface tsecer(harry)
-(void) func3:(double)arg1 ;
@end

@implementation tsecer(harry)
-(void) func3:(double)arg1 
IMPFUN(func3)
@end

tsecer@harry :/home/tsecer/Downloads/gccobj4.1/gcc/xgcc objccategory.m -S
tsecer@harry :cat objccategory.s | grep harry
.type _i_tsecer_harry_func3_, @function
_i_tsecer_harry_func3_:
.size _i_tsecer_harry_func3_, .-_i_tsecer_harry_func3_
八、类的组织方法
1、类的所有实现必须定义在同一个源文件中
tsecer@harry :cat tsecer.h 
@interface tsecer:Object
-(void) func1;
-(int) func3:(int)arg1 ;
@end

tsecer@harry :cat objcsep1.m 
#include <objc/Object.h>
#include <objc/objc-api.h>
#include <objc/objc-list.h>
#include <stdio.h>
#include "tsecer.h"

#define IMPFUN(name) \
{\
SEL sel = @selector(name);\
printf("id %ld type %s\n", (long)sel->sel_id, sel->sel_types);\
}
@implementation tsecer:Object
-(void) func1
IMPFUN(func1)
@end

int main(int argc, char * argv[])
{

}
tsecer@harry :cat objcsep3.m 
#include <objc/Object.h>
#include <objc/objc-api.h>
#include <objc/objc-list.h>
#include <stdio.h>
#include "tsecer.h"

#define IMPFUN(name) \
{\
SEL sel = @selector(name);\
printf("id %ld type %s\n", (long)sel->sel_id, sel->sel_types);\
}
@implementation tsecer:Object
-(int) func3:(int)arg1 
IMPFUN(func3)
@end
tsecer@harry :/home/tsecer/Downloads/gccobj4.1/gcc/xgcc objcsep1.m objcsep3.m -lobjc
objcsep1.m:15: warning: incomplete implementation of class ‘tsecer’
objcsep1.m:15: warning: method definition for ‘-func3:’ not found
objcsep3.m:15: warning: incomplete implementation of class ‘tsecer’
objcsep3.m:15: warning: method definition for ‘-func1’ not found
/tmp/ccYF4qfQ.o:(.rodata+0x10): multiple definition of `__objc_class_name_tsecer'
/tmp/cc2jc5yK.o:(.rodata+0x10): first defined here
collect2: ld returned 1 exit status
tsecer@harry :
2、如何保证外部引用的符号在链接是一定存在
在上面的分析中可以看到一个现象,在大部分情况下通过字符串来完成对类/实例/方法的调用,其实很多时候跳过了对于类定义的引用需求,那么如何保证(或者说检测到)这个外部引用的类一定存在呢?
tsecer@harry :cat objcsep1.m 
#include <objc/Object.h>
#include <objc/objc-api.h>
#include <objc/objc-list.h>
#include <stdio.h>
#include "tsecer.h"

int main(int argc, char * argv[])
{
[[tsecer alloc] func1];
}
tsecer@harry :cat tsecer.h 
@interface tsecer:Object
-(void) func1;
@end

tsecer@harry :/home/tsecer/Downloads/gccobj4.1/gcc/xgcc objcsep1.m -lobjc
/tmp/ccg9l4Mm.o:(.data+0xa0): undefined reference to `__objc_class_name_tsecer'
collect2: ld returned 1 exit status
tsecer@harry :
在生成的汇编代码中
        .data
        .align 8
        .type   __objc_class_ref_tsecer, @object
        .size   __objc_class_ref_tsecer, 8
__objc_class_ref_tsecer:
        .quad   __objc_class_name_tsecer
对于__objc_class_ref_tsecer的引用只有一份,并且这个__objc_class_ref_tsecer在这个汇编代码中从来没有被使用到过,所以也就是说,编译器为了保证引用的外部类在链接时一定有定义,所以定义了一个没有被使用到的变量__objc_class_ref_tsecer,并要求连接器将它复制为类__objc_class_name_tsecer的定义,这样如果在链接的时候找不到这个类的定义,就会导致上面的连接器报错。
九、内置变量的使用
gcc-4.1.0\gcc\objc\objc-act.c
static void
synth_module_prologue (void)
{
……
  /* Pre-build the following entities - for speed/convenience.  */
  self_id = get_identifier ("self");
  ucmd_id = get_identifier ("_cmd");


/* Synthesize the formal parameters 'id self' and 'SEL _cmd' needed for ObjC
   method definitions.  In the case of instance methods, we can be more
   specific as to the type of 'self'.  */

static void
synth_self_and_ucmd_args (void)
{
  tree self_type;

  if (objc_method_context
      && TREE_CODE (objc_method_context) == INSTANCE_METHOD_DECL)
    self_type = objc_instance_type;
  else
    /* Really a `struct objc_class *'. However, we allow people to
       assign to self, which changes its type midstream.  */
    self_type = objc_object_type;

  /* id self; */
  objc_push_parm (build_decl (PARM_DECL, self_id, self_type));

  /* SEL _cmd; */
  objc_push_parm (build_decl (PARM_DECL, ucmd_id, objc_selector_type));
}

gcc-4.1.0\gcc\objc\objc-act.c
/* Transform an Objective-C method definition into a static C function
   definition, synthesizing the first two arguments, "self" and "_cmd",
   in the process.  */

c_parser_postfix_expression--->>>>objc_build_message_expr--->>>>objc_finish_message_expr--->>>>build_objc_method_call
  if (flag_next_runtime)
    {
      /* If we are returning a struct in memory, and the address
of that memory location is passed as a hidden first
argument, then change which messenger entry point this
expr will call.  NB: Note that sender_cast remains
unchanged (it already has a struct return type).  */
      if (!targetm.calls.struct_value_rtx (0, 0)
 && (TREE_CODE (ret_type) == RECORD_TYPE
     || TREE_CODE (ret_type) == UNION_TYPE)
 && targetm.calls.return_in_memory (ret_type, 0))
sender = (super_flag ? umsg_super_stret_decl :
flag_nil_receivers ? umsg_stret_decl : umsg_nonnil_stret_decl);

      method_params = tree_cons (NULL_TREE, lookup_object,
tree_cons (NULL_TREE, selector,
   method_params));
      method = build_fold_addr_expr (sender);
    }
  else
    {
      /* This is the portable (GNU) way.  */
      tree object;

      /* First, call the lookup function to get a pointer to the method,
then cast the pointer, then call it with the method arguments.  */
      
      object = (super_flag ? self_decl : lookup_object);

      t = tree_cons (NULL_TREE, selector, NULL_TREE);
      t = tree_cons (NULL_TREE, lookup_object, t);
      method = build_function_call (sender, t);//调用objc_msg_lookup函数

      /* Pass the object to the method.  */
      method_params = tree_cons (NULL_TREE, object,
tree_cons (NULL_TREE, selector,
   method_params));
    }
这“解释”了为什么汇编代码中调用一个方法,调用objc_msg_lookup和真正调用方法都需要传递实例指针和selector的原因,例如函数开始的方法调用,159行调用的是objc_msg_lookup,接下来的164行调用的时候再次刷新了selector,也就是在类方法中可以通过“_cmd”标识符获得selector的引用
   154 call objc_get_class
   155 movq %rax, %rbx
   156 movl $_OBJC_SELECTOR_TABLE+32, %eax
   157 movq %rax, %rsi
   158 movq %rbx, %rdi
   159 call objc_msg_lookup
   160 movq %rax, %rdx
   161 movl $_OBJC_SELECTOR_TABLE+32, %eax
   162 movq %rax, %rsi
   163 movq %rbx, %rdi
   164 call *%rdx
  评论这张
 
阅读(102)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017