c++程序编译流程

基本流程图

1 预处理

预处理相当于根据预处理指令组装新的C/C++程序。经过预处理,会产生一个没有宏定义,没有条件编译指令,没有特殊符号的输出文件,这个文件的含义同原本的文件无异,只是内容上有所不同。

  • 读取C/C++源程序,对其中的伪指令(以#开头的指令)进行处理

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

    2. 处理所有的条件编译指令,如:“#if”、“#ifdef”、“#elif”、“#else”、“endif”等。这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉。

    3. 处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置。

(注意:这个过程可能是递归进行的,也就是说被包含的文件可能还包含其他文件)

  • 删除所有的注释

  • 添加行号和文件名标识。

以便于编译时编译器产生调试用的行号信息及用于编译时产生的编译错误或警告时能够显示行号

  • 保留所有的#pragma编译器指令

2 编译

将预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后,产生相应的汇编代码文件。

3 汇编

将编译完的汇编代码文件翻译成机器指令,并生成可重定位目标程序的.o文件,该文件为二进制文件,字节编码是机器指令。

  • 汇编器所产生的目标文件至少包括三个区,即文本区(text),数据区(data)和bss区。文本区一般包括程序的代码和常量,数据区通常存放全局变量等内容,bss区用于存放未初始化的变量或作为公共变量存储空间。在一个目标文件中,其text区从地址0开始,随后是data区,再后面是bss区。而要运行程序,必须装载到内存中,所以这些区的地址需要在内存中重新安排,也就是重定位。

4 链接

由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。

例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。

链接程序的主要工作就是将有关的目标文件彼此相连接,也就是将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。


资料一:

  • 汇编器所产生的目标文件至少包括三个区,即文本区(text),数据区(data)和bss区。文本区一般包括程序的代码和常量,数据区通常存放全局变量等内容,bss区用于存放未初始化的变量或作为公共变量存储空间。在一个目标文件中,其text区从地址0开始,随后是data区,再后面是bss区。而要运行程序,必须装载到内存中,所以这些区的地址需要在内存中重新安排,也就是重定位。

资料二:

  • 编译器编译后产生的目标文件是可重定位的程序模块,并不能直接运行,链接就是把目标文件和其他分别进行编译生成的程序模块(如果有的话)及系统提供的标准库函数连接在一起,生成可运行的可执行文件的过程。
    重定位是链接器在完成符号解析后(知道了各个输入模块的代码段和数据段的大小)的一个步骤,其作用顾名思义就是重新定位,确定比如指令,全局变量等在运行时的存储器地址。

资料三:

  • 比如说两个编译后的可重定位目标文件obj1.o和obj2.o
    在obj1.o里面定义了一个全局变量glob(在obj1里面记录了glob相对于该文件数据段的相对地址), 而obj2.0里面又引用了这个全局变量glob。
    链接的重定位就是要确定在链接后的可执行程序中glob的地址,而不是相对于obj1的地址,从而使obj2也能通过地址调用glob。

    当然重定位并不只是全局变量,还包括外部函数,指令等运行时地址的确定

资料四:

  • 当你在程序中写上一个全局变量或者是一个函数时,这个定位过程会经历几个 阶段:
    1. 在这个目标文件中的相对定位,一个目标文件中会此文件中的所有函数,变量进行符号描述,比如一个变量A,它所占的相对地址是多少?是全局的?或者是静态的,或者是外部的??
    2. 在连接多个目标成一个可执行文件时,会再次对这个变量进行重定位,也就是在这个可执行文件中进行对此变量进行描述,同目标文件中的描述差不多,只不过此变量不再有外部,内部之分,都成了本地变量,并且会将所有全局变量存放在一定的逻辑地址中,这是通过连接脚本文件与各个目标文件中的相对地址共同决定的
    3. 最终的操作系统加载这个可执行文件时,会对这些变量与函数地址再次进行重定位,其方式就是首先分析这个可执行文件中的不同段,读出相应的描述表,然后通过逻辑地址与物理地址进行映射出,最终就将可执行的二进制码加进了真实的物理内存了,关于分析可执行文件格式与物理地址的转换,不同的CPU与操作系统的实现方式会有不同之处

编译器把代码文件编译处理为一个可执行的二进制文件,在window上后缀为exe的可执行文件,linux上生成的可执行文件没有后缀来标示,比如,从一个c源代码文件变成一个可执行文件,这期间编译器做了很多事情这些事情依次是:预处理(宏展开等),编译(将c代码翻译成为汇编指令),汇编(将汇编代码翻译成机器指令,也叫可重定位目标文件),链接(链接由汇编产生的目标文件)。
经过汇编后的目标文件可以被链接成为二进制可执行文件。主题来了,链接做了什么?请看上面的资料三,把多个文件链接成为一个文件,之前的各个文件中的 符号,变量在内存中的地址是相对的,链接过程中会把多个文件的相同类型数据段代码段放在一起,所以需要将里面的符号变量重新安置在一个确定的内存地址中,这就是重定位,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值