iOS底层探索-LLVM编译流程

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

我们都知道iOS的编译器是LLVM,本篇我们就探索llvm的编译流程。

解释型语言和编译型语言区别

解释型语言

解释型语言的特征是:它的执行机制是使用一个解释器来执行,解释器对程序一句一句翻译机器语言来一句一句执行。例如:shellpython等。

比如我们执行一段pythion代码:

///hello.py
print("hello python")
复制代码

我们执行上面的代码只需要: python hello.py

编译型语言

编译型语言的特征是:它的执行机制使用编译器来编译成机器语言,然后就可以直接执行编译后的可执行文件。例如:cjava等。

比如我们执行一段c代码:

///hello.c
#include<stdio.h>
void main(int argc,const char* argv[]){
  printf("hello c");
  return 0;
}
复制代码

我们首先要对上面的文件进行编译:

clang hello.c
复制代码

执行clang指令后,会生成一个.out的可执行文件,然后执行可执行文件就可以打印出hello c

传统编译器的设计

编译器是由三部分构成的编译器前端优化器编译器后端

传统编译流程.png

编译器前端

编译器前端主要做词法分析,语法分析,语义分析,检查源代码是否存在错误,构建抽象语法树(Abstract Syntax Tree,AST),最后前端会生成中间代码(intermediate representation,IR)。

优化器

优化器主要负责中间代码的优化。改善代码运行时间,例如消除冗余的计算。

编译器后端

编译器后端主要是将中间代码转换成机器码(二进制),并且进行机器相关的代码优化。

llvm架构编译器的设计

Objective C/C/C++使用的编译器前端是Clang,Swift的前端是Swift,后端是LLVM。示例图如下:

LLVM编译器.png

编译流程

我们使用main.m文件进行测试查看各阶段编译的结果

#include <stdio.h>
#define CUSTOM_HEIGHT 3
int testAdd(int a,int b){
    return a+b+CUSTOM_HEIGHT;
}
int main(int argc, char * argv[]) {
    return testAdd(1, 2);
}
复制代码

通过命令我们可以打印源码的编译阶段

clang -ccc-print-phases main.m
复制代码
0: input, "main.m", objective-c
1: preprocessor, {0}, objective-c-cpp-output 
2: compiler, {1}, ir
3: backend, {2}, assembler
4: assembler, {3}, object
5: linker, {4}, image
6: bind-arch, "arm64", {5}, image
复制代码

其中含义为:

0:输入文件:找到源文件。

1:预处理阶段:处理包括宏的替换,头文件的导入。

2:编译阶段:进行词法分析、语法分析、检查语法是否正确,最终生成IR.

3:后端:LLVM会通过一个一个的Pass去优化,每个Pass做一些事情,最终生成汇编代码。

4:生成目标文件。

5:链接:链接需要的动态库和静态库,生成可执行文件。

6:通过不同的架构,生成对应的可执行文件。

预处理阶段

执行下面命令

clang -E main.m
复制代码

执行完成后会看到头文件的导入和宏的替换。

编译阶段

词法分析

预处理完成后会进行词法分析。代码会被切成一个个Token,比如大小括号、等于号、字符串等。

clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m
复制代码

词法分析.png

语法分析

词法分析后就是语法分析,它的任务是验证语法是否正确。再次发分析的基础上将单词序列组合成各类语法短语,如"程序","语句","表达式"等,然后将所有节点组成抽象语法树(AST),语法分析阶段程序判断源程序在结构上是否正确。

 clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
复制代码

语义分析.png

生成中间代码IR(intermediate representation)

完成上面的步骤后就开始生成中间代码IR了,代码生成器(Code Gemeration)会将语法树自定向下便利逐步翻译成LLVM IR。通过下面命令,查看IR代码

clang -S -fobjc-arc -emit-llvm main.m
复制代码

Objective C代码这一步会进行runtime的桥接,property合成,ARC处理等。 这一步会生成main.ll文件,内容如下:

