美文网首页
oc- APP编译过程以及启动过程

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

作者: 雨天多久就 | 来源:发表于2019-08-06 22:31 被阅读0次

    简单介绍 - 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编译过程以及启动过程

          本文链接:https://www.haomeiwen.com/subject/qcegdctx.html