编译和链接
引论 当我们敲的一行行源代码形成的.c.cpp文件的同时产生.exe的可执行文件时,难免会有些疑惑,这咋形成的其中的原理时啥。接下来就我的认知来对此过程进行展开论述。
前论
平常写代码就打开一个编译器就开始了一天的辛劳工作,我们比较少去需要关注编译和链接过程。这是因为我们通常使用的开发环境都是集成开发环境—IDE—,例如:Visual Studio, Dec等等。在此开发环境中编译和链接的过程都是一步完成。这些底层原理是至关重要的,就像一座楼房的地基,了解这些我们才能走得更远更踏实。
内容
一个源文件(源代码)转化成可执行程序期间需要翻译环境和运行环境
-
翻译环境 预编译 编译 汇编 链接 -
运行环境—程序执行的过程
翻译环境
翻译环境中源代码可以被翻译成可执行的机器指令,在此过程中需要俩个大体过程也就是编译(广泛)和翻译。而编译又可以细化分成预编译(预处理),编译和汇编,现在我们来剖析其中各个部分。
预编译
预编译的主要过程主要是处理源代码文件中以“#”开始的预编译指令,主要的处理方式如下: 1.#define定义符号的替换:将所有“#define”删除,并且展开所有的宏定义 2.对#include预编译指令进行处理,将其包含的文件加载到此预编译指令的位置中 3.会删除所有的注释”//“和’’/**/’’ 4.但会保存所有的#pragma 编译器指令
预编译的就是文本替换和文本操作,经过预编译的过程后,就不包含任何宏定义,所有宏都将被展开,而且包含的文件也将被插入进来。
编译
编译阶段就是通过一系列词法分析、语法分析、语义分析和符号汇总把C语言或C++语言等高级语言优化转化成汇编代码文件,而符号汇总的是全局变量和函数名。
汇编
汇编过程就是通过汇编器将汇编代码变成机器可以执行的机器指令(二进制指令),而后形成目标文件(二进制形式文件— linux .o ---- windows .obj),目标文件会形成对应的符号表(在符号表中,程序源代码中的每个标识符都和它的声明或使用信息绑定在一起,比如其数据类型、作用域以及内存地址。)。目标文件的格式是elf,解析时需要用readelf(可执行文件的格式也是elf linux a.out) 汇编器的汇编过程相对于编译器而言比较简单,它没有复杂的语法,也没有语义,只是根据汇编指令和机器指令的对照表一一翻译即可。
链接
链接过程主要是完成俩件事1.合并段表;2.符号表的合并和重定位,最后形成可执行程序 链接器存在年限可比编译器长,而通过链接器和链接库(每个函数对应的库函数(—libraries)链接加载进来)的处理下把多个目标文件进行加工形成可执行程序,就可解决一个程序的源代码的文件长达数百万行的现象
运行环境—程序执行的过程
1.程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。 2.程序的执行便开始。接着便调用main函数。 3.开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。 4.终止程序。正常终止main函数;也有可能是意外终止。
|