【阅读笔记】程序员的自我修养2

本文详细介绍了Linux中使用GCC编译程序的四个步骤:预处理、编译、汇编和链接。预处理阶段处理宏定义、头文件等;编译阶段生成汇编代码;汇编阶段将汇编代码转换为机器代码;链接阶段将所有模块组合成可执行文件,修正函数和变量的地址。这一过程涉及源代码、头文件、库和目标文件的交互,最终形成可执行程序。
摘要由CSDN通过智能技术生成

第二章 编译和链接

Linux中,使用gcc编译Hello World程序的时候,只需使用简单的命令:gcc hello.c。事实上,这个过程可以分解为四个步骤:
预处理(Prepressing)、编译(Compilation)、汇编(Assembly)、和链接(Linking)。

  • 预编译:主要处理源代码中以“#”开始的预编译指令,如“#include”、“#define”“#ifdef”等。这个过程包括了删除#define,展开宏定义,处理其他预编译指令等,删除所有的注释"//,/**/",添加行号和文件名标识(便于调试时输出相关信息或编译错误警告产生行号),保留所有的#pragma编译器指令等

    经过预编译后的.i文件不包含任何宏定义,因为所有的宏已经被展开,并且包含的文件也已经被插入到.i文件中。


  • 编译:将预处理完的文件进行一系列的词法分析、语法分析、语义分析及优化,然后生产出相应的汇编代码文件,这个过程往往是程序构建(build)的核心部分。现版本gcc把预编译和编译两个步骤合并成一个步骤。


  • 汇编:将汇编代码转变成机器可以执行的指令。汇编器输出的是目标文件.o(不是可执行文件)

    gcc -c hello.c -o hello.o
    

  • 链接:。。。

    静态链接:

    当一个系统特别复杂的时候,我们不得不将它分割成小的系统以达到各个突破的目的。我们将每个源代码模块独立地编译,然后按照须要将它们“组装”起来,这个组装的过程就是链接(Linking)。链接器的功能本质上就是调整地址的作用,将一些指令对其他符号地址的引用加以修正。最基本的静态链接过程如下:

    Source Code < a.c >
    ProPressing
    Compilation
    Assmebly
    Object File < a.o >
    Linking <ld>
    Exacutable < a.out >
    Header Files < .h >
    Library < libc.a , crt1.o,...>
    Source Code < b.c >
    ProPressing
    Compilation
    Assmebly
    Object File < b.o >

    每个模块的源代码文件(.c)经过编译器编译成目标文件(.o/.obj),目标文件和库一起链接形成最终的可执行文件。

    比如我们在程序模块main().c中使用另外一个模块func.c中的函数foo().我们在main().c模块的每一处调用foo的时候都必须确切知道foo这个函数的地址,所以它暂时将这些调用foo的指令的目标地址搁置,等待最后链接的时候由连接器去将这些指令的目标地址修正。

    在连接的过程中,对其他定义在目标文件中的函数调用的指令须重新调整,对使用其他定义在其他目标文件的变量也同样如此。假设我们有个全局变量var,他在目标文件A中,我们在目标文件B中要访问这个全局变量。。。由于在编译目标文件B的时候,编译器并不知道变量var的目标地址,所以编译器在无法确定地址的情况下会将指令的目标地址置为0,等待链接器在将目标文件A和B链接起来的时候再将其修正。这个地址修正的过程也被叫做重定位(Relocation).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值