【问题标题】:Is the static loading of shared libraries linked like dynamic loading or static linking?共享库的静态加载是像动态加载还是静态链接一样链接?
【发布时间】:2014-05-31 14:51:59
【问题描述】:

根据this expert

动态加载是指在启动后将可执行文件或库映射(或较少复制)到进程的内存中。 动态链接是指在编译后解析符号 - 将它们的名称与地址或偏移量相关联。

因此,相应地:静态加载是指在可执行文件或库启动之前将其映射到内存中,静态链接是指在编译时解析符号。 p>

现在,当您对库进行静态加载静态链接时,库的二进制代码会附加到您的二进制代码中,并且(函数和变量)引用您对库的二进制代码已修补(不确定这是否是正确的术语),以便它们指向正确的位置。

这意味着在静态链接一个函数调用之前

foo()

会给你(在 x86 ASM 中),除其他外,如下指令:

 call    0x00000000

在静态链接之后,你会得到类似的东西:

 call    0x00001043

其中 0x00001043 是链接器输出的二进制代码中函数 foo 的入口点。

现在,当您进行动态加载动态链接时,您将通过函数指针调用库函数: typedef int (*fun_ptr)(void);

library = dlopen("mylib.so");
fun_ptr foo = dlsym(library, "foo");
foo();

这种机制也是 C++ 虚方法的工作方式。要调用的方法的地址在运行时通过使函数指针指向实例的方法部分(存储在所谓的 vtable 中)来解析。

我的问题是这样的:

当您对共享库(对于上下文,比如说 linux 中的 .so)进行 静态加载动态链接 时,此链接是否会修补我的二进制文件的引用,例如在静态加载和链接场景中,还是像动态加载和链接和C++虚方法那样通过函数指针工作?

【问题讨论】:

    标签: linker static-linking dynamic-linking


    【解决方案1】:

    当您对共享库进行静态加载和动态链接时

    您不会对共享库进行“静态加载”。

    即使它在您看来是最终用户,例如libc.so.6 在进程启动时是“静态加载”的,实际上并非如此。相反,内核“静态加载”主二进制文件和ld-linux.so,然后ld-linux 动态加载所有其他共享库。

    这个链接是像在静态加载和链接场景中那样修补我的二进制文件的引用,还是像在动态加载的情况下那样通过函数指针工作

    视情况而定。

    通常共享库是从与位置无关的代码 (PIC) 链接的,并以函数指针的方式工作(指针存储在 GOT -- 全局偏移表中)。

    但有时共享库是从非PIC 代码链接的,并且需要“文本重定位”,其工作方式类似于“静态链接”。

    【讨论】:

    • 谢谢,知道这个很有用!现在我终于明白了为什么在我的 linux 机器中编译共享库时必须添加 -fPIC 标志:) 一些后续问题:你知道哪些系统使用文本重定位,哪些使用全局偏移表吗?是否可以编译 linux 内核以使用文本重定位而不是 GOT?另外,为什么首选GOT?更快的加载优先于更快的运行时性能?
    • 我发现this link 很有用。这似乎意味着文本重定位不能由 SELinux 机器中的内核以外的任何东西执行(因为内存页面在 SELinux 中不能既可写又可执行)。
    【解决方案2】:

    我已经能够使用 libbfd(位于 GNU binutils 的 ld 链接器下方的库)生成运行时静态链接的示例:https://github.com/bloff/runtime-static-linking-with-libbfd

    【讨论】:

      猜你喜欢
      • 2012-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多