程序编译与连接
学习笔记,转自http://tieba.baidu.com/p/1783319407
?
平时做软件开发,大部分人很少关注编译和连接过程,因为所使用的集成开发环境(IDE)帮助我们做了这些事情。尤其是Linux 环境下的程序员如果不理解这些概念并使用 GNU make 来构建和管理自己的工程,应该不能算是一个合格的专业程序员,至少不能称得上是Linux程序员。
IDE提供的默认配置、编译和链接参数对于大部分软件开始来说已经足够了。但其强大的功能往往会迷惑我们,很多运行机制被掩盖。当程序出现的莫名其妙 的错误、遇到性能瓶颈时,就会茫然,束手无策。因为我们只能看到问题的现象,却很难看清本质,这些问题的本质就是软件运行背后的机制,以及支持软件运行的 平台和工具。
?
下面以C语言经典入门程序“Hello World!”为例。
#include?
{
printf(“Hello World!\n”);
return 0;
}
我们以使用GCC来编译为例说明,此时只需要使用最简单的命令(假设源文件名为helloworld.c):
$ gcc helloworld.c
?
事实上,上述过程分为4个步骤,分别为预处理(Preprocessing )、编译(Compilation)、汇编(Assembly)、链接(Linking)。gcc在后台实际上也经历了这几个过程,我们可以通过-v参数 查看它的编译细节,如果想看某个具体的编译过程,则可以分别使用参数-E、-S、-c和-O,对应的后台工具则分别为cpp、cc1、as、ld。
?
1、预处理
预编译过程主要处理那些源文件中以“#”开始的预编译指令,以及删除所有的注释“//”和“/* */”。预编译过程相当于以下命令(-E表示只进行预编译):
$ gcc -E helloworld.c -o helloworld.i
或者
$ cpp helloworld.c > helloworld.i
?
2、编译?
编译工程就是把预处理完的文件进行一系列语法分析、句法分析、语义分析及优化后生成相应的汇编代码文件,这个过程往往是整个程序构建的核心部分,也是最复杂的部分之一,现在只做介绍,不再进一步分析了。编译过程相当于以下命令:
$ gcc -S helloworld.i -o helloworld.s
现在版本的GCC把预编译和编译合为一步,使用cc1程序完成这一过程。我们可以直接调用ccl来完成编译。
$ ccl -S helloworld.c
对于C语言预编译和编译程序时cc1;对于C++是cc1plus;Objective-C是cclobj;java是jc1。所以gcc命令只是这些后台程序的包装,它会根据不同的参数要求去调用不同的后台程序。
gcc提供了一个优化选项-O,以便根据不同的运行平台和用户要求产生经过优化的汇编代码。例如,
$ gcc helloworld.c -o helloworld #默认优化级别(-O2)
$ gcc -O helloworld.c -o helloworld #进行基本优化
?
3、汇编?
汇编器将汇编代码转变成机器可以执行的指令,每一句汇编语句几乎都对已一条机器指令。所以汇编器的汇编过程相对于编译器来说比较简单,它没有复杂的语法、语义,也不需要指令优化,只要意义翻译即可,所以称为“汇编”。此过程可以使用汇编器as来完成:
$ as helloworld.s -o helloworld.o
或者
$ gcc -c helloworld.s -o helloworld.o
或者使用gcc命令从C源文件开始,经过预编译、编译、汇编后,直接输出目标文件:
$ gcc -c helloworld.c -o helloworld.o
gcc和as默认产生的目标代码都是ELF格式的,不再是普通的文本格式,无法直接通过文本编辑器浏览,需要一些专门的工具。
?
?
