编译与链接详解------@图论软件

来源:互联网 发布:2g手机怎样用4g网络 编辑:程序博客网 时间:2024/05/16 14:57

编译与链接详解

2017-10-25 图小论 图论软件

前文:

         我们知道一个.c/.cpp源程序文件要最后变成我们的.exe(windows)或者.out(Linux)可执行文件,要经过我们的编译和链接。了解这个过程对程序员来说是最基本的素质(因为写了这么久的代码都不知道它最后为啥能执行,那不是搞笑吗?)

        首先总体分为了编译和链接两大步。

        编译又包含了:预处理,编译,汇编,生成二进制可重定位文件。

        链接又包含了:

        链接第一步:1.合并所有需要链接的.obj(.o)文件 的段,并且调整段的偏移和段长度,合并.o文件的符号表。2.符号的解析。3。分配符号的虚拟内存地址。

         链接第二步:符号的重定位

        预处理阶段:它为我们把源代码中展开了所有以“#”开头的宏定义,并且删除了所有的注释。预处理后生成我们的.i文件

编译阶段:它进行我们的语法,语义分析(找错),并且将我们代码优化成ASCLL文件(也就是汇编语言)。从而生成.s文件。

         汇编阶段:通过汇编器将汇编语言转换成我们的计算机可以执行的二进制可重定位文件。为何是可重定位?

         因为我们任何一个源文件在进行编译阶段的时候会去产生我们的符号表,符号表中存放的就是我们程序所产生的符号(例如:函数名,变量名等),我们的编译阶段是不会去给我们的符号分配正确的地址,因此当我们查看.obj(.o)文件的符号表信息时就会出现下面这种情况:

我们定义一个main函数:

同时定义一个add函数:

这时我们去编译main.c生成我们的.o文件,并且去查看.o文件的符号表:

         我们可以发现我们符号的地址都是0x00000000,这些都是错误的地址,因此我们的计算机无法通过正确的地址去寻找到它的指令,那么计算机就无法去执行,这也就是我们.obj(.o)文件没有链接为何不能执行的根本原因.

         链接第一步:链接器首先把多个.o文件(包括我们头文件中包含的库函数)会按照相似段的属性(.text和.text,.data和.data,.bss和.bss的合并),段的长度和位置来合并这些段,并且建立起来映射关系,并且去合并他们的符号表。合并完符号表,从上图我们可以看出有的符号有其准确定义的地方比如.text段,.data段,但是像add和printf他们还处于UND状态。这是说明我们在引用他们,但是并未找到他们定义的地方,所以我们的符号的解析,它的作用就是去把那些还处于UND状态的符号找到其准确定义的地方。最后我们就会给这些符号分配正确的虚拟地址空间。

        链接的第二步:符号的重定位,经历过链接第一步,我们的符号的地址已经被正确的分配,因此我们需要回到我们的.o文件的符号表中,去给这些符号修改成正确的地址,这样我们的计算机就能够正确的寻址,从而执行指令,达到我们的可执行文件。

        看似简单的编译和链接,其实底层也发生了很多事情,虚心学习,其实你懂的只是沧海一粟。只有不断的学习积累,才能有所成就。