预编译、编译、汇编、链接

程序环境和预处理

程序的翻译环境和执行环境

程序的编译也叫做程序的翻译,主要可以分为这四个步骤:预编译、编译、汇编、链接

在ANSIC的任何一种实现中,存在两个不同的环境。

  • 第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
  • 第2种是执行环境,它用于实际执行代码。
#include <iostream>
using namespace std;
int main()
{
    cout<<"hello world"<<endl;
}

一份C语言源代码,(假设名称为 main.c) ,需要通过,预编译、编译、汇编、链接生成可执行文件(即可以运行的文件)。可执行文件的文件后缀为 .exe 文件。

  • 在Windows中C语言源代码生成的可执行文件的扩展名一般是.exe
  • 在Linux中C语言源代码生成的可执行文件的扩展名一般是.out

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nU60Do68-1680685702051)(D:\typora1.4.8\图片\b1fc1c89462ac3d8da1ba7e4105dabc.png)]

预编译、编译、汇编、链接

预编译

预编译也叫做预处理。会生成 .i 文件,通过gcc -E main.c -o main.i 生成.i文件将进行如下操作:

  1. 将所有的 #define 删除,并展开宏定义。
  2. 处理所有的预编译指令,如:#if,#elif,#else,#endif。
  3. 处理#include预编译指令,将被包含的头文件插到预编译指令的位置。
  4. 添加行号信息,文件名标识,便于调试。
  5. 删除所有的注释。
  6. 保留所有的#gragma编译指令。
  7. 生成 main.i 文件(包括注释,宏替换,头文件展开,条件编译),编译生成的 main.i 文件不包含任何的宏定义,因为宏已经被展开,并且被插入到 .i 文件中。

编译(C/C++语音 ------> 汇编):

通过gcc -S main.i –o main.s 生成.s文件,需要进行如下操作:

  1. 扫描、词法分析、语法分析、语义分析、源代码分析、目标代码生成、目标代码优化。

    • 词法分析

      词法分析会分析你的代码中的所有符号,然后产生一系列不同类型的记号:标识符、特殊符号(比如运算符号)、数字、字符串等。

    • 语法分析

      运算符的优先级和含义也被定下来。在这个阶段,括号不匹配,缺少操作符等问题就会被编译器发现,然后报告语法错误。

    • 语义分析

      编译器可以分析的语义是静态语义。包括声明和类型的匹配,类型的转换等。

      //举例子:
      //  当一个浮点类型的数据被赋值给整形数据时,其中隐含了一个浮点类型到整形数据的转换,语义分析的过程需要完成这个步骤。
      //  将一个浮点值赋值给一个指针的时候,编译器会发现类型不匹配,然后报编译错误。
      

      动态语义一般是值在运行的时候出现的语义相关的问题,比如0作为除数时是一个运行时语义错误。

  2. 生成汇编代码。

  3. 符号汇总。

    • 在词法分析的时候我们得到了很多的符号。在整个编译与链接的过程中,我们将函数名和变量名作为他们对应的符号名。
  4. 生成.s文件。

汇编(汇编 ------> 二进制)

汇编是利用汇编器将汇编代码转化成机器可以执行的指令。每一个汇编指令几乎都对应了一条机器指令。

通过gcc –c main.s –o main.o 生成.o文件,(windows环境中目标文件的后缀是.obj、在linux`环境目标文件是后缀是.o)

汇编需要进行如下操作:

1、根据汇编指令和特定平台,把汇编指令翻译成二进制形式。

2、合并各个section,合并符号表。

3、生成.o文件。

汇编后得到的文件就是目标文件。

  • 目标文件就是源代码编译后但是还没有进行链接的中间文件。

  • 目标文件中有编译后的机器指令代码,数据。除此以外,目标文件中还有链接时需要的一些信息:符号表,调试信息,字符串等。

  • 一般目标文件将这些信息按照不同的属性,以段segment的形式存储形成符号表。(一般情况下,他们都表示一个一定长度的区域)。

    //符号表中有什么?
    
    //符号表中记录了每一个被汇总的符号,以及该符号的地址。如果这个符号是一个还没有被定义的函数名,那么这个地址就不是一个游戏地址,但是符号表中仍然有这个符号的数据。
    
  • 这是整个编译汇编过程中十分重要的一步。每一个文件编译完后都会有一个对应的符号表存储在目标文件中。

  • 每一个目标文件都会有一个符号表,这个表中记录了目标文件中所用到的所有符号,每一个定义的符号有一个对应的值,叫做符号值。对于函数和变量来说这个符号值就是它们的地址。

  • 符号表的作用在链接的时候体现。

链接

链接过程会进行如下操作:

1、合并各个.obj文件的section,合并符号表,进行符号解析。

2、符号地址重定位。

3、生成可执行文件。

链接依靠的是链接器—为了让我们使用库函数有源头。现代的编译器可以将一个源代码编译成一个未链接的目标文件,然后由链接器将这些目标文件链接起来形成一个可执行文件。

我们的两个文件在连接前是不能够运行出结果的。因为在main函数调用sum函数的时候无法找到准确的地址。而链接的作用就可以简单理解为帮助程序去找到外部符号的地址

怎样找到外部符号的地址呢?

链接器通过符号表的合并和符号表的重定位做到这一点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sEh0OJpr-1680685702053)(D:\typora1.4.8\图片\ea61e86933793c0a3eb5669758565ca.png)]

这样在调用外部符号的时候就可以找到准确的地址了。

链接器通过符号表的合并和符号表的重定位做到这一点。
————————————————
版权声明:本文为CSDN博主「头疼的太阳花」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cainiaochufa2021/article/details/125661575

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值