说明:这篇文件是在读《程序员的自我修养——链接、装载与库》的一点笔记,权当时学习的记录。
1、GCC编译过程分解
以HelloWorld程序为例
2、预编译
规则:
命令:gcc -E XXX.c -o XXX.i
3、编译
词法分析、语法分析、语义分析及优化 --------------->> 汇编代码文件
命令:gcc -S XXX.c -o XXX.s
3.1 编译过程
6步:扫描、语法分析、语义分析、源代码优化、代码生成和目标代码优化。
1、词法分析
源代码程序进入扫描器(scanner),将源代码的字符序列分割成一系列的记号(Token)。并将记号进行分类,如符号表(存放标识符)和文字表(存放数字、字符串常量)等。
2、语法分析
语法分析器(Grammer Parser)对记号(Token)进行语法分析,并生成语法树(Syntax Tree)。
如,array[index] = (index + 4) * (2 + 6) 生成的语法树图。
3、语义分析
语义分析器完成对表达式的语法层面的分析。它不知道语句真正含义,是对静态语义的分析。所谓静态语义,是编译期可确定的语义,包括声明、类型匹配和类型转换。对应的动态语义,则是运行期确定的语义。
语义分析结果,在语法树上标识类型。
4、中间语言生成
源代码优化器对源代码进行优化。如将编译期可确定的值进行优化。语法树如下:
5、目标代码生成与优化
代码生成器将中间代码转换成目标机器代码,依赖于目标机器。
目标代码优化器对上面生成的目标代码进行优化(如、寻址方式、位移代替乘法、删除多余的指令等)。
总结:编译器可以将一个源代码文件编译成一个未链接的目标文件。
4、汇编
汇编代码 --------------->> 机器指令
命令:as XXX.s -o XXX.o 或者 gcc -c XXX.s -o XXX.o
5、链接
符号(Symbol),表示一个地址。这个地址可以是一段子程序的起始地址,或是一个变量的起始地址。
代码按照功能或者性质划分。如语句块、函数、功能模块。变量的访问需要知道目标变量的地址,函数访问需要知道目标函数的地址,这就是模块划分后面临的模块间的通信问题。链接(Linking)将这些模块完美的拼接和组合起来。如下图所示:
静态链接,把各个模块之间相互引用的部分处理好,使得各模块间能够正确地衔接。包括,地址空间分配、符号决议和重定位等。
库是一些常用代码被编译成目标文件后打包存放。