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

Posted

技术标签:

【中文标题】共享库的外部符号如何在主程序中解析?【英文标题】:How are external symbols of a shared library resolved in the main program? 【发布时间】:2019-02-20 11:24:12 【问题描述】:

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

myShared.sh

int get()
   return 0;

main.c

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

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

    1234563函数(就像共享库如何在 PIC 之前使用加载时重定位)但这会导致显着的开销,并且是(我认为)首先引入 PIC 的动机

    主程序也有自己的 GOT 和 PLT,加载器还必须沿着共享库的 GOT 填充主程序的 GOT(在全局变量的情况下在加载期间一次全部完成,或者以一种懒惰的方式将 PLT 用于函数)但这听起来像是重复劳动。

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

【问题讨论】:

this 有用吗? @JulianH 如果我没记错的话,在 Linux 和共享对象上,链接发生在加载时(在运行之前,而不是编译时)。请注意,该 OP 明确标记了 Linux。 (我知道 Windows 上的 DLL 在这方面有点不同。) @Scheff 我认为在 Linux 上您必须将库的名称传递给 g++,以便链接器能够解析这些符号。如果你用dlopen链接,你不能用extern来寻址get @JulianH 我刚刚发现:Static, Shared Dynamic and Loadable Linux Libraries: 为运行时链接编译 ... 这些库不会包含在可执行文件中,但会包含在可执行文件中在运行时执行期间动态链接。 ;-) 我将其理解为:在编译时它是“链接的”,为运行时链接做准备。我在吹毛求疵吗? 是的,我明白了,Linux 和 Windows 之间存在差异,抱歉。 【参考方案1】:

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

【讨论】:

以上是关于共享库的外部符号如何在主程序中解析?的主要内容,如果未能解决你的问题,请参考以下文章

共享库如何免受利用?

如何使共享库符号强大?

如何在共享库中找到 C++ isfinite() 的解析位置?

当另一个库具有相同的符号时,gdb 不显示来自共享库的符号

需要在 GDB 中加载共享库的调试符号

链接共享库时限制符号的可见性