Xcode Run之后发生的事

原文:点击 Run 之后发生了什么?

简单来说,点击 Run 之后 App 进行编译、汇编、链接、代码签名以及启动执行等操作
这里写图片描述

一 编译

编译主要依靠编译器来完成一系列的操作

主要操作有

  • 预处理
  • 词法分析
  • 语法分析
  • 语义分析
  • 生成中间代码
  • 生成目标代码
  • 优化目标代码

OS X 现在使用的编译器是 LLVM (Low Level Virtual Machine),在最初使用的是 GCC作为官方的编译器,但是由于下面的众多限制,apple 使用了自己的一套编译器

  • GCC 原名为GNU C语言编译器,它原本只能处理 C语言,后来扩展了Objective-C、Java等语言,但是对于Objective-C的处理还是存在众多不便
  • GCC 效率低下、性能不强
  • 苹果开发自己的编译器,有利于开展自己的工具链,比如后期做 Swift、lldb 等
llvm 的基本架构

这里写图片描述

1 编译器
  • 编译器前端(clang)
    • 负责产生机器无关的中间代码
  • 编译器后端
    • 负责对中间代码进行优化并转化为目标机器代码

中间代码(IR:intermediate representation)也称为中间表示

  • 通过中间代码为不同的语言针对诸多架构生成代码
    这里写图片描述

2 预处理

  • 处理源文件中以 #开头的预编译命令,比如#include等

3 词法分析

将输入分解为一个个独立的词法符号,也叫单词符号(token)

  • 注释、宏、空格、换行等都不是单词

例子:

// 1 find a zero
float  matchZero(char *s) {

}
//2 返回下列单词流
//大概了解即可,觉得背这些词法符号定义对目前 iOS 开发用处不大
FLOATID(MATCHZERO)、LPAREN、CHARID(S) 、RPAREN  

4 语法分析

  • 将符号化的字符串,转化抽象为能被计算机存储的树形结构(即抽象语法树(AST))
  • 验证语法的正确性
    • 例如:忘记带分号
  • 只能完成语法层面的分析,无法判别整个语句的真正意义
    • 比如类型不匹配就无法检查

5 语义分析

  • 类型检查、以及符号表管理

6 生成中间代码

  • 编译器前端
    • 负责产生机器无关的中间代码

7 目标代码的生成与优化

编译器后端包括

  • 代码生成器
    • 代码生成器将中间代码转换为目标代码
  • 代码优化器
    • 代码优化器主要是进行一些优化,比如删除多余指令,选择合适寻址方式等

二 汇编

  • 目标代码经过汇编器处理,变成机器上可以执行的指令。生成对应的.o文件

三 链接

  • 链接器(这里指的是静态链接器)将多个目标文件合并为一个可执行文件
  • 在 OS X 和 iOS中的可执行文件是 Mach-O

链接又分为静态链接和动态链接

  • 静态链接
    • 在编译链接期间,把目标文件和静态库一起链接形成可执行文件
    • 静态库如果多个程序都用到了一个库,那么每个程序都要将其链接到可执行文件中,非常冗余
    • 不方便升级,必须重新编译

这里写图片描述

  • 动态链接
    • 在运行时,把目标文件和动态库一起链接形成可执行文件
    • 多个程序可以共享同一段代码,不需要在磁盘上存多份拷贝
    • 增加启动时间,影响性能
      • 因为动态链接发生在启动或运行时
    • 方便升级

整个过程如下图

这里写图片描述

四 代码签名

  • 应用构建(build)完成之后会自动调用命令行工具codesign 进行签名,形成一个可以在系统上跑起来的可执行程序
  • 程序一旦签名,就没有办法更改其中的任何东西,包括资源文件,可执行文件等,iOS系统会检查这个签名
  • 我们每次build之后,都会发现工程目录下多了一个.app文件
    • .app目录中,包含一个叫_CodeSignature的子目录 ,它是一个 plist文件
      • 包含了程序的代码签名
        这里写图片描述

五 启动

  • 其实在启动过程中,dyld(动态链接器) 起了很重要的作用,进行动态链接,进行符号和地址的一个绑定

dyld 主要在启动过程中主要做了以下事情:

  • 加载所依赖的dylibs
  • Fix-ups:Rebase修正地址偏移,因为 OS X和 iOS 搞了一个叫 ASLR的东西来做地址偏移(随机化)来避免收到攻击
  • Fix-ups:Binding确定 Non-Lazy Pointer地址,进行符号地址绑定。
  • ObjC runtime初始化:加载所有类
  • Initializers:执行load 方法和_attribute_((constructor))修饰的函数

对于如何减少启动时间,今年的 WWDC 也有详细的阐述,可以在参考链接中找到相关的资料。

总结

编译 - 汇编 - 静态链接 - 签名 - 启动(动态链接等操作)- 跑起来了

这里写图片描述

参考链接

  • 虎书
  • 程序员的自我修养
  • MDCC 2016 - 孙源(Sunnyxx)- clang 概述
  • iDev 2016 - 孙源(Sunnyxx)- 把玩链接器
  • 优化 App 的启动时间
  • WWDC 2016 Session 406

名词解释

  • SPARC

    • 全称为“可扩充处理器架构”(Scalable Processor ARChitecture),是RISC微处理器架构之一
  • MIPS(Million Instructions Per Second):

    • 单字长定点指令平均执行速度 Million Instructions Per Second的缩写,每秒处理的百万级的机器语言指令数。这是衡量CPU速度的一个指标
  • Pentium

    • Pentium(奔腾)是英特尔第五代x86架构的微处理器

猜你喜欢

转载自blog.csdn.net/u010828718/article/details/80492777