LLVM编译流程等相关知识整理

Overview

整理这篇博客主要是了解iOS编译的过程,了解其相关知识,丰富自己的知识体系。

在写这篇博客之前查看了李明杰在腾讯课堂的关于LLVM的付费课程,《LLVM编译器实战教程》相关书籍,还有网络上一些博客,在此向他们致敬!

LLVM

什么是LLVM

LLVM项目是模块化、可重用的编译器以及工具链技术的集合。

LLVM跟传统的静态编译器一样使用了经典三段式的结构设计,如下图所示,分别为前端、优化器和后端。

传统编译器架构

传统编译器架构

  • Frontend(编译器前端):进行词法分析、语法分析、语义分析、生成中间代码(IR)
  • Optimizer(优化器):中间代码优化。
  • Backend(后端):生成机器码

LLVM编译器如这篇文章的头图所示。这样做的优点如下:

  • 如果需要支持一种新的编程语言,只需要实现一种新的编译器前端即可。
  • 如果需要支持一种新的硬件设备,只需要实现一个新的后端即可。
  • 优化阶段是一个通用的阶段,它针对的是统一的LLVM IR,不论是支持新的编程语言,还是支持新的硬件设备,都不需要对优化阶段进行修改。

什么是Clang

ClangLLVM项目的一个子项目,是基于LLVM架构的C/C++/Objective-C编译器前端

Clang常用指令

Clang工具可以再Xcode中查看,具体路径为:

1
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang

可以再终端输入Clang -help查看所有指令。

常用的指令如下所示:

  • 生成可执行文件:clang main.o -o main
  • 查看编译过程:clang -ccc-print-phases main.m
  • 查看预处理结果:clang -E main.m
  • 语法分析,生成Token:clang -fmodules -E -Xclang -dump-tokens main.m
  • 生成语法树(AST):clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
  • LLVM中间表示层(LLVM IR):clang -S -fobjc-arc -emit-llvm main.m -o main.ll
  • 生成汇编:clang -S -fobjc-arc main.m -o main.s
  • 生成目标文件:clang -fmodules -c main.m -o main.o

swiftc常用指令

swiftc工具可以在Xcode中查看,具体路径为:

1
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc

可以在终端输入swiftc -help 查看相关指令。

常用的指令如下所示:

  • 生成可执行文件:swiftc -o main.out main.swift
  • 生成抽象语法树(AST):swiftc main.swift -dump-ast
  • 生成中间语言(SIL):swiftc main.swift -emit-sil
  • LLVM中间表示层(LLVM IR):swiftc main.swift -emit -ir
  • 生成汇编:swiftc main.swift -emit-assembly

App编译过程

  1. 编译信息写入辅助文件,创建文件架构 .app 文件
  2. 处理文件打包信息
  3. 执行 CocoaPod 编译前脚本,checkPods Manifest.lock
  4. 编译.m文件,使用 CompileC 和 clang 命令
  5. 链接需要的 Framework
  6. 编译 xib
  7. 拷贝 xib ,资源文件
  8. 编译 ImageAssets
  9. 处理 info.plist
  10. 执行 CocoaPod 脚本
  11. 拷贝标准库
  12. 创建 .app 文件和签名

Swift语言编译过程

Swift编译前端使用的是swiftc,其中Swift前端会多出SIL optimizer,它会将*.swift生成的中间代码*.sil设置成High-Level IR

因为swift在编译时就完成了方法绑定直接通过地址调用,属于强类型语言。方法调用也不像OC那样进行消息转发,这样编译就可以获得更多的信息用在后端的优化上。

Swift编译过程

关于LinkMap

Link Map File其实就是链接的映射文件,它是在Xcode生成可执行文件的同时生成的链接信息文件,用于描述可执行文件的构造部分,包含了代码段和数据段的分布情况。

Object files

这个部分的内容都是 .m 文件编译后的 .o 和需要 link 的 .a 文件。前面是文件编号,后面是文件路径。

Sections

这里描述的是每个 Section在可执行文件中的位置和大小。每个 Section 的 Segment 的类型分为__TEXT代码段和 __DATA 数据段两种。

Symbols

Symbols是对Sections进行了再划分。这里会描述所有的methodsivar和字符串,及它们对应的地址,大小,文件编号信息。

关于符号表dSYM

符号表是内存地址与函数名、文件名、行号的映射表。符号表的元素如下所示:

<起始地址><结束地址><函数>[<文件名:行号>]

一般打包完成后会保存符号表文件,后期可以通过堆栈进行解析和还原,来定位用户APP发生Crash的代码位置。

可以参考Bugly相关文档

参考资料