我想深入了解编译器,链接器和加载器的意义和工作。
参考任何语言优选c。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 1=====> COMPILATION PROCESS <======
2
3 |
4 |----> Input is Source file(.c)
5 |
6 V
7 +=================+
8 | |
9 | C Preprocessor |
10 | |
11 +=================+
12 |
13 | ---> Pure C file ( comd:cc -E <file.name> )
14 |
15 V
16 +=================+
17 | |
18 | Lexical Analyzer|
19 | |
20 +-----------------+
21 | |
22 | Syntax Analyzer |
23 | |
24 +-----------------+
25 | |
26 | Semantic Analyze|
27 | |
28 +-----------------+
29 | |
30 | Pre Optimization|
31 | |
32 +-----------------+
33 | |
34 | Code generation |
35 | |
36 +-----------------+
37 | |
38 | Post Optimize |
39 | |
40 +=================+
41 |
42 |---> Assembly code (comd: cc -S <file.name> )
43 |
44 V
45 +=================+
46 | |
47 | Assembler |
48 | |
49 +=================+
50 |
51 |---> Object file (.obj) (comd: cc -c <file.name>)
52 |
53 V
54 +=================+
55 | Linker |
56 | and |
57 | loader |
58 +=================+
59 |
60 |---> Executable (.Exe/a.out) (com:cc <file.name> )
61 |
62 V
63 Executable file(a.out)
64
C预处理器: –
C预处理是编译的第一步。它处理:
define语句。
include语句。
条件语句。
宏
该单元的目的是将C源文件转换为Pure C代码文件。
C编译:
单位有六个步骤:
1)词汇分析器:
它组合源文件中的字符,形成一个“TOKEN”。一个
令牌是一组不具有“空格”,“制表符”和“新行”的字符。
因此,这个编译单元也称为“TOKENIZER”。它也删除
注释,生成符号表和重定位表条目。
2)语法分析器:
此单元检查代码中的语法。例如:
1
2
3
4
5
6
7
8
9 1{
2 int a;
3 int b;
4 int c;
5 int d;
6
7 d = a + b - c * ;
8}
9
上面的代码将生成解析错误,因为方程不是
均衡。此单元通过生成解析器树在内部检查
如下:
1
2
3
4
5
6
7
8 1=
2 / \
3 d -
4 / \
5 + *
6 / \ / \
7 a b c ?
8
因此,该单位也称为PARSER。
3)语义分析器:
此单元检查语句中的含义。例如:
1
2
3
4
5
6
7
8
9
10 1{
2 int i;
3 int *p;
4
5 p = i;
6 -----
7 -----
8 -----
9}
10
上面的代码生成错误“Assignment of incompatible type”。
4)预优化:
该单元独立于CPU,即存在两种类型的优化
优化(独立于CPU)
后优化(取决于CPU)
此单元以下列形式优化代码:
I)死代码消除
II)子代码消除
III)循环优化
I)死代码消除:
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13 1{
2 int a = 10;
3 if ( a > 5 ) {
4 /*
5 ...
6 */
7 } else {
8 /*
9 ...
10 */
11 }
12}
13
这里,编译器在编译时知道’a’的值,因此它也
知道if条件总是为真。因此,它消除了else
部分在代码中。
II)子代码消除:
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 1{
2 int a, b, c;
3 int x, y;
4
5 /*
6 ...
7 */
8
9 x = a + b;
10 y = a + b + c;
11
12 /*
13 ...
14 */
15}
16
可以优化如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 1{
2 int a, b, c;
3 int x, y;
4
5 /*
6 ...
7 */
8
9 x = a + b;
10 y = x + c; // a + b is replaced by x
11
12 /*
13 ...
14 */
15}
16
III)循环优化:
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 1{
2 int a;
3 for (i = 0; i < 1000; i++ ) {
4
5 /*
6 ...
7 */
8
9 a = 10;
10
11 /*
12 ...
13 */
14 }
15}
16
在上面的代码中,如果’a’是局部的而不是在循环中使用,那么它可以是
优化如下:
1
2
3
4
5
6
7
8
9
10 1{
2 int a;
3 a = 10;
4 for (i = 0; i < 1000; i++ ) {
5 /*
6 ...
7 */
8 }
9}
10
5)代码生成:
这里,编译器生成汇编代码使得更多
常用的变量存储在寄存器中。
6)后优化:
这里的优化是依赖于CPU。假设有多个
跳转到代码中,然后将它们转换为一个:
1
2
3
4
5
6 1-----
2 jmp:<addr1>
3<addr1> jmp:<addr2>
4 -----
5 -----
6
控制跳转到直接。
然后最后一个阶段是链接(创建可执行文件或库)。当运行可执行文件时,它需要的库是加载的。