本篇重点:
1.程序的翻译环境和执行环境
2.详解翻译环境中的 编译+链接
----------------------------------------------------------------------------------------------------------------------
程序的翻译环境和执行环境
在ANSI的任何一种实现中,存在两个不同的环境。
1. 翻译环境,在这个环境中源代码被转换为可执行的机器指令。
2. 执行环境,它用于实际执行代码。
翻译环境
^ 组成一个程序的每个源文件通过编译过程分别转换成目标文件(object code)
^ 每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序(.exe)。
^ 链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。
编译+链接
我们把翻译环境分为两个部分,分别是编译和链接。而编译部分又可分为三个部分,分别是预编译、编译和汇编。
接下来我们就分别来看看这几个阶段。(Linux操作系统下演示)
预处理 (gcc test.c -E > test.i)
看这段代码:
经过预处理后变成了这样:
本来只有几行的代码变成了几百行,是哪里变了呢?
1. #include包含的函数stdio.h显示出来了。
2. 注释被删除了。
3. #include符号替换了。
这些就是预编译阶段所完成的内容。
编译 (gcc test.i -S)
经过编译之后,代码已经成这样了:
已经把C语言代码转换为汇编代码。
在转换的过程中还要经历下面这几个内容:
1.语法分析:
例
若是源代码写成这样 #define MAX = 100,那么编译时会报错,报错如下
2.词法分析:判断源程序中单词符号的合法性。
3.语义分析:检测例如类似于for循环有没有使用错误。
4.符号汇总:(本例)g_val Add main 。 (后面来介绍符号汇总有什么用)
汇编 (gcc test.s -c)
把汇编代码转换成机器指令。
转换过程中的内容:
形成符号表(readelf test.o -s):给每个汇总的符号一个地址。
链接
我们把源文件中的Add函数改成extern int Add(int x, int y),然后再创建一个新的源文件sum.c,内容如下图,汇编后,Add会有一个地址。
我们假设 sum.c中 Add地址是 0x100
test.c中 Add 0x000 (无意义地址)
g_val 0x200
main 0x300
printf 0x400
每个目标文件由链接器捆绑在一起,形成一个单一而完整的可执行程序。所以Add也将合并在一起,用有效的地址。即
所以链接过程中主要的操作有以下两点:
1.符号表的合并和重定位。
2.合并段表。
以上就是翻译环境的主要内容,为了方便记忆,给大家一幅图来帮助记忆。
执行环境
程序执行的过程:
1. 程序必须载入内存中。在有操作系统的环境中:一般这个有操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2. 程序的执行开始。接着便调用main函数。
3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储在静态内存中的变量在程序的整个执行过程一直保留他们的值。
4. 终止程序。正常终止main函数;也有可能是意外终止。
----------------------------------------------------------------------------------------------------------------------
以上就是程序环境:翻译环境与执行环境的全部内容了,你学会了吗?