• 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],执行完成后退出

  • 相关阅读:
    poj 1860 Currency Exchange(最短路径的应用)
    poj 2965 The Pilots Brothers' refrigerator
    zoj 1827 the game of 31 (有限制的博弈论)
    poj 3295 Tautology (构造法)
    poj 1753 Flip Game(枚举)
    poj 2109 (贪心)
    poj 1328(贪心)
    Qt 对单个控件美化
    Qt 4基础
    Bash Shell
  • 原文地址:https://www.cnblogs.com/chaoguo1234/p/13283990.html
Copyright © 2020-2023  润新知