C++编译过程详解

编译步骤:

一、编译:预处理,编译,汇编

二、链接


预处理:生成“.ii文件”,对所有的#进行预处理,对include进行链接,对宏macro进行替换(预处理器cpp(c preprocessor)) g++生成的文件后缀名为.ii,gcc生成的文件后缀名为.i。

头文件中不能放函数的以及变量定义,因为当同时编译多个编译单元并连接为一个可执行文件的时候,如果这些编译单元中有重复引用同一个头文件,, 如果头文件中定义的函数又没有定义成局部函数, 那么在连接时, 就会发现多个相同的函数, 就会报错。如果在 header file 中定义全局变量, 并且将此全局变量赋初值, 那么在多个引用此 header file 的 implementation file 中同样存在相同变量名的拷贝, 关键是此变量被赋了初值, 所以编译器就会将此变量放入 DATA 段, 最终在连接阶段, 会在 DATA 段 中存在多个相同的变量, 它无法将这些变量统一成一个变量,。假定这个变量在 header file 中没有赋初值, 编译器就会将之放入 BSS 段, 连接器会对 BSS 段 的多个同名变量仅分配一个存储空间。因此,在预处理过程中替换进来的头文件中只有声明,没有定义。


编译:将“.i文件”转换为汇编语言文件“.s文件”(编译器egcs)。


汇编:将汇编语言文件“.s文件”转换为机器码文件“.o文件”(编译器as)


链接:1.地址与空间分配(Address and Storage Allocation) 2.符号解析(Symbol Resolution) 3.重定位(Relocation)

地址与空间分配:扫描所有的输入目标文件,获得它们的各个节的长度、属性、位置,并将输入目标文件中的符号表中所有的符号定义和符号引用收集起来,统一放到一个全局的符号表。这一步,链接器能够获得所有输入目标文件的节的长度,并将它们合并,计算出输出文件中各个节合并后的长度与位置,并建立映射关系。在elf文件中字节对齐是以4字节对齐的,在可执行程序中是以页的方式对齐的(一个页的大小为4k),因此如果我们在链接时将各个.o文件各个段单独的加载到可执行文件中,将会非常浪费空间(因为每个文件的大小并非4k=4096的整数倍),一般采取的方法便是合并相同性质的节,比如:将所有输入文件的 .text合并到输出文件的 text段。

符号解析:在链接中,将函数和变量统称为符号,函数名和变量名统称为符号名,每个目标文件要提供两个符号表给链接器使用。符号解析时,链接器根据目标文件提供的未解决符号表,去所有的编译单元的导出符号表中去查找与这个未解决符号相匹配的符号名,如果找到,就把这个符号的地址填到未解决符号的地址处,如果没有找到,就会报链接错误。

未解决符号表:本编译单元里有引用但是不在本单元定义的符号及其对应的地址。

导出符号表:本单元定义,并且可提供给其他单元使用的符号及其在本单元对应地址。 可以使用 nm 命令查出二进制文件包含的符号表。

重定位:多个编译单元的符号地址可能是相同的,比如都从 (0x0000) 开始,那么最终多个目标文件链接时就会导致地址重复。 所以链接器在链接时就会对每个目标文件的地址进行调整,这个调整的过程就是重定位。

链接具体过程:链接器首先决定各个目标文件(要编译链接的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值