《2022年C语言的编译系统 .pdf》由会员分享,可在线阅读,更多相关《2022年C语言的编译系统 .pdf(3页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、从源代码到可执行的目标程序,除了编译器之外往往还需要预处理器、汇编器和链接器。而想让目标代码运行还需要一些工具的支撑,如动态连接程序、无用单元收集程序等,这些工具的集合称为运行系统。就 C 语言而言, 其源代码往往分成若干个模块而存储在不同的源文件中,C 编译系统对这些源文件分别进行预处理、编译、 汇编过程以形成可重定位的目标文件;然后再使用链接器将这些可重定位的目标文件和必要的库文件链接成一个可执行的目标文件,即具有绝对地址的机器代码,如图:大多数编译系统提供一个驱动程序来调用预处理器、编译器、汇编器、链接器,以便支持用户完成从源程序到可执行程序的整个开发过程,例如典型的GCC 。预处理器主
2、要完成文件包含、宏的替换、条件编译等工作。编译器对预处理器后的C语言代码进行词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价、优化的中间代码表示或汇编代码。汇编器主要负责将表示存储单元的所有标识符都存入符号表并分配地址将每个操作码译为目标机器代表该操作的二进制位串,并把代表存储单元的每个标识符翻译成符号表中这个标识符所分配的地址。我们必须明确, 由于许多没有解决的问题(例如一个汇编文件中存在外部符号的引用,即某个源文件引用了另一源文件中定义的某个符号,如变量或者函数调用等;或者在程序中调用了某个库文件中的函数),所以由汇编器生成的除平坦二进制文件外的其他目标文件都不能立即
3、执行,所有的这些问题都需要经链接器的处理才能解决。链接是一个收集、 组织程序所需的不同代码和数据(因为他们可能在不同的目标文件中),以便程序能被装入内存并被执行的过程。这样,链接器的主要工作就是将有关的目标文件彼此相连接, 将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。这样,我们就知道目标文件由汇编器或链接器创建,实际上主要分为可重定位的目标文件和可执行的目标文件有两种(还有共享的目标文件):可重定位的目标文件包含二进制代码和数据,可以和其他可重定位目标文件链接成一个可执行的目标文件或更大的可重定位的目标文件预处
4、理器 cpp源程序修改后的源程序*.i可重定位的目标程序 *.o 库可重定位的目标文件编译器 ccl汇编器 as汇编程序*.s连接器 ld 可执行的目标程序名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 3 页 - - - - - - - - - 可执行的目标文件包含二进制代码和数据,可以直接被复制到内存执行,类似于shell脚本等需要抽象机制辅助的程序是不被接受的。当然,目标文件的格式随操作系统的不同而不同,主要有以下几种:COM ,用于 DOS 操作系统,平坦的二进制
5、形式a.out , 用于早期UNIX操作系统, 现代 UNIX下的可执行文件仍然被缺省地命名为a.out COFF (Common Object File Format),用于System V UNIX 操作系统PE (Portable Executable),用于Win NT 操作系统,从COFF 中衍生ELF(Executable and Linkable Format ),用于现代UNIX 操作系统中,作为应用程序二进制接口Application Binary Interface而开发,为工作在相同体系结构上不同操作系统提供可移植的二进制文件下面我们对链接器进行着重说明。我们已经知道,
6、链接是一个收集、组织程序所需的不同代码和数据(因为他们可能在不同的目标文件中),以便程序能被装入内存并被执行的过程。实际上, 如果这些目标文件以有用的方式组织在一起,那么他们之间必然会出现一些外部引用, 这种引用可以是定义在一个文件而使用在另一个文件的数据单元,也可以是入口点出现在一个文件而调用点出现在另一个文件中的函数。从以上的两点我们可以看出,链接器其实主要完成了两个任务,即符号解析和重定位。符号解析是为了识别并关联所有的符号,而重定位是为了将所有从零地址开始的相对地址重定位为绝对地址。为了建立对符号解析和重定位的深刻理解,我们必须首先来看一个背景知识:对于编译器/汇编器而言,当遇到当前源
7、文件没有定义的符号时,它们就假定该符号在其他某个模块中定义, 并为该符号产生一条符号表条目,把它留给链接器处理;如果链接器在所有的输入模块中都找不到被引用符号的定义,那么就会出错。这样我们就能给出符号解析和重定位的准确定义了,所谓符号解析 (symbol resolution ) ,即识别各个目标模块中定义和引用的符号,为每一个符号引用确定它所关联的一个同名符号的定义。 更具体地说, 就是链接器需要将每个符号引用正确地与某可重定位模块的符号表中的一个符号定义相关联,从而确定各个符号引用的位置。在链接器的上下文中,一个重定位模块 M 可能定义和引用的符号通常有三类,即:全局符号, 那些在模块M中
8、定义, 可以被其它模块引用的符号,包括模块M中定义的非static属性的函数和全局变量局部符号, 指那些在模块M中定义, 且只能在本模块中引用的符号,包括模块 M中定义的有 static属性的函数和全局变量外部符号,指那些由模块M引用并由其它模块定义符号而所谓的重定位是因为汇编器产生的代码段和数据段都是从零地址开始的,链接器为了将这些从零地址开始的代码段和数据段组织成一个文件,就需要重定位这两个节,其具体方法是将每一个符号定义关联到一个内存位置,然后修改所有对这些符号的引用,使他们指向相关联的内存位置。链接可以在三种情况下进行,即编译时、 装入时和运行时进行,其中编译时链接在将源代码翻译成机器
9、代码的过程中完成,装入时链接在程序装入内存并执行时完成,运行时链接在程序运行时完成。这样也就引出了静态链接器和动态链接器的概念,所谓静态链接器即将多个可重定位的目标文件组成一个可执行的目标文件/可重定位的目标文件的工具;而动态链接器用于在内存中的可执行程序执行时与共享目标文件/动态链接库进行动态链接。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 3 页 - - - - - - - - - 11.1.6 静态库将相关的可重定位目标模块打包成一个文件,作为连接器的输入连接器
10、仅复制库中被应用程序引用的模块gcc c swap.c 编译arrcsmylib.aswap.o 建库gcc static o swap1 main.c /usr/lib/libc.amylib.a 生成可执行文件这里描述的装入过程从概念上来说是正确的若需要了解装入过程真正是怎样工作的,必须在理解了进程、虚拟内存和内存分页等概念以后而目标代码运行时,还需要一些工具的支撑,如动态连接程序、无用单元收集程序等,这些工具的集合称为运行系统。根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种:(1)静态链接在这种链接方式下,函数的代码将从其所在的静态链接库中被拷贝到最终的可执行程序中。这样
11、该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。(2)动态链接在此种方式下, 函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。对于可执行文件中的函数调用,可分别采用动态链接或静态链接的方法。使用动态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使
12、用时能节约一些内存,因为在内存中只需要保存一份此共享对象的代码。但并不是使用动态链接就一定比使用静态链接要优越。在某些情况下动态链接可能带来一些性能上损害。11.1.8 动态连接静态库周期性地被维护和更新内存可能有多份printf 和 scanf 的代码共享库在运行时可以装到任意的内存位置,被内存中的进程共享共享库以两种不同的方式被共享共享库的代码和数据被所有引用该库的可执行目标文件所共享共享库的 .text 节在内存中的一个副本可以被正在运行的不同进程共享可执行目标文件及装入名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 3 页 - - - - - - - - -