selector

LLVM编译器架构

2021-04-14  本文已影响0人  conowen

编译过程

传统编译过程一般分为以下步骤。

源代码(source code)→ 预处理器(preprocessor)→ 编译器(compiler)→ 汇编程序(assembler)→ 目标代码(object code)→ 链接器(linker)→ 可执行文件(executables)

其中预处理主要工作是宏定义的替换和头文件的引入

编译器

简单而言,编译器的设计一般分为三部分

传统编译器(compiler)的设计一般如下图所示


image.png

LLVM编译器设计如图所示

image.png

LLVM

底层虚拟机(Low Level Virtual Machine),LLVM是一套编译器基础设施项目,以C++写成,包含一系列模块化的编译器组件和工具链,用来开发编译器前端和后端。优化各种语言写的程序在编译过程中环节,如编译时期、链接时期、运行时期以及闲置时期。

LLVM前端

Clang是LLVM编译器工具集的前端(front-end),属于LLVM项目中的一个子项目,它是基于LLVM架构图的轻量级编译器,Clang的现在已经取代GCC,负责C、C++、OC语言的编译。Clang主要工作是输出代码对应的抽象语法树(Abstract Syntax Tree, AST),并将代码编译成LLVM Bitcode。接着在后端(back-end)使用LLVM编译成平台相关的机器语言。

LLVM中间端

LLVM的核心是中间端表达式(Intermediate Representation,IR),一种类似汇编的底层语言。

LLVM后端

LLVM后端的主要工作是将LLVM中间端表达式(IR)转换成特定目标机器代码(object code),机器代码一般由机器代码或接近于机器语言的代码组成。即存放目标代码的计算机文件,它常被称作二进制文件(binaries)。目前LLVM支持输出多种后端指令集,包括X86、PowerPC、ARM以及SPARC等。目标文件包含着机器代码(可直接被CPU执行)以及代码在运行时使用的数据,如重定位信息,如用于链接或调试的程序符号(变量和函数的名字),此外还包括其他调试信息。目标文件是从源代码文件产生程序文件这一过程的中间产物。

LLVM链接器

LLD是LLVM项目中的链接器,替换GNU系统链接器。LLD把目标文件(.o文件和 .dyld .a)链接在一起来生成可执行文件或库文件(mach-o文件)。

Mach-O文件格式

Mach-O 是 iOS 可执行文件的格式,典型的 Mach-O 是主二进制和动态库。Mach-O 可以分为三部分:

image.png

Header 的最开始是 Magic Number,表示这是一个 Mach-O 文件,除此之外还包含一些 Flags,这些 flags 会影响 Mach-O 的解析。

Load Commands 存储 Mach-O 的布局信息,比如 Segment command 和 Data 中的 Segment/Section 是一一对应的。除了布局信息之外,还包含了依赖的动态库等启动 App 需要的信息。

Data 部分包含了实际的代码和数据,Data 被分割成很多个 Segment,每个 Segment 又被划分成很多个 Section,分别存放不同类型的数据。

标准的三个 Segment 是 TEXT,DATA,LINKEDIT,也支持自定义:

iTunes Connect 会对上传 Mach-O 的 TEXT 段进行加密,防止 IPA 下载下来就直接可以看到代码。这也就是为什么逆向里会有个概念叫做“砸壳”,砸的就是这一层 TEXT 段加密。iOS 13 对这个过程进行了优化,在博文中的page fault过程中,需要读取Page In 的时候不需要解密了。

参考文章
http://www.aosabook.org/en/llvm.html
抖音品质建设 - iOS启动优化《原理篇》

上一篇 下一篇

猜你喜欢

热点阅读