程序的静态链接(1):概述

前言

现代编译器支持以分离编译的方式单独地编译所有的源文件,然后通过链接将所有模块组装成一个完整的应用。这种方式使得我们可以将一个复杂的应用程序分解成更小、更好管理的模块,并且可以独立地对这些模块进行修改和编译。当我们改变其中一个模块时,只需要对修改的模块重新编译,然后重新进行链接,而不必重新编译其它的模块。

静态链接

程序的编译可分为预处理、编译、汇编以及链接这四个主要阶段,编译器在完成汇编阶段之后,所有的代码源文件已经都翻译成了二进制的目标文件,但是目标文件相互之间仍然是独立的,很多依赖信息还没有解决,包括:

  • 对于每个目标文件,它可能会依赖其它目标文件或者库中的符号信息;
  • 对于每个目标文件,其在内存中的运行地址信息此时也是不确定的,因此还无法直接加载到程序中运行。

这些问题都将由静态链接解决。静态链接的核心作用就是将编译生成的多个目标文件及其依赖的库进行链接,以生成最终的可执行文件。静态链接的基本示意如下:
在这里插入图片描述

静态链接过程

在Linux平台下,使用的静态链接器通常为ld工具,为了生成可执行文件,链接器必须完成三个主要任务,概述如下:

  • 空间与地址分配:扫描所有输入的目标文件,获取所有文件中节的信息,包括属性、长度和位置等,并且收集所有目标文件中的符号定义和符号引用信息。计算出输出文件中各个段合并后的长度与位置,并建立与目标平台程序地址空间的映射关系;
  • 符号解析:目标文件中定义和引用的符号,每个符号都对应于一个函数、全局变量或者静态变量。符号解析的目的就是将每个符号引用和一个符号定义关联起来;
  • 重定位:目标文件包含从地址0开始的代码和数据节。链接通过把每个符号定义与一个内存地址关联起来,从而重定位这些节,然后修改所有对这些符号的引用,使得它们指向这个内存位置。

完成这三个任务之后,链接器会为最终的可执行文件指定一个程序入口地址,在链接C运行库的情况下,这个入口函数通常为_start。当可执行文件被加载到内存中时,系统会跳转到指定的入口地址开始执行。

相关参考

  • 《程序员的自我修养——编译、装载与库》
  • 《深入理解计算机系统》
posted @ 2020-07-26 19:59  Aspiresky  阅读(35)  评论(0编辑  收藏  举报