自举完成之后,动态链接器将可执行文件和链接器本身的符号表都合并在一个符号表里,我们可以叫它 全局符号表,然后链接器开始寻找可执行文件所依赖的共享对象。需要的信息在 .dynamic
段的 DT_NEEDED
类型里。
由此,链接器获得了该可执行文件所依赖的共享对象,并将这些名字放在一个装载的集合里,然后广度优先搜索,不断地将共享对象所需的共享对象放在集合中知道集合为空,同时每当一个新的共享对象被装载进来的时候,全局符号表里面将包含进程中所有的动态链接所需要的符号
如果两个不同的模块定义了同一个符号,在动态链接的时候,他们的所有符号都会被并进来,但是后面进来的同名符号会被忽略,称为 全局符号介入
前面对于 地址引用方式(动态链接情况) 的说明,对于第一类的内部调用或者跳转的处理来说,我们简单的认为是相对地址的调用或者是跳转,但是因为全局符号介入的原因,可能调用模块内的函数会被其他模块内的同名函数覆盖,那么按理说那个相对地址部分还得重定位一次,这个就不是 PIC 了,所以对于没有加 static
的模块内定义的函数的调用,编译器只能够当作模块外部符号处理,重定位到 .got.plt
部分
如果要提高模块内部函数调用的效率,要使用 static
函数。这种情况下编译器就能确定这个函数不会被其他函数覆盖,那么就能够使用模块私有内部函数调用的方法,用函数偏移直接调用,提高了函数的调用速度