目录
之前一直想自己发明一个新语言并配套搞个编译器来着,想了很久发现不太可行,付出与回报不成正比,也没法推广,现在没有一个新的语言的生存环境。所以就通过gcc的原理去对编译原理做加深性的学习吧。GCC(GNU Compiler Collection)是一个广泛使用的编译器集合,支持多种编程语言,如C、C++、Fortran等。
一、GCC编译过程
GCC的编译过程通常分为以下几个主要阶段:
-
预处理(Preprocessing):
- 输入:源代码文件(如.c文件)。
- 输出:预处理后的代码文件(通常通过gcc -E命令查看,文件后缀通常为.i)。
- 任务:处理宏定义、文件包含(#include)、条件编译指令(#ifdef等)等。
- 工具:cpp(C PreProcessor)。
-
编译(Compiling):
- 输入:预处理后的代码文件。
- 输出:汇编代码文件(通常为.s文件,通过gcc -S命令查看)。
- 任务:将预处理后的代码翻译成目标架构的汇编代码。
- 工具:前端编译器(如cc1,针对C语言)。
-
汇编(Assembling):
- 输入:汇编代码文件。
- 输出:目标文件(通常为.o文件,通过gcc -c命令生成)。
- 任务:将汇编代码翻译成机器代码,生成目标文件。
- 工具:as(GNU Assembler)。
-
链接(Linking):
- 输入:一个或多个目标文件。
- 输出:可执行文件。
- 任务:将多个目标文件和库文件链接在一起,生成最终的可执行文件。
- 工具:ld(GNU Linker)。
二、GCC内部工作机制
GCC的内部工作机制复杂而精妙,主要由以下几个部分组成:
-
前端(Frontend):
- 负责处理特定编程语言的语法和语义分析。
- 生成中间表示(IR,Intermediate Representation)。GCC支持多种前端,每种前端负责不同的编程语言。
-
中间表示(IR):
- GCC使用一种称为GIMPLE的中间表示形式。GIMPLE是一种三地址码,便于进行各种优化和转换。
- 通过将代码转换为统一的中间表示,GCC可以对不同语言使用相同的优化和后端处理。
-
优化器(Optimizer):
- GCC进行多种优化,包括局部优化、全局优化、循环优化、指令级并行优化等。
- 优化可以在不同的阶段进行,如GIMPLE层优化、RTL(Register Transfer Level)层优化等。
- 常见的优化技术包括常量折叠、循环展开、死代码消除等。
-
后端(Backend):
- 负责将中间表示转换为目标机器的汇编代码。
- 包含特定架构的代码生成器和指令选择器。
- 处理目标架构的寄存器分配、指令调度等。
三、GCC优化技术示例
-
常量传播:
- 原始代码:
int square(int x) { int result = x * x; return result; }
- 优化后代码:
int square(int x) { return x * x; }
- 常量传播和折叠将中间变量
result
去掉,直接返回计算结果。
- 原始代码:
-
死代码消除:
- 原始代码:
int foo(int x) { int y = x * 2; if (x > 10) { y = 0; } return y; }
- 优化后代码:
int foo(int x) { if (x > 10) { return 0; } return x * 2; }
- 死代码消除移除了不必要的变量和赋值操作。
- 原始代码:
-
循环展开:
- 原始代码:
void loop_example(int *arr, int n) { for (int i = 0; i < n; i++) { arr[i] = i * 2; } }
- 优化后代码:
void loop_example(int *arr, int n) { int i; for (i = 0; i <= n - 4; i += 4) { arr[i] = i * 2; arr[i + 1] = (i + 1) * 2; arr[i + 2] = (i + 2) * 2; arr[i + 3] = (i + 3) * 2; } for (; i < n; i++) { arr[i] = i * 2; } }
- 循环展开减少了循环控制的开销,提高了执行效率。
- 原始代码:
四、源码获取
其实有个很有意思的现象,高级语言的编译器源码都是高级语言。gcc的源码是c语言,大家可能会想到先有鸡还是先有蛋的悖论。其实最初C语言的编译器是B语言实现的,再往前推很多的语言的编译是汇编做的,而最开始的汇编器是打孔打出来的。为了方便大家使用,编译器都会根据人的使用习惯去升级。所以可能会出现左脚踩右脚的神奇现象。但时至今日其实编译原理这门科学已经有很久都没有进步过了。越往底层就越趋近于数学。由于研究起来没有收益,全世界对这里的投入近些年来可能近乎于0.
有点偏离主题了。gcc源码可以通过ftp获取也可以去官网或者github获取。但是我更推荐ftp因为快。其它途径受某些限制的影响很慢。
ftp://gcc.gnu.org/pub/gcc/infrastructure
进来之后有这些东西,release是发布的版本,下载下来可以直接使用
infrastructure
目录扮演着至关重要的角色。这个目录主要包含了GCC编译过程中所需的一些基础设施和依赖库。具体来说,这些依赖库是GCC正确编译和运行的基石,它们提供了必要的数学运算和算法支持。
通常,在infrastructure
目录下,你会找到诸如GMP(GNU Multiple Precision Arithmetic Library,GNU多精度算术库)、MPFR(Multiple Precision Floating-Point Reliably,多精度浮点可靠库)、MPC(Multiple Precision Complex,多精度复数库)等关键依赖库的源代码。这些库分别用于支持高精度整数运算、高精度浮点运算以及高精度复数运算,是GCC在编译和优化过程中不可或缺的组件。
例如,当你尝试手动下载并安装GCC时,你可能需要先从infrastructure
目录下载这些依赖库的源代码,然后在编译GCC之前将它们解压并放置在合适的目录中。这样,GCC在编译过程中就能够正确地找到并使用这些依赖库,从而确保编译出的GCC版本具备完整的功能和性能。
libstdc++是GCC项目中的一个重要部分,它实现了C++标准库。这个库为C++程序提供了基本的运行时支持,包括内存管理、输入输出、字符串处理等功能。在使用GCC编译C++程序时,libstdc++通常是必需的。
在软件开发和版本控制领域,“snapshots”通常指的是软件在某一特定时刻的状态记录,也就是快照。这种快照版本通常代表软件的不稳定、尚处于开发中的状态。对于GCC和libstdc++来说,快照版本可能包含了最新的功能或修复,但也可能存在一些未知的问题或错误。因此,使用快照版本需要谨慎,并进行充分的测试。
也可以从gnu官网获取
Software- GNU Project - Free Software Foundation
现在gnu有中文的网页了,十分人性
我原来在imax6ull上适配的linux是基于7.5的,在exynos4412上适配的是基于4.6.4的,imax6ull已经捐给学校了,因为做我的毕设了。所以现在就拿exynos4412展示吧
gcc的代码都用sha512做的加密,防止下载过程中被黑客注入木马什么的。
防止有的兄弟找不到可以直接在这个目录下载
篇幅问题下期在讲gcc源码的目录层次。最近工作特别忙,也就抽出来这点时间搞点自己的事情,顺便和大家分享一下。后面我会调整一下个人时间分配,多花些时间提升自己。希望各位爱好技术的兄弟们我们可以顶峰相见。