note:这里还要补充的可能很多,包含可重定位目标文件的内容等。
符号和符号表
在ld等链接器的上下文中,有三种不同的符号。每一个可重定位目标模块m都有一个符号表,它包含m所定义的和引用的符号的信息。
由m所定义的并且能够被其他模块所引用的全局符号。就是非静态的c函数和被定义为不带c static属性的全局变量。
在其他模块定义并被模块m引用的全局符号。对应于定义在其他模块中的c函数和变量,external。
只在模块m定义和引用的本地符号。有的就是对应于带static属性的c函数和全局变量。这些符号在模块m中随处可见,但是不能被其他模块引用。目标文件中对应于模块m的节和相应的源文件中的名字都能获得本地符号。
.symtab中的符号表不包含对应于本地非静态程序变量的任何符号。这些符号在运行时在栈中被管理,链接器对此类符号不感冒。
对于static属性的本地过程变量是不在栈中管理的,相反,编译器在.data和.bss中为每个定义分配空间,并在符号表中创建一个有唯一名字的本地链接器符号。
带有static属性的全局变量和函数是模块私有的。相反,则是可以被其他模块访问的。
符号表是由汇编器构造的,使用编译器输出到汇编语言.s文件中的符号。
关于这个表的每个条目,有name和value。value是表示符号的地址,对于可重定位的模块来说,value是距定义目标的节的起始位置的偏移。还有size是目标的大小。每个符号都和目标文件的某个节相关联。.ndx为1表示.text节,为3表示.data节。
链接器解析符号引用的方法是将每个引用和它输入的可重定位的目标文件的符号表中的一个确定的符号定义联系起来。
符号解析
首先,我对符号表已经有了一定的概念,就是那张可以重定义的符号表(含有对符号的定义)。这个表格第一次接触到,还是会比较新颖的,现在就成了学习符号解析的利器了。
为什么需要解析符号引用?因为在代码的其它部分会使用到这些符号。
对于不同类型的符号,符号解析分别有什么特点?对那些引用和定义在同一个模块中的符号,符号解析是非常简单的。
当编译器遇到一个不是在本地定义的全局符号的时候呢?它当然会假设该符号是在其他模块中定义的,然后就去查找(这个过程就生成一个链接器符号表条目,并把它交给链接器处理)如果链接器在它的任何模块都找不到这个被引用的符号,它就输出一条错误信息。。
(note哈哈,下面将要给出一个例子,这个很简单,也经常遇到。但是在c.learncodethehardway里面介绍了很多静态库和动态库编译链接的东西,从这里过去便可以做进一步的理解了。)
在cpp和Java 中由于有重载的存在,所以链接器貌似要使用到一种叫做mangling的技术(可以多查找一点资料看看,应该非常有意思)
那么链接器是如何工作的呢?
强弱符号的概念?没有初始化的全局变量则是弱符号。
链接器的逻辑并不复杂。
但是在特殊的情况下,链接器是如何解析多重定义的全局符号的?
规则:
1.部允许有多个强符号。
2.如果有一个强符号和多个弱符号,那么选择强符号。(这里输出一个例子,非常有意思哦)
3.如果有多个弱符号,那么从这些弱符号中任意选择一个。(这里甚至还谈到了不同类型的重复符号,可能会产生很大的分歧)
与静态库(以前写好的模块)链接
note:这里有很多例子和技巧可言(恰好还有这方面的经验)。
除了静态库,还有哪些可以使用到的alternative?
为什么系统要支持库的概念呢?因为他定义了一组广泛的标准IO,字符串操作盒证书数学函数等。他们在libc.a中。如果不使用静态库,可以由多种方法来做这个工作(比如让编译器辨认出对标准函数的调用,并直接生成相应的代码(这个对编译器的复杂性将是一个可怕的灾难。。。。当然还有别的缺点啦。根本就是不合适的))
另外一个呢?就是把所有的标准C函数都放在一个单独的可重定位目标模块中,然后应用程序员就可以把这个模块连接到他们的可执行文件中啦。。。(和上一种方法相比,至少能够把编译器的实现和标准函数的实现分离开来)缺点呢?每个可执行文件都包含着一份标准函数集合的完全拷贝,这对磁盘空间是很大的浪费。更糟糕的是,每个运行的程序都将它自己的这些函数的拷贝放在存储器中,这又是一个极大地浪费。
当然我们也可以为每个标准函数创建一个独立的可重定位文件,把他们放在一个大家都知道的目录中来解决其中的一些问题。(这需要应用程序员现实的简介合适的目标模块到他们的可执行文件)
静态库到底是什么?有什么好处?
在unix系统中,静态库以一种称为archive的特殊文件格式存放在磁盘中。存档文件是一组连接起来的可重定位目标文件的集合(有一个头部用来描述每个成员目标文件的大小和位置)。存档文件名由后缀.a标志。
现在有一个很重要的问题,那就是链接器如何使用静态库来解析引用?
…
重定位
是符号解析的下一步,将合并输入模块,并为每个符号分配运行时地址。
可执行目标文件
我们的c程序,开始时是一组ascii 文本文件,已经被转化为一个二进制文件,而且这个二进制文件包含加载程序到存储器并运行它所需的所有信息。
加载可执行目标文件
一个loader的操作系统代码,来运行可执行程序。
动态链接共享库
从应用程序中加载和链接共享库
p.s.,这些我都讲的过于简略,有空再详细补充图片解析和内容
参考文献
csapp:Computer Systems A Programmer’s perspective
http://c.learncodethehardway.org/book/ex28.html
http://c.learncodethehardway.org/book/ex29.html