zoukankan      html  css  js  c++  java
  • NSThread的main方法内部做了什么?

    NSThread当调用start方法的时候,start方法就会调用main方法。那么这个main方法内部做了什么呢?下面是汇编码:

     1 ;Foundation`-[NSThread main]:
     2 ->  0x7fff2594fa69 <+0>:  push   rbp
     3     0x7fff2594fa6a <+1>:  mov    rbp, rsp
     4     0x7fff2594fa6d <+4>:  mov    rax, qword ptr [rdi + 0x8]
     5     0x7fff2594fa71 <+8>:  mov    rsi, qword ptr [rax + 0x20]
     6     0x7fff2594fa75 <+12>: test   rsi, rsi
     7     0x7fff2594fa78 <+15>: je     0x7fff2594fa8e            ; <+37>
     8     0x7fff2594fa7a <+17>: mov    rdi, qword ptr [rax + 0x18]
     9     0x7fff2594fa7e <+21>: test   rdi, rdi
    10     0x7fff2594fa81 <+24>: je     0x7fff2594fa8e            ; <+37>
    11     0x7fff2594fa83 <+26>: mov    rdx, qword ptr [rax + 0x28]
    12     0x7fff2594fa87 <+30>: pop    rbp
    13     0x7fff2594fa88 <+31>: jmp    qword ptr [rip + 0x5b02d3c2] ; (void *)0x00007fff50ba4400: objc_msgSend
    14     0x7fff2594fa8e <+37>: pop    rbp
    15     0x7fff2594fa8f <+38>: ret  

    因为rdi寄存器存放的就是self,我们可以知道第4行的汇编其实就是从当前NSThread对象偏移8字节,将此处地址指向的值传给rax寄存器,其实就是获取NSThread对象内部的一个实例变量值。那么NSThread对象内部偏移8字节的地方是什么实例变量呢?我们使用下面的方法获取NSThread对象内部的实例变量:

    1 (lldb) po [0x600002bbe600 _ivarDescription]
    2 <NSThread: 0x600002bbe600>:
    3 in NSThread:
    4     _private (id): <_NSThreadData: 0x600000fe0a00>
    5     _bytes (unsigned char[44]): Value not representable, [44C]
    6 in NSObject:
    7     isa (Class): NSThread (isa, 0x7fff87b504c8)

    从上面的输出可以看到,NSThread对象内部的实例变量就3个,偏移8字节就是偏移了一个isa指针的长度,那么此时的实例变量就是上面输出第4行的_NSThreadData对象,也就是说rax寄存器此时是_NSThreadData对象的地址。

    继续看main的汇编码第5行,该行汇编码将_NSThreadData对象偏移32字节处的实例变量值赋给了rsi寄存器。同样,我们查看_NSThreadData对象偏移32字节是什么实例变量:

     1 po [0x600000fe0a00 _ivarDescription]
     2 <_NSThreadData: 0x600000fe0a00>:
     3 in _NSThreadData:
     4     dict (id): <__NSDictionaryM: 0x600003edaa80>
     5     name (id): @"com.apple.uikit.eventfetch-thread"
     6     target (id): <UIEventFetcher: 0x6000001fc000>
     7     selector (SEL): threadMain
     8     argument (id): nil
     9     seqNum (int): 2
    10     qstate (unsigned char): Value not representable, C
    11     qos (char): 33
    12     cancel (unsigned char): Value not representable, C
    13     status (unsigned char): Value not representable, C
    14     performQ (id): nil
    15     performD (NSMutableDictionary*): nil
    16     attr (struct _opaque_pthread_attr_t): {
    17         __sig (long): 1414022209
    18         __opaque (char[56]): Value not representable, [56c]
    19     }
    20     tid (struct _opaque_pthread_t*): 0x600000fe0a88 -> 0x700004e45000
    21     pri (double): 0.5
    22     defpri (double): 0.5
    23 in NSObject:
    24     isa (Class): _NSThreadData (isa, 0x7fff87b504a0)

    通过上面的输出,我们发现偏移32字节处是selector实例变量(计算偏移时不要忘了isa指针),也就是说现在rsi寄存器里面是selector的值。

    main函数汇编第6行检测selector是否为空,为空就跳转专<+37>处,也就是汇编码第14行,此时main函数清除栈之后就会退出。如果selector有值,那么就会将_NSThreadData对象偏移24字节处的实例变量传给rdi寄存器(第8行)。对照上面的输出,就会发现rdi寄存器的值应该是target实例变量值。第9行汇编码会检测target是否为空,为空函数也会直接退出。如果不为空,就会将_NSThreadData对象偏移40字节处的实例变量传给rdx寄存器,此时rdx寄存器存储的是argument实例变量的值。有了target,有了selector,有了argument,汇编码第13行就调用objc_msgSend这个方法,调用[target selector:argument],执行完成后,main函数退出。

    总结:

    1 如果创建NSThread时不指定target或者selector,那么main函数就会直接推出;

    2 如果都指定了,main函数会调用[target selector:argument],执行完成后退出

  • 相关阅读:
    eclipse提速01
    eclipse提速02
    快速清空Access资料库中所有表的数据
    删除数据之后自增长列重新开始计数
    JS中控制两个小数位
    JS控制table中tr位置互换
    MIME 类型列表
    JS中对于email格式的判断
    获取网站根目录的方法
    通过存储过程创建SQL作业
  • 原文地址:https://www.cnblogs.com/chaoguo1234/p/13283990.html
Copyright © 2011-2022 走看看