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],执行完成后退出
NSThread的main方法内部做了什么?的更多相关文章
- Java:关于main方法的10道面试题
感觉假期过得好快,东西也丢得快. 假期吃喝玩乐之余也来温故一下Java知识,下面给大家整理了10道Java main方法的经典面试题,都来挑战一下自己的Java基础知识吧! 1.main方法是做什么用 ...
- main方法执行之前,做什么事
1.我们知道程序的入口是main方法,那么在执行main方法之前,需要做些什么准备工作呢? 2.main方法执行之前,必须要把non-local static对象构造完成.static对象有:全局对象 ...
- 类(静态)变量和类(静态)static方法以及main方法、代码块,final方法的使用,单例设计模式
类的加载:时间 1.创建对象实例(new 一个新对象时) 2.创建子类对象实例,父类也会被加载 3.使用类的静态成员时(静态属性,静态方法) 一.static 静态变量:类变量,静态属性(会被该类的所 ...
- 不包含适合于入口点的静态"Main"方法
学习新建项目.此问题做为笔记. 错误 1 程序“admin.exe”不包含适合于入口点的静态“Main”方法 原因:原来创建项目的时候,用的是“空项目”,我以为这样就会生成类库,实际上,一开始准备运行 ...
- 07 java main方法
1.问题:Java main方法为什么是 public static void main(String[] args)??? 序号 场景 编译 运行 解释 1 public修改为private pr ...
- Java中的static关键字解析(转自海子)__为什么main方法必须是static的,因为程序在执行main方法的时候没有创建任何对象,因此只有通过类名来访问。
Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键 ...
- [Java] JVM 在执行 main 方法前的行为
JVM 执行一个 Java 程序时,先从某个指定的 Java 类的 main 方法开始执行代码,同时,传一个字符串数组作为 main 方法的参数.例如在 Unix 系统上,执行下面的命令 java T ...
- 【细说Java】揭开Java的main方法神秘的面纱
大家都知道,main方法是Java应用程序的入口,其定义格式为: public static void main(String[] args) 可是为什么要这么定义呢?不这样定义可以么?main方法可 ...
- 【细说Java】揭开Java的main方法神秘的面纱(转)
大家都知道,main方法是Java应用程序的入口,其定义格式为: public static void main(String[] args) 可是为什么要这么定义呢?不这样定义可以么?main方法可 ...
- public static void main(String[] args){} 关于Java main()方法
是Java程序的入口方法,JVM在运行程序时,会首先查找main()方法. public是权限修饰符,表明任何类或对象都可以访问这个方法: static表明main()方法是一个静态方法,即方法中的代 ...
随机推荐
- KingbaseES Collate排序规则对结果集的影响
背景 前端在客户现场遇到一个问题,模糊查询报错:error:invalid multibyte charactor for locale pg the server LC_TYPE locale is ...
- 【已解决】Exception in thread "main" java.lang.RuntimeException: java.net.ConnectException
没有启动hadoop集群
- 冲刺 NOIP2024 之动态规划专题
专题链接 B - Birds \(3.19\) . 混合背包 \(DP\) . 定义 \(f_{i,j}\) 表示取到鸟巢 \(i\) ,获得 \(j\) 只小鸟时所剩的魔力值. 显然有 \(f_{0 ...
- Supervisor 安装与使用
一.Supervisor 介绍 Supervisor 是一个用 Python 编写的进程管理工具,它可以用于监控和控制类 UNIX 操作系统上的多个进程.它是一个客户端/服务器系统,其中 Superv ...
- #树状数组,线段树,离散#JZOJ 3854 分组
题目 Bsny所在的精灵社区有\(n\)个居民,每个居民有一定的地位和年龄,\(r_i\)表示第\(i\)个人的地位,\(a_i\)表示第\(i\)个人的年龄. 最近社区里要举行活动,要求几个人分成一 ...
- 网络组件axios可以在OpenHarmony上使用了
什么是axios 上古浏览器页面在向服务器请求数据时,因为返回的是整个页面的数据,页面都会强制刷新一下,这对于用户来讲并不是很友好.并且我们只是需要修改页面的部分数据,但是从服务器端发送的却是整个页面 ...
- js复制文字到剪切板
此方法仅适用于 IE demo <!DOCTYPE html> <html lang="en"> <head> <meta charset ...
- pySpark-merge多个dataframe
当需要merge多个spark datafame的时候: from functools import reduce buff = [] for pdfs in [pdf1, pdf1,pdf3...] ...
- jenkins 持续集成和交付——maven小栗子(四)
前言 因为前面一节中介绍了自由风格模式,这里介绍一个专门为maven打造的模式,没错就是使用插件.这里写这个只是为了说明,如果我们构建一些不是那么复杂的项目,那么可以去使用一些插件,这样可以更加方便, ...
- Android开发 Error:The number of method references in a .dex file cannot exceed 64K.Android开发 Error:The number of method references in a .dex file cannot exceed 64K
前言 错误起因: 在Android系统中,一个App的所有代码都在一个Dex文件里面. Dex是一个类似Jar的存储了多有Java编译字节码的归档文件. 因为Android系统使用Dalvik虚拟机, ...