如何在主程序中解析共享库的外部符号?

How are external symbols of a shared library resolved in the main program?

我已经阅读了很多关于共享库加载时链接语义的文章,但我难以理解的一件事是主程序如何引用共享库中定义的函数?例如,假设我有这个代码

myShared.sh

int get(){
   return 0;
}

main.c

  extern int get();
  int main(){
    int a = get();
  }

我明白,由于共享库不能对它们的放置位置做出任何断言,它们必须使用 GOT 和 PLT 来引用它们自己的函数和全局数据。但是使用上述库的实际程序如何知道函数将加载到哪里以便它可以引用它们?显然,链接器不知道,因为此类库的链接直到加载时才会发生。因此,我能想到的只有两种方法可以引用此类外部函数。

  1. 链接器只是在调用 get(在上面的示例中)的地方放置一些占位符,然后添加加载程序所需的一些元数据,然后来替换该位置holder 和函数的实际地址(比如共享库如何在 PIC 之前使用加载时重定位)但这会导致显着的开销,并且是(我认为)首先引入 PIC 的动机

  2. 主程序也有自己的 GOT 和 PLT,加载器还必须填充主程序的 GOT 和共享库的 GOT(在加载期间一次全部填充,以防万一全局变量,或者以懒惰的方式使用 PLT 函数)但这听起来像是一个主要的重复工作。

那么,如果有的话,这两个中哪一个是用于解析共享库外部符号的方法?

主程序中的符号解析与共享库中的符号解析没有太大区别,都是通过主程序的 GOT 和 PLT 表来实现的。你是对的,这会在静态(ld)和动态(ld.so)链接器之间产生一定数量的重复,并减慢程序启动速度,但另一方面允许在运行时增加灵活性(例如通过插入符号LD_PRELOAD)。