; ModuleID = 'main.m'
source_filename = "main.m"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "arm64-apple-macosx11.0.0"
​
; Function Attrs: noinline nounwind optnone ssp uwtable
define i32 @testAdd(i32 %0, i32 %1) #0 {
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  store i32 %0, i32* %3, align 4
  store i32 %1, i32* %4, align 4
  %5 = load i32, i32* %3, align 4
  %6 = load i32, i32* %4, align 4
  %7 = add nsw i32 %5, %6
  %8 = add nsw i32 %7, 3
  ret i32 %8
}
​
; Function Attrs: noinline nounwind optnone ssp uwtable
define i32 @main(i32 %0, i8** %1) #0 {
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  %5 = alloca i8**, align 8
  store i32 0, i32* %3, align 4
  store i32 %0, i32* %4, align 4
  store i8** %1, i8*** %5, align 8
  %6 = call i32 @testAdd(i32 1, i32 2)
  ret i32 %6
}
attributes #0 = { noinline nounwind optnone ssp uwtable "disable-tail-calls"="false" "frame-pointer"="non-leaf" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "probe-stack"="__chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.5a,+zcm,+zcz" "unsafe-fp-math"="false" "use-soft-float"="false" }
​
!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11}
!llvm.ident = !{!12}
​
!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 11, i32 3]}
!1 = !{i32 1, !"Objective-C Version", i32 2}
!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
!6 = !{i32 1, !"wchar_size", i32 4}
!7 = !{i32 1, !"branch-target-enforcement", i32 0}
!8 = !{i32 1, !"sign-return-address", i32 0}
!9 = !{i32 1, !"sign-return-address-all", i32 0}
!10 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!11 = !{i32 7, !"PIC Level", i32 2}
!12 = !{!"Apple clang version 13.0.0 (clang-1300.0.29.3)"}
复制代码

IR的基本语法

@全局标识

%局部标识

alloca开辟空间

align内存对齐

i32 32bit,4字节

store 写入内存

load 读取数据

call 调用函数

ret 返回

IR的优化

LLVM的优化分别是-O0 -O1 -O2 -O3 -Os

clang -Os -S -fobjc-arc -emit-llvm main.m -o main.ll
复制代码

可以看到优化后的代码:

; ModuleID = 'main.m'
source_filename = "main.m"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "arm64-apple-macosx11.0.0"
​
; Function Attrs: norecurse nounwind optsize readnone ssp uwtable willreturn
define i32 @testAdd(i32 %0, i32 %1) local_unnamed_addr #0 {
  %3 = add i32 %0, 3
  %4 = add i32 %3, %1
  ret i32 %4
}
​
; Function Attrs: norecurse nounwind optsize readnone ssp uwtable willreturn
define i32 @main(i32 %0, i8** nocapture readnone %1) local_unnamed_addr #0 {
  ret i32 6
}
​
attributes #0 = { norecurse nounwind optsize readnone ssp uwtable willreturn "disable-tail-calls"="false" "frame-pointer"="non-leaf" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "probe-stack"="__chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.5a,+zcm,+zcz" "unsafe-fp-math"="false" "use-soft-float"="false" }
​
!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11}
!llvm.ident = !{!12}
​
!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 11, i32 3]}
!1 = !{i32 1, !"Objective-C Version", i32 2}
!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
!6 = !{i32 1, !"wchar_size", i32 4}
!7 = !{i32 1, !"branch-target-enforcement", i32 0}
!8 = !{i32 1, !"sign-return-address", i32 0}
!9 = !{i32 1, !"sign-return-address-all", i32 0}
!10 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
!11 = !{i32 7, !"PIC Level", i32 2}
!12 = !{!"Apple clang version 13.0.0 (clang-1300.0.29.3)"}
复制代码

bitCode(非必须)

生成.bc的中间代码。

