-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathld2.txt
84 lines (39 loc) · 3.37 KB
/
ld2.txt
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
==被隐藏的"编译"过程==
常用的IDE将编译和链接过程集成在一起,这个过程一般被称为"build"(构建).
编译器的过程分解:预处理(prepressing)-->编译(compilation)-->汇编(assembly)-->链接(linking)
===预编译/预处理===
源代码.c和相关的.h文件在预编译器cpp进行预编译过程,输出.i文件,源代码.cpp和.hpp编译输出.ii文件.
实例:gcc -E hello.c -o hello.i; cpp hello.c > hello.i
具体实现:
[1]#define涉及的所有宏定义展开.
[2]条件判断的预编译指令,例如#if,#ifdef等全部处理.
[3]递归操作去处理#include涉及的头文件内容,将包含的文件插入到指令的位置.
[4]删除所有注释
[5]为代码段添加"行号"和"文件名标识",便于出错时指出.
[6]保留所有#pragma编译器指令(特殊)
===编译===
对.i预编译后的文件进行语法分析,词法分析并在优化后生产相应的.s汇编代码文件.
实例:gcc -S hello.i -o hello.s; gcc -S hello.c -o hello.s
===汇编===
每一句汇编语句基本都对应着一条机器指令,本过程即是通过汇编器as将.s的汇编代码文件转化为机器语言的代码,输出.o文件,属于一种"翻译"过程.
实例:as hello.s -o hello.o; gcc -c hello.s -o hello.o; gcc -c hello.c -o hello.o
===链接===
将所有的相关的.o文件和各类库文件(.a .lib .so .dll等等)组合在一起,形成某种关系,输出.out可执行文件.
(./project_name.out)
==编译器的"工作"==
源代码--(扫描)-->tokens--(语法分析/parser)-->语法树/syntax_tree--(语义分析/semantic anlyzer)-->commented syntax tree--(源代码优化)-->intermediate representation--(代码生成)-->目标代码--(目标代码优化)-->最终目标代码.
[1]扫描(Scanner):将源代码通过有限状态机的算法记录为一个个的字符/记号(token)
[2]语法分析:对记号进行"上下文无关语法"分析语法,由grammar parser生成以"表达式"为节点的树,整个树就是很多表示式的组合.
树的结构以"计算符号"为引导节点,数字和一般符号通常在树的底端.
[3]语义分析:实际变量的替换和可行性尝试,整个语法树都被会标识上符号和数字的类型,还会涉及例如符号类型之间的硬性转换等等.
[4]中间语言生成:源代码优化器将一些可以在编译期就确定的东西进行简化,从而精简源代码.(三地址码/P-代码)
[5]代码生成:将中间代码转换成机器代码,
[6]目标代码优化:对机器代码还可以有进一步的优化
问题:index和array的地址未确定......如果定义在其他模块,就需要链接器在最后将所有相关的目标文件链接起来形成可执行文件.
==链接器==
重定位:重新计算各个目标的地址
代码的模块化更利于单独的开发编译测试,模块间的沟通通过函数调用和变量访问来实现,都可以归属于"模块间的符号引用",最后完成拼接过程.
==静态链接==
地址和空间分配,符号决议(绑定),重定位.
runtime library:运行时库,支持程序运行的基本函数集合.
链接器链接过程中对不同模块间的需要的相应地址做出修正,让程序员可以直接引用其他模块的函数和全局变量而无需知道它们的地址,链接器会自己去查询地址,链接完成后会自动修正之前那些未知的目标地址,使其指向正确的地址,这个过程就叫"重定位".