程序源代码——最终可执行文件

程序编译链接实现过程:预编译、编译、汇编、链接

1、     预编译

       首先是源代码文件hello.c和相关的头文件,如stdio.h等被预编译器预编译成一个.i文件,对应c++文件来说,它的源代码文件的扩展名可能是.cpp或.cxx,头文件的扩展名可能是.hpp,而预编译后的文件扩展名是.ii。第一步预编译的过程相当于如下命令(-E表示只进行预编译):

$ gcc  -E  hello.c  -o  hello.i  (gcc  -o  hello.i   -E  hello.c  ) 注:- o后为生成的

或者$ cpp  hello.c   >   hello.i

预处理器(cpp)预编译过程主要处理源代码文件中的以“#”开始的预编译指令,例如“#include”、“#define”主要处理规则如下:

(1)  将所有的“#define”删除,并且展开所有的宏定义。

(2)处理所有条件预编译指令,将被包含的文件插入到改预编译指令的位置,注意,这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。

(3)删除所有的注释“//”和“/* */”。

(4)添加行号和文件名标识,比如#2“hello.c”2,以便于编译时 编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号。

(5)保留所有的#pragma编译器指令,因为编译器要使用它们。

经过预编译后的.i文件不包含任何宏定义,因为所有的宏已经被展开,并且包含的文件也已经被插入到.i文件中。所以当我们无法判断宏定义是否正确或者头文件包含是否正确时,可以查看预编译后的文件来确定问题。

2、     编译

编译过程就是把预处理的文件进行一系列词法分析、语法分析、语义分析及优化后产生相应的汇编代码文件。

编译器(ccl)编译过程一般可以分为6步:扫描、语法分析、语义分析、代码生成和目标代码优化

编译过程相当于如下命令:

$ gcc  -S  hello.i  -o  hello.s  (gcc  -o  hello.s   -S  hello.i  ) 

3、     汇编

汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。

汇编器(as)汇编过程相当于如下命令:

$ gcc  -c  hello.s  -o  hello.o 

或者可以调用汇编器as来完成

$ as  hello.s  -o  hello.o 

4、     链接

链接的内容主要就是把各个模块之间相互引用的部分都处理好,使得各个模块之间能够正确地衔接。链接过程主要包括了地址和空间分配、符号决议和重定义。

最基本的静态链接过程为:每个模块的源代码文件(如.c文件)经过编译器编译成目标文件(object   file, 一般扩展名为.o或者.obj),目标文件(也称为模块)和库一起链接形成最终可执行文件。

链接器(ld)链接过程相当于如下命令:

$ gcc  -o  hello  hello.o 

5、     一步完成

可以使用gcc命令从C源代码文件开始,经过预编译、编译和汇编直接输出目标文件

$ gcc  -c  hello.c  -o  hello.o 

($ gcc  -o  hello   hello.c )

6、    两步完成  

$ gcc  -c  hello.c

$ gcc  -o  hello hello.o 

7、    .o文件不能执行的原因

因为.o文件下符号表里的符号未分配虚拟地址,所以执行的时候因为找不到存储地址而不能执行。

猜你喜欢

转载自blog.csdn.net/Aspiration_1314/article/details/80178029