clang -emit-llvm -c main.ll -o main.bc
复制代码
dec0 170b 0000 0000 1400 0000 0c0b 0000
ffff ffff 4243 c0de 3514 0000 0700 0000
620c 3024 9596 a6a5 f7d7 7f7d d3b4 4ffb
76ef df3f 2d44 0132 0500 0000 210c 0000
7c02 0000 0b02 2100 0200 0000 1600 0000
0781 2391 41c8 0449 0610 3239 9201 840c
2505 0819 1e04 8b62 8010 4502 4292 0b42
8410 3214 3808 184b 0a32 4288 4870 c421
2344 1287 8c10 4192 0264 c808 b114 2043
4688 20c9 0132 4284 182a 282a 9031 7cb0
5c91 20c4 c800 0000 8920 0000 0e00 0000
3222 0809 2064 8504 1322 a484 0413 22e3
84a1 9014 124c 888c 0b84 844c 1034 7304
6050 0600 a098 2340 6888 ca00 5064 0301
2900 0423 0054 0000 5118 0000 b200 0000
1bde 27f8 ffff ffff 0170 0009 2803 4003
c280 2087 7498 8770 1007 7628 8736 a087
7048 0776 6883 7108 0776 6087 7900 cc21
1cd8 611e ca01 20cc 411e c2a1 1dca a10d
e0e1 1dd2 c11d e8a1 1ce4 0170 8777 7087
3660 8772 0807 7300 0876 2887 7998 8736
8007 7928 8771 4887 7928 8736 3007 7868
8770 2007 c01c c281 1de6 a11c 00a2 1dd2
c11d da80 1dca e11c c281 1dda c01e ca61
1ce8 e11d e4a1 0dee 211d c881 1ed0 0180
0380 7087 7768 8374 7007 7398 8736 3007
7868 8376 0807 7a40 07c0 1cc2 811d e6a1
1c00 c21d dea1 0dd4 a11e da01 1eda 801e
c241 1cd8 a11c e601 3087 7060 8779 2807
8070 8777 6803 7708 0777 9887 3630 0778
6883 7608 077a 4007 c01c c281 1de6 a11c
00c2 1dde a10d e621 1dce c11d ca81 1cda
401f ca41 1ede 611e dac0 1ce0 a10d da21
1ce8 011d 0073 0807 7698 8772 0008 7778
8736 a007 7908 0778 8087 7470 8773 6883
7608 077a 4007 801e e4a1 1eca 0120 e041
1ede 411c caa1 0de6 811e c261 1cd6 01f8
855f 1807 7458 8779 a087 75f8 0572 0807
79b8 8774 7007 8098 077a 0887 7158 8736
8007 7978 077a 2887 71a0 8777 9087 3610
877a 3007 7328 0779 6883 7948 077d 2807
000f 0082 1ec2 411e cea1 1ce8 a10d c601
1eea 0108 0778 8007 7628 8736 6887 3800
087a 0807 7938 8772 a087 3630 8772 0807
7aa8 0779 2887 7900 d620 1cca 611e d860
0dc6 411e c681 0dd6 601c e421 1fe0 811e
de81 0dd6 801c de81 1ee0 411e de81 1cd8
600d cc01 1eda 201c e4a1 1dec 010f d860
0dcc 011e e2c0 0ecc a11d d881 0dd6 c01c
ea81 1dd8 c11c e021 0eec 800d d680 1de6
a11c d860 0ddc a11c dec1 1dd8 600d e421
1ce6 810d d640 1ec6 011e c681 0dd6 401e
c8a1 1dd8 600d e601 1dc2 410e d860 0de6
011d c261 0ed8 600d e6a1 1de8 800d d6c0
1ef0 c00d ea20 1cd8 600d f461 1cda 810d
d640 1fc6 411f 00a2 1edc 611e c2c1 1cca
a10d cc01 1eda a01d c281 1ed0 0130 8770
6087 7928 0780 a887 7928 8736 9887 7730
077a 6803 7360 8777 0807 7a00 cc21 1cd8
611e ca01 0000 0000 4918 0000 0100 0000
1382 0000 13b0 7090 8776 b003 3a68 8370
8007 7860 8772 6883 7608 8771 7887 79c0
8738 8803 3780 0337 8083 0d61 500e 6dd0
0e7a f00e 6d90 0e76 4007 7a60 0774 d006
e910 0772 8007 7a10 0772 8007 6de0 0e73
2007 7a60 0774 d006 b310 0772 8007 1a21
0c69 3000 d2f8 cc90 0a38 0200 0002 0000
0000 0000 0000 8003 1852 1d84 0100 4000
0000 0000 0000 0000 7000 121b 048a 0a0a
0000 6481 0000 0000 0a00 0000 321e 9810
1911 4c90 8c09 2647 c604 4382 22a0 1c4b
5806 8212 1801 a019 0120 28c0 8042 2807
0000 0000 b118 0000 9700 0000 3308 801c
c4e1 1c66 1401 3d88 4338 84c3 8c42 8007
7978 0773 9871 0ce6 000f ed10 0ef4 800e
330c 421e c2c1 1dce a11c 6630 053d 8843
3884 831b cc03 3dc8 433d 8c03 3dcc 788c
7470 077b 0807 7948 8770 7007 7a70 0376
7887 7020 8719 cc11 0eec 900e e130 0f6e
300f e3f0 0ef0 500e 3310 c41d de21 1cd8
211d c261 1e66 3089 3bbc 833b d043 39b4
033c bc83 3c84 033b ccf0 1476 6007 7b68
0737 6887 7268 0737 8087 7090 8770 6007
7628 0776 f805 7678 8777 8087 5f08 8771
1887 7298 8779 9881 2cee f00e eee0 0ef5
c00e ec30 0362 c8a1 1ce4 a11c cca1 1ce4
a11c dc61 1cca 211c c481 1dca 6106 d690
4339 c843 3998 4339 c843 39b8 c338 9443
3888 033b 94c3 2fbc 833c fc82 3bd4 033b
b0c3 0cc7 6987 7058 8772 7083 7468 0778
6087 7418 8774 a087 19ce 530f ee00 0ff2
500e e490 0ee3 400f e120 0eec 500e 3320
281d dcc1 1ec2 411e d221 1cdc 811e dce0
1ce4 e11d ea01 1e66 1851 38b0 433a 9c83
3bcc 5024 7660 077b 6807 3760 8777 7807
7898 514c f490 0ff0 500e 331e 6a1e ca61
1ce8 211d dec1 1d7e 011e e4a1 1ccc 211d
f061 0654 8583 38cc c33b b043 3dd0 4339
fcc2 3ce4 433b 88c3 3bb0 c38c c50a 8779
9887 7718 8774 0807 7a28 0772 9881 5ce3
100e ecc0 0ee5 500e f330 23c1 d241 1ee4
e117 d8e1 1dde 011e 6648 193b b083 3db4
831b 84c3 388c 4339 ccc3 3cb8 c139 c8c3
3bd4 033c cc48 b471 0807 7660 0771 0887
7158 8719 dbc6 0eec 600f ede0 06f0 200f
e530 0fe5 200f f650 0e6e 100e e330 0ee5
300f f3e0 06e9 e00e e450 0ef8 3023 e2ec
611c c281 1dd8 e117 ec21 1de6 211d c421
1dd8 211d e821 1f66 209d 3bbc 433d b803
3994 8339 cc58 bc70 7007 7778 077a 0807
7a48 8777 7007 0000 7920 0000 8600 0000
721e 4820 4388 0c19 0972 3248 2023 818c
9191 d144 a010 2864 3c31 3242 8e90 21a3
e830 ee02 cbe4 796d e071 4a36 5d5d e206
5344 4b20 5665 7273 696f 6e4f 626a 6563
7469 7665 2d43 2056 6572 7369 6f6e 4f62
6a65 6374 6976 652d 4320 496d 6167 6520
496e 666f 2056 6572 7369 6f6e 4f62 6a65
6374 6976 652d 4320 496d 6167 6520 496e
666f 2053 6563 7469 6f6e 5f5f 4441 5441
2c5f 5f6f 626a 635f 696d 6167 6569 6e66
6f2c 7265 6775 6c61 722c 6e6f 5f64 6561
645f 7374 7269 704f 626a 6563 7469 7665
2d43 2047 6172 6261 6765 2043 6f6c 6c65
6374 696f 6e4f 626a 6563 7469 7665 2d43
2043 6c61 7373 2050 726f 7065 7274 6965
7377 6368 6172 5f73 697a 6562 7261 6e63
682d 7461 7267 6574 2d65 6e66 6f72 6365
6d65 6e74 7369 676e 2d72 6574 7572 6e2d
6164 6472 6573 7373 6967 6e2d 7265 7475
726e 2d61 6464 7265 7373 2d61 6c6c 7369
676e 2d72 6574 7572 6e2d 6164 6472 6573
732d 7769 7468 2d62 6b65 7950 4943 204c
6576 656c 4170 706c 6520 636c 616e 6720
7665 7273 696f 6e20 3133 2e30 2e30 2028
636c 616e 672d 3133 3030 2e30 2e32 392e
3329 0000 2308 8030 8290 0c23 0800 3182
0014 2308 8331 8200 1c23 0800 3282 0024
330c 4f00 cd30 44c2 33c3 100d d20c 4344
1433 0c91 31cd 3044 0735 c310 21d5 0c43
9448 330c 9122 cd30 448b 34c3 1031 d20c
83d5 3c33 048e 8c04 2628 2336 36bb 3697
b637 b23a b632 1733 b6b0 b3b9 5118 ebc2
326d e33a ef03 8330 4885 8dcd aecd 258d
accc 8d6e 9440 0c00 a918 0000 1c00 0000
0b0a 7228 8777 8007 7a58 7098 433d b8c3
38b0 4339 d0c3 82e6 1cc6 a10d e841 1ec2
c11d e621 1de8 211d dec1 1d16 34e3 600e
e750 0fe1 200f e440 0fe1 200f e750 0ef4
b080 8107 7928 8770 6007 7678 8771 0807
7a28 0772 5870 9cc3 38b4 013b a483 3d94
c382 031e e841 1ec2 a11e e801 1d00 0000
d110 0000 0600 0000 07cc 3ca4 833b 9c03
3b94 033d a083 3c94 4338 90c3 0100 0000
6120 0000 0e00 0000 1304 412c 1000 0000
0100 0000 0465 0000 3311 0040 8cc2 4c04
0010 a330 6c40 08c5 000c 1b10 0131 0024
c020 0106 0a01 0860 6080 c006 0000 0000
6120 0000 0d00 0000 1304 c14c 0400 10a3
3013 0100 c428 cc44 1400 410a c306 c4a0
0cc0 b001 2114 0330 6c40 0404 018c 1818
0008 8241 f02c cd06 0000 0000 7120 0000
0300 0000 320e 1022 8400 e304 1830 4f00
0000 0000 650c 0000 2500 0000 1203 9428
0100 0000 0200 0000 0b00 0000 0600 0000
4c00 0000 0100 0000 5800 0000 0000 0000
5800 0000 0200 0000 8800 0000 0000 0000
1100 0000 1800 0000 2900 0000 0600 0000
0700 0000 0000 0000 8800 0000 0000 0000
0000 0000 0200 0000 0000 0000 2f00 0000
0800 0000 0000 0000 0700 0000 ffff ffff
0024 0000 3700 0000 0500 0000 0700 0000
0400 0000 ffff ffff 0024 0000 0000 0000
5d0c 0000 1200 0000 1203 947c 0000 0000
7465 7374 4164 646d 6169 6e31 332e 302e
3061 726d 3634 2d61 7070 6c65 2d6d 6163
6f73 7831 312e 302e 306d 6169 6e2e 6d5f
7465 7374 4164 645f 6d61 696e 0000 0000
复制代码

