程序环境详解(翻译环境)

一,分类

程序环境包括翻译环境和执行环境。
在这里插入图片描述
翻译环境: 计算机可以识别二进制指令,而我们写的代码时文本信息,计算机无法识别,需要翻译环境进行翻译后,计算机才能识别运行。
执行环境: 执行二进制指令。

二,翻译环境

1. 翻译环境过程总览

在这里插入图片描述
链接库:
我们使用的库函数在静态库中存放(文件后缀为 .LIB 的文件),库函数已经被编译好了放到了静态库中,所以可以直接链接使用,比如,使用了scanf()的函数,VS就会自动将包含 scanf() 的静态库链接到程序中去。

VS中的翻译环境:
Microsoft Visual Studio(简称 VS)是集成开发工具,集成了编译器,链接器和调试器。
VS2019 中的编译器是 c1.exe,链接器是 link.exe。

2. 翻译环境具体过程

在这里插入图片描述
翻译环境可以分为两个大的过程,一个是编译,一个是链接,其中编译过程又分为预编译,编译,汇编三个过程。

2.1 编译

编译中三个过程对文件的操作:
在这里插入图片描述

2.1.1 预编译:

对我们所写的代码进行变动,有注释的删除和处理预处理指令。
预处理指令有 #include ,#define ,条件编译等。

#include:将引用的头文件中的内容全部放到当前原文件的#include的位置。
#define:将代码中用到 #define 定义的符号的内容进行替换。

关于预处理 #include 和链接期间链接静态库的区别:
在这里插入图片描述
#include 包含库函数的头文件,在预处理阶段只是将头文件中的函数声明,头文件等信息放到当前位置,而链接期间是将有关的静态库(里面有库函数的定义)链接到程序中。
#include 预处理:只是把东西给你放过来,谁知道里面是什么,就算有函数,那也是函数声明(告诉一声你能用这个东西,但这个实际上存不存在并不关心),而不是定义(实体)。
链接库:链接到函数的定义(实体)。

预编译阶段只是进行了文本操作。

2.1.2 编译:

将文本代码通过语法分析,词法分析,语义分析,符号汇总,编译成了汇编指令,并放到了 .s 文件中。

编译阶段:文本信息——>汇编指令

2.1.3汇编:

汇编阶段,是将汇编指令转为二进制指令,并放到 .obj 文件中,即生成了目标文件(VS中目标文件后缀是 .obj ,Linux 中目标文件后缀是 .o)。
该阶段形成了符号表。

汇编阶段:汇编指令——>二进制指令

2.2 链接

对多个 .o 文件,链接库进行链接,生成一个可执行程序 .exe 后缀的二进制文件。
链接阶段所完成的有段表的合总,符号表的合并和重定位。

2.3 段表和符号表

2.3.1 通过 readelf 查看目标文件内容:

在这里插入图片描述

在汇编阶段,我们形成了目标文件(.o 文件).

在 Linux 下gcc 编译产生的目标文件,可执行程序都是按照 ELF 这种文件的格式来存储的。

目标文件是二进制文件,我们无法看懂,在 Linux 环境中 readelf 工具能够识别 elf 格式的文件。
通过 readelf 来看 .o 文件,里面有各种段(文本段,数据段,只读数据段…),ELF 格式存储,是按照不同的段来存储数据的。

.o 文件中的符号包括全局对象符号,函数符号(自定义,库函数),不存在局部变量的符号。

2.3.2 段表

在这里插入图片描述
Linux 下gcc 编译产生的目标文件,可执行程序都是按照 ELF 这种文件的格式来存储的。
所以,每个 .c 文件生成的 .o 文件中都有一个段表,数据按不同段存储,链接过程中,将各个 .o 文件链接到一起时就会把相同段的数据放到相同的区域,合并形成一个段表,这就是合并段表过程。

2.3.3 符号表

在这里插入图片描述
由上面得知,.o 文件中的符号有函数,全局变量等,那在编译阶段就是搜寻汇总出代码中全部的这样的符号。
在汇编阶段,就是将符号和符号的地址一起组成符号表。如下图:

在链接阶段,是将各个 .c 文件编译形成的 .o 文件链接到一起,那就会有多个符号表,同一个函数,可能在多个原文件中使用了,未有定义的函数要使用必须有函数的声明,而通过声明的函数符号也会被识别汇总形成符号表,但函数的定义代码只可能在一个源文件中(如果同一个函数有多个定义,那就会出现重定义现象),只有函数定义处的函数地址才是真的,可以通过此地址找到改函数,所以,合并符号表时需要进行符号表的重定位以找到可以通过地址真正找到函数的地址形成符号表。图解如下:
在这里插入图片描述

三,执行环境

1. 程序必须载入内存中。

一般由操作系统完成,独立环境中程序的载入要手动安排或者通过可执行代码置入只读内存来完成。

2. 程序的执行开始。

接着调用 main 函数。

3. 开始执行程序代码。

程序将使用一个运行时堆栈,存储函数的局部变量和返回地址。程序同时也可以使用静态内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。

4. 终止程序。

正常终止 main 函数,也可能意外终止。

END

本人才疏学浅,有什么不对的地方,欢迎大家指出,不吝赐教 !!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值