LLVM 苹果出品的编译器
编译器组成
前端、优化器、后端 三个部分
编译器前端 :解析源代码
- 词法分析、语法分析,语义分析 (比如a=b-c会被解析成几个操作。这就是词法分析类似的工作)
- 检测代码错误
- 构建抽象语法树 (AST Abstract Syntax Tree)
- 生成中间代码 (IR)
编译器优化器
改善代码优化时间,降低冗余计算(理解为算法优化,合并计算等)
编译器后端 代码生成器
生成机器语言,并优化
iOS编译器LLVM
特点:前端可定制,后端也可定制。通过抽象出IR文件。可满足不同语言
前端输入IR文件,后端输入IR文件。优化器公用
- llvm 前端 (clang)
- LLVM 优化器
- LLVM后端
clang 开发者的主要开发
clang输出不同编译阶段
clang -ccc-print-phases main.m
得到结果如下:
0: input, "main.m", objective-c 输入文件,找到源文件
1: preprocessor, {0}, objective-c-cpp-output 预处理阶段:这个过程包括宏的替换,头文件导入
2: compiler, {1}, ir 编译阶段: 进行词法分析、语法分析、语法检测,最终生成IR
3: backend, {2}, assembler 后端: LLVM会通过一个一个的Pass优化,每个Pass做一些事情,最终生成汇编
4: assembler, {3}, object 生成目标文件 .o文件
5: linker, {4}, image 链接: 链接需要的静态库和动态库。生成可执行文件
6: bind-arch, "x86_64", {5}, image 通过不同架构,生成不同的可执行文件
镜像文件: 可执行文件硬盘拷贝到内存中的文件,即镜像文件
预处理 (preprocessor)
作用 导入头文件 展开宏
clang -E main.m // 预处理命令
clang -E main.m >>main2.m // 预处理+重定向命令
查看main2.m:
编译阶段(compiler)
词法分析
clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m
将代码,拆成一个一个的 Token ,(包括代码字符串,以及文件信息,行数信息)
语法分析
clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
/*依赖指定SDK*/
clang -isysroot /Applications/Xcode.cpp/Content/…/SDKs/iPhoneSimulator12.2.sdk -fmodules -fsyntax-only -Xclang -ast-dump main.m
1.组合token 生成抽象语法树
抽象语法树节点
ImportDecl
TypedefDecl
FuntionDecl 方法节点 (函数范围 )
ParmVarDecl 参数节点
CompoundStmt
ObjcAutoreleasePoolStmt
CallExpr 函数调用
BinaryOperator 运算符
2.检查报错
生成中间代码IR
clang -S -fobjc-arc -emit-llvm main.m // 生成main.ll
//编译优化后的命令,优化后,例如。一些简单的计算,会直接成为结果
clang -Os -S -fobjc-arc -emit-llvm main.m -o main.ll
/*优化级别 O0 O1 O2 O3 Os*/
IR文件语法
@ 全局标识
% 局部标识
alloca 开辟空间
align 内存对齐
i32 32个bit 4字节
store 写入内存
load 读取数据
call 调用函数
ret 返回
iOS编译优化级别
-O0 代码没有优化,编译时间最快
-O1 适度优化,没有显著的降低编译时间
-O2 全面优化,生成高度优化的代码,编译时间最慢
-O3 和-O2一样的全面优化。同时在一个unit里使用更积极的自动内连子程序且尝试进行循环
-Os 优化程序的空间使用,包括代码和数据
BitCode优化
clang -emit-llvm -c main.ll -o main.bc
生成汇编代码(backend, assembler)
.bc 或者.ll代码生成汇编代码命令
clang -S -fobjc-arc main.bc -o main.s
clang -S -fobjc-arc main.ll -o main.s
/*汇编代码也可以优化*/
clang -Os -S -fobjc-arc main.ll -o main.s
/*优化级别 O0 O1 O2 O3 Os*/
生成目标文件(assembler, object)
目标文件: 将汇编代码转换为机器码,输出目标文件(objct file 也称.o文件)
clang -fmodules -c main.s -o main.o
通过nm 命令,查看main.o中的符号
xcrun nm -nm main.o
.o 文件中常用符号信息
(undefined) external _printf // 外部符号(动态库,初始地址0x0 ,在二次链接时,确定函数地址 通常在 (__DATA,__la_symbol_ptr))
(_TEXT,_text) external _main // 内部符号 (存储位置 Mach-O文件Text段指定地址)
undefined 标识当前文件暂时找不到的符号 (通常就是动态库)
external 标识外部可以访问的
生成可执行文件(linker)
将编译产生的.o文件和(.dylib .a)文件。集合动态库和静态库
clang main.o -o main
查看链接后的符号
xcrun nm -nm main