生成汇编代码

我们通过最终的.bc或.ll代码生成汇编代码

clang -S -fobjc-arc main.bc -o main.s
clang -S -fobjc-arc main.ll -o main.s
复制代码

生成的汇编代码如下:

  .section  __TEXT,__text,regular,pure_instructions
  .build_version macos, 11, 0 sdk_version 11, 3
  .globl  _testAdd                        ; -- Begin function testAdd
  .p2align  2
_testAdd:                               ; @testAdd
  .cfi_startproc
; %bb.0:
  sub sp, sp, #16                     ; =16
  .cfi_def_cfa_offset 16
  str w0, [sp, #12]
  str w1, [sp, #8]
  ldr w8, [sp, #12]
  ldr w9, [sp, #8]
  add w8, w8, w9
  add w0, w8, #3                      ; =3
  add sp, sp, #16                     ; =16
  ret
  .cfi_endproc
                                        ; -- End function
  .globl  _main                           ; -- Begin function main
  .p2align  2
_main:                                  ; @main
  .cfi_startproc
; %bb.0:
  sub sp, sp, #32                     ; =32
  stp x29, x30, [sp, #16]             ; 16-byte Folded Spill
  add x29, sp, #16                    ; =16
  .cfi_def_cfa w29, 16
  .cfi_offset w30, -8
  .cfi_offset w29, -16
  stur  wzr, [x29, #-4]
  str w0, [sp, #8]
  str x1, [sp]
  mov w0, #1
  mov w1, #2
  bl  _testAdd
  ldp x29, x30, [sp, #16]             ; 16-byte Folded Reload
  add sp, sp, #32                     ; =32
  ret
  .cfi_endproc
                                        ; -- End function
  .section  __DATA,__objc_imageinfo,regular,no_dead_strip
L_OBJC_IMAGE_INFO:
  .long 0
  .long 64
​
.subsections_via_symbols
复制代码

汇编代码也可以优化,参数和IR相同

clang -Os -S -fobjc-arc main.m -o main.s
复制代码

优化后的汇编代码如下:

  .section  __TEXT,__text,regular,pure_instructions
  .build_version macos, 11, 0 sdk_version 11, 3
  .globl  _testAdd                        ; -- Begin function testAdd
  .p2align  2
_testAdd:                               ; @testAdd
  .cfi_startproc
; %bb.0:
  add w8, w0, w1
  add w0, w8, #3                      ; =3
  ret
  .cfi_endproc
                                        ; -- End function
  .globl  _main                           ; -- Begin function main
  .p2align  2
_main:                                  ; @main
  .cfi_startproc
; %bb.0:
  mov w0, #6
  ret
  .cfi_endproc
                                        ; -- End function
  .section  __DATA,__objc_imageinfo,regular,no_dead_strip
L_OBJC_IMAGE_INFO:
  .long 0
  .long 64
​
.subsections_via_symbols
复制代码

生成目标文件

目标文件生成,汇编器以汇编代码作为输出,将汇编代码转为机器代码,最后输出目标文件(object file)。

clang -fmodules -c main.s -o main.o
复制代码

.o文件的内容:

cffa edfe 0c00 0001 0000 0000 0100 0000
0400 0000 b801 0000 0020 0000 0000 0000
1900 0000 3801 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
a000 0000 0000 0000 d801 0000 0000 0000
a000 0000 0000 0000 0700 0000 0700 0000
0300 0000 0000 0000 5f5f 7465 7874 0000
0000 0000 0000 0000 5f5f 5445 5854 0000
0000 0000 0000 0000 0000 0000 0000 0000
5400 0000 0000 0000 d801 0000 0200 0000
7802 0000 0100 0000 0004 0080 0000 0000
0000 0000 0000 0000 5f5f 6f62 6a63 5f69
6d61 6765 696e 666f 5f5f 4441 5441 0000
0000 0000 0000 0000 5400 0000 0000 0000
0800 0000 0000 0000 2c02 0000 0000 0000
0000 0000 0000 0000 0000 0010 0000 0000
0000 0000 0000 0000 5f5f 636f 6d70 6163
745f 756e 7769 6e64 5f5f 4c44 0000 0000
0000 0000 0000 0000 6000 0000 0000 0000
4000 0000 0000 0000 3802 0000 0300 0000
8002 0000 0200 0000 0000 0002 0000 0000
0000 0000 0000 0000 3200 0000 1800 0000
0100 0000 0000 0b00 0003 0b00 0000 0000
0200 0000 1800 0000 9002 0000 0500 0000
e002 0000 2800 0000 0b00 0000 5000 0000
0000 0000 0300 0000 0300 0000 0200 0000
0500 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 ff43 00d1 e00f 00b9
e10b 00b9 e80f 40b9 e90b 40b9 0801 090b
000d 0011 ff43 0091 c003 5fd6 ff83 00d1
fd7b 01a9 fd43 0091 bfc3 1fb8 e00b 00b9
e103 00f9 2000 8052 4100 8052 0000 0094
fd7b 41a9 ff83 0091 c003 5fd6 0000 0000
4000 0000 0000 0000 0000 0000 0000 0000
2400 0000 0010 0002 0000 0000 0000 0000
0000 0000 0000 0000 2400 0000 0000 0000
3000 0000 0000 0004 0000 0000 0000 0000
0000 0000 0000 0000 4400 0000 0400 002d
2000 0000 0100 0006 0000 0000 0100 0006
1c00 0000 0e01 0000 0000 0000 0000 0000
1600 0000 0e02 0000 5400 0000 0000 0000
1000 0000 0e03 0000 6000 0000 0000 0000
0100 0000 0f01 0000 2400 0000 0000 0000
0700 0000 0f01 0000 0000 0000 0000 0000
005f 6d61 696e 005f 7465 7374 4164 6400
6c74 6d70 3200 6c74 6d70 3100 6c74 6d70
3000 0000 0000 0000 
复制代码

生成可执行文件(链接)

链接器把编译产生的.o文件和.dylib/.a文件,生成一个mach-o文件。

clang main.o -o main
复制代码

可执行文件.jpg

总结

本篇我们主要研究了编译器的编译流程,从源代码可执行文件

  • 预处理:处理包括宏的替换,头文件的导入等。
  • 词法分析:根据一些标识符对源文件进行切割,词法分析产生的记号一般可以分为如下几类:关键字、标识符、字面量和特殊符号。注意这一步是不会检查代码是否有错误。
  • 语法分析:语法分析器对词法分析后的记号进行语法分析,产生抽象语法树(AST),这一步会检查语法是否正确
  • 生成中间代码(IR):将上面生成的语法树转换成中间代码。中间代码使得编译器可以范围内前端和后端。编译器的前端负责产生机器无关的中间代码,编译器后端将中间代码转换成目标机器代码。
  • 生成汇编代码:将中间代码准换成汇编。
  • 生成目标文件(.o):将汇编语言转换成目标文件。
  • 链接目标文件,生成可执行文件:这一步主要是处理多个库依赖的情况。

猜你喜欢

转载自juejin.im/post/7014753131842011166