oc- APP编译过程以及启动过程

简单介绍 - LLVM编译器

苹果使用的是LLVM编译器,LLVM架构设计的非常好,主要分为前端,中间,后端

  • Frontend 前端 主要是将编程代码进行预处理、词法分析、语法分析、语义分析,然后生成对应的中间代码(这个时候的产物已经与机器没有关系了,可以理解为任何机器都通用的)

  • Optimizer 中间 主要是将前端的输出进行优化

  • Backend 后端 主要是针对不同的机器生成对应的指令代码

llvm入门篇

编译过程:

1.预处理

主要处理文件中以#开头的预编译命令 比如宏定义替换,引入的头文件进行内容替换

2.词法分析

将代码分解成一个一个独立的词法符合(Token)

3.语法分析

将词法分析的结果生成对应的抽象语法树,并验证语法的正确性

4.语义分析

对整个语句进行判别是否有问题

5.生成中间代码

编译器前端的产物,生成与机器无关的中间代码。

  • Class/Meta Class/Protocol/Category 内存结构生成,并放在指定的section中。

  • Method/Ivar/Property内存结构生成

  • 组成method_list/iva_list/property_list并填入Class

  • 为每个ivar合成偏移量

  • 将语法树中的ObjCMessageExpr翻译成相应版本的objc_msgSend等等

  • 根据修饰符strong、weak、copy、atomic合成@property自动实现的setter/getter

  • 生成block_layout的数据结构

  • block数据结构捕获相应的变量

  • 分析对象引用关系,将objc_storeStrong/objc_storeWeak等ARC代码插入

  • 自动实现调用【super dealloc】

  • 为每个拥有ivar的class合成.cxx_destructor方法来自动释放类的成员变量

  • Bitcode 生成字节码

6.目标代码生成与优化

Optimizer对前端产物进行优化,再交给后端根据不同的机器指令集生成对应的机器代码,生成对应的Mach-O文件

7.对Mach-O,静态文件等进行link,生成可执行文件,写入对应的.app包里
8.拷贝项目中的资源文件到对应的.app包里
9.编译xib和storyboard
10.link xib和storyboard的产物
11.如果有自定义的脚本,执行脚本(Build Phase 里的Run Script 可以设置自定义的脚本)
12.处理info.plist文件(具体处理什么,不太清楚)
13.生成DSYM文件
14.如果有混编swift,就会将swift的标准库拷贝到对应的.app包里(所以混编oc和swift会增大包体积)
15.代码签名

出于安全考虑,为了防止代码被篡改,最后的可执行文件会被codeSign进行签名。app运行的时候会去校验签名

Mach-O简单介绍

Mach-O 是一种用户记录可执行文件、对象代码、共享库、动态加载代码和内存转储的文件格式。

Mach-O文件类型分为:

  • 应用的主要二进制

  • dylib动态链接库

  • 静态链接库

  • Bundle 不能被链接的Dylib,只能在运行时使用dlopen( )加载,可当做macOS的插件

  • 可重定向文件类型

主要包含三个主要区域:

  • Header: 文件类型, 目标架构

  • Load command: 描述文件在虚拟内存中的逻辑与布局

  • Raw segment date: 原始数据

    • _TEXT 代码段 (方法名,类名,方法签名……)

    • _DATA 读取和写入数据的段 (全局变量,程序中的类的列表,自己实现+load方法的类,被引用的类列表,协议列表等等)

    • _LINKEDIT 动态连接器需要使用的信息

[图片上传失败...(image-9cc8ea-1581587495399)]

点击APP图标启动过程

内核先加载主程序
Load dylibs

dyld(动态链接器)启动,然后dyld开始递归加载所有的动态库(通过ImageLoader去加载)。

动态库有哪些好处?

  • 代码共用 很多程序都动态链接了这些lib,但是内存和磁盘上仅有一份

  • 易于维护 可以随时进行更新替换

  • 减少了程序的可执行文件体积(运行时候才被加载)

Rebase

因为动态库是被加载到随机地址上的,所以要对所有库内部进行地址指针修正

Bind

修改库对外的指针

Objc Runtime

bind操作结束后,会读取二进制文件的DATA段,找到与objc相关的信息,注册objc类,确保selector的唯一性,读取protocol以及category的信息

Initializers初始化

调用objc类的+load函数

调用c++中带有constructor标记的函数

执行main函数

你可能感兴趣的:(oc- APP编译过程以及启动过程)